Beispiel #1
0
class Program(linkable_model.Linkable):
  """The Program model, representing a Program ran by a Sponsor."""

  _messages_model = ProgramMessages

  #: string used as a prefix of various key names for other models
  #TODO(daniel): eliminate this
  prefix = 'program'

  #: Identifier of the program which is be the last part of its unique key name
  program_id = db.StringProperty(required=True,
      verbose_name=translation.ugettext('Program ID'))
  program_id.help_text = translation.ugettext(
      'Used as part of various URL links throughout the site.')

  #: Reference to the sponsor of the program. Its key_name is used as the first
  #: part of program's unique key name
  sponsor = db.ReferenceProperty(required=True,
      reference_class=sponsor_model.Sponsor, collection_name='programs',
      verbose_name=translation.ugettext('Sponsor'))

  #: Required field storing name of the group.
  name = db.StringProperty(required=True,
      verbose_name=translation.ugettext('Name'))
  name.group = GENERAL_INFO_GROUP
  name.help_text = translation.ugettext(
      'Complete, formal name of the program.')

  #: Required field storing short name of the group.
  #: It can be used for displaying group as sidebar menu item.
  short_name = db.StringProperty(required=True,
      verbose_name=translation.ugettext('Short name'))
  short_name.group = GENERAL_INFO_GROUP
  short_name.help_text = translation.ugettext(
      'Short name used for sidebar menu')

  #: Required field storing description of the group.
  description = db.TextProperty(required=True,
      verbose_name=translation.ugettext('Description'))
  description.group = GENERAL_INFO_GROUP
  description.help_text = translation.ugettext(
      '<small><i>for example:</i></small><br>'
      '<tt><b>GSoC 2009</b> is the <i>Google Summer of Code</i>,'
      ' but in <u>2009</u>!</tt><br><br>'
      '<small><i>(rich text formatting is supported)</i></small>')

  #: Number of accepted organizations
  nr_accepted_orgs = db.IntegerProperty(
      required=False, verbose_name=translation.ugettext('#accepted orgs'))
  nr_accepted_orgs.group = GENERAL_INFO_GROUP
  nr_accepted_orgs.help_text = translation.ugettext(
      'The number of accepted organizations.')

  #: Property that contains the minimum age of a student allowed to
  #: participate
  student_min_age = db.IntegerProperty(
      required=False, verbose_name=translation.ugettext('Student minimum age'))
  student_min_age.group = AGE_REQUIREMENTS_GROUP
  student_min_age.help_text = translation.ugettext(
      'Minimum age of students.')

  #: Property that contains the maximum age of a student allowed to
  #: participate
  student_max_age = db.IntegerProperty(default=200,
      required=False, verbose_name=translation.ugettext('Student maximum age'))
  student_max_age.group = AGE_REQUIREMENTS_GROUP
  student_max_age.help_text = translation.ugettext(
      'Maximum whole-year age of students.')

  #: Property that contains the date as of which above student
  #: minimum/maximum age requirement holds.
  student_min_age_as_of = db.DateProperty(
      required=False, verbose_name=translation.ugettext('Age as of'))
  student_min_age_as_of.group = AGE_REQUIREMENTS_GROUP
  student_min_age_as_of.help_text = translation.ugettext(
      'Date on which students must satisfy age requirements.')

  #: Required 1:1 relationship indicating the Program the Timeline
  #: belongs to.
  timeline = db.ReferenceProperty(
      reference_class=timeline_model.Timeline,
      required=True, collection_name="program",
      verbose_name=translation.ugettext('Timeline'))

  #: Document reference property used for the Org Admin Agreement
  org_admin_agreement = db.ReferenceProperty(
      reference_class=document_model.Document,
      verbose_name=translation.ugettext('Organization Admin Agreement'),
      collection_name='org_admin_agreement')
  org_admin_agreement.group = PROGRAM_DOCUMENTS_GROUP
  org_admin_agreement.help_text = translation.ugettext(
      'Document containing optional Mentor Agreement for participating as a '
      'Organization admin.')

  #: Document reference property used for the Mentor Agreement
  mentor_agreement = db.ReferenceProperty(
      reference_class=document_model.Document,
      verbose_name=translation.ugettext('Mentor Agreement'),
      collection_name='mentor_agreement')
  mentor_agreement.group = PROGRAM_DOCUMENTS_GROUP
  mentor_agreement.help_text = translation.ugettext(
      'Document containing optional Mentor Agreement for participating as a '
      'Mentor.')

  #: Document reference property used for the Student Agreement
  student_agreement = db.ReferenceProperty(
      reference_class=document_model.Document,
      verbose_name=translation.ugettext('Student Agreement'),
      collection_name='student_agreement')
  student_agreement.group = PROGRAM_DOCUMENTS_GROUP
  student_agreement.help_text = translation.ugettext(
      'Document containing optional Student Agreement for participating as a '
      'Student.')

  #: Status of the program
  status = db.StringProperty(required=True, default=STATUS_INVISIBLE,
      verbose_name=translation.ugettext('Program Status'),
      choices=[STATUS_INVISIBLE, STATUS_VISIBLE, STATUS_INVALID])
  status.group = GENERAL_INFO_GROUP
  status.help_text = translation.ugettext(
      # TODO(nathaniel): Someone got their HTML in this Python.
      '<tt>%s: Program Stealth-Mode Visible to Hosts and Devs only.<br/>'
      '%s: Visible to everyone.<br/>'
      '%s: Not visible or editable by anyone.</tt>' % (
          STATUS_INVISIBLE, STATUS_VISIBLE, STATUS_INVALID))

  #: The document entity which contains the "About" page for the program
  about_page = db.ReferenceProperty(
      reference_class=document_model.Document,
      verbose_name=translation.ugettext('About page document'),
      collection_name='about_page')
  about_page.group = PROGRAM_DOCUMENTS_GROUP
  about_page.help_text = translation.ugettext('The document with <b>About</b>')

  #: The document entity which contains "Events & Timeline" page
  #: for the program
  events_page = db.ReferenceProperty(
      reference_class=document_model.Document,
      verbose_name=translation.ugettext('Events page document'),
      collection_name='events_page')
  events_page.group = PROGRAM_DOCUMENTS_GROUP
  events_page.help_text = translation.ugettext(
      'The document for the <b>Events & Timeline</b> page')

  #: The url which contains the "Events & Timeline" frame
  events_frame_url = db.LinkProperty(
      verbose_name=translation.ugettext('Events page iframe url'))
  events_frame_url.group = GENERAL_INFO_GROUP
  events_frame_url.help_text = translation.ugettext(
      'The iframe url for the <b>Events & Timeline</b> page')

  #: The document entity which contains the "Connect With Us" page
  #: for the program
  connect_with_us_page = db.ReferenceProperty(
      reference_class=document_model.Document,
      verbose_name=translation.ugettext('Connect with us document'),
      collection_name='connect_with_us_page')
  connect_with_us_page.group = PROGRAM_DOCUMENTS_GROUP
  connect_with_us_page.help_text = translation.ugettext(
      'The document for the <b>Connect With Us</b> page')

  #: The document entity which contains the "Help" page
  #: for the program
  help_page = db.ReferenceProperty(
      reference_class=document_model.Document,
      verbose_name=translation.ugettext('Help document'),
      collection_name='help_page')
  help_page.group = PROGRAM_DOCUMENTS_GROUP
  help_page.help_text = translation.ugettext(
      'The document for the <b>Help</b> page')

  privacy_policy_url = db.LinkProperty(
      verbose_name=translation.ugettext("Privacy Policy"))
  privacy_policy_url.group = GENERAL_INFO_GROUP
  privacy_policy_url.help_text = translation.ugettext(
      "The url for the <b>Privacy Policy</b>")

  #: ATOM or RSS feed URL. Feed entries are shown on the site
  #: page using Google's JavaScript blog widget
  feed_url = db.LinkProperty(verbose_name=translation.ugettext('Feed URL'))
  feed_url.group = CONTACT_INFO_GROUP
  feed_url.help_text = translation.ugettext(
      'The URL should be a valid ATOM or RSS feed. '
      'Feed entries are shown on the program home page.')

  blogger = db.LinkProperty(
      required=False, verbose_name=translation.ugettext("Blogger URL"))
  blogger.group = CONTACT_INFO_GROUP
  blogger.help_text = translation.ugettext(
      "URL of the Blogger home page for the program")

  gplus = db.LinkProperty(
      required=False, verbose_name=translation.ugettext("Google+ URL"))
  gplus.group = CONTACT_INFO_GROUP
  gplus.help_text = translation.ugettext(
      "URL of the Google+ home page for the program")

  email = db.EmailProperty(
      required=False, verbose_name=translation.ugettext("Program email"))
  email.group = CONTACT_INFO_GROUP
  email.help_text = translation.ugettext(
      "Contact email address for the program")

  irc = db.EmailProperty(
      required=False, verbose_name=translation.ugettext("IRC URL"))
  irc.group = CONTACT_INFO_GROUP
  irc.help_text = translation.ugettext(
      "URL of the irc channel for the program in "
      "the format irc://<channel>@server")

  #: Whether the messaging system is enabled
  messaging_enabled = db.BooleanProperty(default=False,
      verbose_name=translation.ugettext('Messaging Enabled'))
  messaging_enabled.group = GENERAL_INFO_GROUP
  messaging_enabled.help_text = translation.ugettext(
      'Indicates if the messaging system should be enabled.')

  #: Property pointing to the file with predefined schools.
  schools = blobstore.BlobReferenceProperty()

  def getProgramMessages(self):
    def get_or_create_txn():
      entity = type(self)._messages_model.all().ancestor(self).get()

      if not entity:
        entity = self._messages_model(parent=self)
        entity.put()
      return entity

    return db.run_in_transaction(get_or_create_txn)
Beispiel #2
0
class CrawlSkipUrl(db.Model):
    url = db.LinkProperty()
    lastseen = db.DateTimeProperty(auto_now_add=True)
    added_on = db.DateTimeProperty(auto_now_add=True)
Beispiel #3
0
class Client(db.Model):
    id = db.StringProperty(required=True)
    name = db.StringProperty(required=True)
    created = db.DateTimeProperty(required=True, auto_now_add=True)
    last_modified = db.DateTimeProperty(required=True, auto_now=True)
    domain = db.LinkProperty(required=True)
Beispiel #4
0
class Profile(soc.models.linkable.Linkable):
  """Per-program user information.

  Parent:
    soc.models.user.User
  """

  #: A required many:1 relationship that ties (possibly multiple
  #: entities of) Role details to a unique User. A Role cannot
  #: exist unassociated from a login identity and credentials. The
  #: back-reference in the User model is a Query named 'roles'.
  user = db.ReferenceProperty(reference_class=soc.models.user.User,
                              required=True, collection_name='roles')

  #: A reference to program entity to which the profile corresponds.
  #: Each profile is created for exactly one program. If the same
  #: user participates in more of them, a separate profile must be created
  #: for each.
  # TODO(daniel): make this field required when it is updated for
  # all existing entities
  program = db.ReferenceProperty(
      reference_class=soc.models.program.Program, required=False,
      collection_name='profiles')

  #: Required field storing publicly-displayed name.  Can be a real name
  #: (though this is not recommended), or a nick name or some other public
  #: alias.  Public names can be any valid UTF-8 text.
  public_name = db.StringProperty(
      required=True, verbose_name=ugettext('Public name'))
  public_name.help_text = ugettext(
      'Human-readable name (UTF-8) that will be displayed publicly on the'
      ' site.')
  public_name.group = PUBLIC_INFO_GROUP

  #====================================================================
  #  (public) name information
  #====================================================================

  #: Required field storing the parts of the Role's name
  #: corresponding to the field names; displayed publicly.
  #: given_name can only be ASCII, not UTF-8 text, because it is
  #: used, for example, as part of the shipping (mailing) address.
  given_name = db.StringProperty(required=True,
      verbose_name=ugettext('First (given) name'))
  given_name.help_text = ugettext('only A-z, 0-9 and whitespace characters')
  given_name.group = PUBLIC_INFO_GROUP

  #: Required field storing the parts of the Role's name
  #: corresponding to the field names; displayed publicly.
  #: Surname can only be ASCII, not UTF-8 text, because it is
  #: used, for example, as part of the shipping (mailing) address.
  surname = db.StringProperty(
      required=True,
      verbose_name=ugettext('Last (family) name'))
  surname.help_text = ugettext('only A-z, 0-9 and whitespace characters')
  surname.group = PUBLIC_INFO_GROUP

  #: Optional field used as a display name, such as for awards
  #: certificates. Should be the entire name in the format
  #: the Role would like it displayed (could be surname followed by
  #: given name in some cultures, for example). Display names can be
  #: any valid UTF-8 text.
  name_on_documents = db.StringProperty(
      verbose_name=ugettext('Legal name'))
  name_on_documents.help_text = ugettext(
      'Optional field used as a display name, such as for documents like '
      'awards certificates. Should be the entire name in the format '
      'the person would like it displayed (could be family name followed '
      'by given name in some cultures, for example). Legal name can be '
      'any valid UTF-8 text.')
  name_on_documents.group = PUBLIC_INFO_GROUP

  #====================================================================
  #  (public) contact information
  #====================================================================

  #: Optional field storing Instant Messaging network; displayed publicly.
  im_network = db.StringProperty(
      verbose_name=ugettext('IM Network'))
  im_network.help_text = ugettext(
      'examples: irc:irc.freenode.net xmpp:gmail.com/Home')
  im_network.group = PUBLIC_INFO_GROUP

  #: Optional field storing Instant Messaging handle; displayed publicly.
  im_handle = db.StringProperty(
      verbose_name=ugettext('IM Handle'))
  im_handle.help_text = ugettext(
      'personal identifier, such as: screen name, IRC nick, user name')
  im_handle.group = PUBLIC_INFO_GROUP

  #: Optional field storing a home page URL; displayed publicly.
  home_page = db.LinkProperty(
      verbose_name=ugettext('Home Page URL'))
  home_page.group = PUBLIC_INFO_GROUP

  #: Optional field storing a blog URL; displayed publicly.
  blog = db.LinkProperty(
      verbose_name=ugettext('Blog URL'))
  blog.group = PUBLIC_INFO_GROUP

  #: Optional field storing a URL to an image, expected to be a
  #: personal photo (or cartoon avatar, perhaps); displayed publicly.
  photo_url = db.LinkProperty(
      verbose_name=ugettext('Thumbnail Photo URL'))
  photo_url.help_text = ugettext(
      'URL of 64x64 pixel thumbnail image')
  photo_url.group = PUBLIC_INFO_GROUP

  #====================================================================
  # (private) contact information
  #====================================================================

  #: Required field used as the contact mechanism for the program
  #: Role (for example the address the system sends emails to).
  email = db.EmailProperty(
      required=True,
      verbose_name=ugettext('Email Address'))
  email.group = CONTACT_INFO_GROUP
  email.help_text = ugettext("This is the address we send all notifications to.")

  #: Required field containing residence street address; kept private.
  #: Residence street address can only be ASCII, not UTF-8 text, because
  #: it may be used as a shipping address.
  res_street = db.StringProperty(required=True,
      verbose_name=ugettext('Street Address 1'))
  res_street.help_text = ugettext(
      'street number and name, '
      'only A-z, 0-9 and whitespace characters')
  res_street.group = CONTACT_INFO_GROUP

  #: Optional field containing the 2nd line for the residence street address;
  #: kept private.
  #: Can only be ASCII, not UTF-8 text, because
  #: it may be used as a shipping address.
  res_street_extra = db.StringProperty(required=False,
      verbose_name=ugettext('Street Address 2'))
  res_street_extra.help_text = ugettext(
      '2nd address line usually for apartment numbers. '
      'only A-z, 0-9 and whitespace characters')
  res_street_extra.group = CONTACT_INFO_GROUP

  #: Required field containing residence address city; kept private.
  #: Residence city can only be ASCII, not UTF-8 text, because it
  #: may be used as a shipping address.
  res_city = db.StringProperty(required=True,
      verbose_name=ugettext('City'))
  res_city.help_text = ugettext(
      'only A-z, 0-9 and whitespace characters')
  res_city.group = CONTACT_INFO_GROUP

  #: Optional field containing residence address state or province; kept
  #: private.  Residence state/province can only be ASCII, not UTF-8
  #: text, because it may be used as a shipping address.
  res_state = db.StringProperty(
      verbose_name=ugettext('State/Province'))
  res_state.help_text = ugettext(
      'optional if country/territory does not have states or provinces, '
      'only A-z, 0-9 and whitespace characters')
  res_state.group = CONTACT_INFO_GROUP

  #: Required field containing residence address country or territory; kept
  #: private.
  res_country = db.StringProperty(required=True,
      verbose_name=ugettext('Country/Territory'),
      choices=countries.COUNTRIES_AND_TERRITORIES)
  res_country.group = CONTACT_INFO_GROUP

  #: Required field containing residence address postal code (ZIP code in
  #: the United States); kept private.  Residence postal code can only be
  #: ASCII, not UTF-8 text, because it may be used as a shipping address.
  res_postalcode = db.StringProperty(required=True,
      verbose_name=ugettext('ZIP/Postal Code'))
  res_postalcode.help_text = ugettext(
      'only A-z, 0-9 and whitespace characters')
  res_postalcode.group = CONTACT_INFO_GROUP

  #: Required field containing a phone number that will be used to
  #: contact the user, also supplied to shippers; kept private.
  phone = db.PhoneNumberProperty(
      required=True,
      verbose_name=ugettext('Phone Number'))
  phone.help_text = ugettext(
      'include complete international calling number with country code, '
      'use numbers only')
  phone.group = CONTACT_INFO_GROUP

  #: Optional field containing a separate recipient name; kept
  #: private. Recipient name can only be ASCII, not UTF-8 text
  ship_name = db.StringProperty(
      verbose_name=ugettext('Full Recipient Name'))
  ship_name.help_text = ugettext(
      'Fill in the name of the person who should be receiving your packages.')
  ship_name.group = SHIPPING_INFO_GROUP

  #: Optional field containing a separate shipping street address; kept
  #: private.  If shipping address is not present in its entirety, the
  #: residence address will be used instead.  Shipping street address can only
  #: be ASCII, not UTF-8 text, because, if supplied, it is used as a
  #: shipping address.
  ship_street = db.StringProperty(
      verbose_name=ugettext('Shipping Street Address 1'))
  ship_street.help_text = ugettext(
      'Street number and name, only A-z, 0-9 and whitespace characters.')
  ship_street.group = SHIPPING_INFO_GROUP

  #: Optional field containing a 2nd line for the shipping street address; kept
  #: private. If shipping address is not present in its entirety, the
  #: residence address will be used instead.  Shipping street address can only
  #: be ASCII, not UTF-8 text, because, if supplied, it is used as a
  #: shipping address.
  ship_street_extra = db.StringProperty(
      verbose_name=ugettext('Shipping Street Address 2'))
  ship_street_extra.help_text = ugettext(
      '2nd address line usually used for apartment numbers, '
      'only A-z, 0-9 and whitespace characters.')
  ship_street_extra.group = SHIPPING_INFO_GROUP

  #: Optional field containing shipping address city; kept private.
  #: Shipping city can only be ASCII, not UTF-8 text, because, if
  #: supplied, it is used as a shipping address.
  ship_city = db.StringProperty(
      verbose_name=ugettext('Shipping City'))
  ship_city.help_text = ugettext(
      'Only A-z, 0-9 and whitespace characters.')
  ship_city.group = SHIPPING_INFO_GROUP

  #: Optional field containing shipping address state or province; kept
  #: private.  Shipping state/province can only be ASCII, not UTF-8
  #: text, because, if supplied, it is used as a shipping address.
  ship_state = db.StringProperty(
      verbose_name=ugettext('Shipping State/Province'))
  ship_state.help_text = ugettext(
      'Optional if country/territory does not have states or provinces, '
      'Only A-z, 0-9 and whitespace characters.')
  ship_state.group = SHIPPING_INFO_GROUP

  #: Optional field containing shipping address country or territory; kept
  #: private.
  ship_country = db.StringProperty(
      verbose_name=ugettext('Shipping Country/Territory'),
      choices=countries.COUNTRIES_AND_TERRITORIES)
  ship_country.help_text = ugettext(
      'Only A-z, 0-9 and whitespace characters.')
  ship_country.group = SHIPPING_INFO_GROUP

  #: Optional field containing shipping address postal code (ZIP code in
  #: the United States); kept private.  Shipping postal code can only be
  #: ASCII, not UTF-8 text, because, if supplied, it is used as a
  #: shipping address.
  ship_postalcode = db.StringProperty(
      verbose_name=ugettext('Shipping ZIP/Postal Code'))
  ship_postalcode.help_text = ugettext(
      'Only A-z, 0-9 and whitespace characters')
  ship_postalcode.group = SHIPPING_INFO_GROUP

  #====================================================================
  # (private) personal information
  #====================================================================

  #: Required field containing the Role's birthdate (for
  #: determining Program participation eligibility); kept private.
  birth_date = db.DateProperty(
      required=True,
      verbose_name=ugettext('Birth Date'))
  birth_date.help_text = ugettext(
      'format YYYY-MM-DD, required for determining program eligibility')
  birth_date.group = PRIVATE_INFO_GROUP

  #: Optional field indicating choice of t-shirt fit; kept private.
  tshirt_style = db.StringProperty(
      verbose_name=ugettext('T-shirt Style'),
      choices=('male', 'female'))
  tshirt_style.group = PRIVATE_INFO_GROUP

  #: Optional field indicating choice of t-shirt, from XXS to XXXL;
  #: kept private.
  tshirt_size = db.StringProperty(
      verbose_name=ugettext('T-shirt Size'),
      choices=('XXS', 'XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL'))
  tshirt_size.group = PRIVATE_INFO_GROUP
  tshirt_size.help_text = ugettext('See also '
      '<a href="http://bit.ly/ayGxJk" target="_blank"> for women</a> and '
      '<a href="http://bit.ly/8ZrywF" target="_blank">for men</a>.')

  #: Optional field indicating gender;
  #: kept private.
  gender = db.StringProperty(
      verbose_name=ugettext('Gender'),
      choices=('male', 'female', 'other'))
  gender.group = PRIVATE_INFO_GROUP

  #: Property to gain insight into where students heard about this program
  program_knowledge = db.TextProperty(required=False, verbose_name=ugettext(
      "How did you hear about this program?"))
  program_knowledge.help_text = ugettext("Please be as "
      "specific as possible, e.g. blog post (include URL if possible), mailing "
      "list (please include list address), information session (please include "
      "location and speakers if you can), etc.")
  program_knowledge.group = PRIVATE_INFO_GROUP

  #: field storing wheter the User has agreed to the site-wide Terms of Service.
  #: (Not a required field because the Terms of Service might not be present
  #: when the first User profile is created when bootstrapping the site.)
  agreed_to_tos = db.BooleanProperty(required=False, default=False,
      verbose_name=ugettext('I Agree to the Terms of Service'))
  agreed_to_tos.help_text = ugettext(
      'Indicates whether the user agreed to this role Terms of Service.')
  agreed_to_tos.group = TERMS_OF_SERVICE_GROUP

  #: field storing when the User has agreed to the site-wide Terms of Service.
  #: (Not a required field because the Terms of Service might not be present
  #: when the first User profile is created when bootstrapping the site.)
  agreed_to_tos_on = db.DateTimeProperty(required=False, default=None,
      verbose_name=ugettext('Has agreed to the Terms of Service on'))
  agreed_to_tos_on.help_text = ugettext(
      'Indicates when the user agreed to this role Terms of Service.')
  agreed_to_tos.group = TERMS_OF_SERVICE_GROUP

  #: field storing the status of this role
  #: Active means that this role can exercise all it's privileges.
  #: Invalid means that a role should not be able to excercise any
  #: priviliges.
  status = db.StringProperty(default='active',
      choices=['active', 'invalid'],
      verbose_name=ugettext('Status of this Role'))
  status.help_text = ugettext('Indicates the status of the role '
      'concerning which privileges may be used.')

  #====================================================================
  #notification settings
  #====================================================================

  notify_new_requests = db.BooleanProperty(required=False, default=True,
      verbose_name=ugettext('Notify of new requests'))
  notify_new_requests.help_text = ugettext(
      'Whether to send an email notification when new requests are submitted.')
  notify_new_requests.group = NOTIFICATION_SETTINGS_GROUP

  notify_request_handled = db.BooleanProperty(required=False, default=True,
      verbose_name=ugettext('Notify of handled requests'))
  notify_request_handled.help_text = ugettext(
      'Whether to send an email notification when your request is handled.')
  notify_request_handled.group = NOTIFICATION_SETTINGS_GROUP

  #====================================================================
  #specific roles information
  #====================================================================

  #: field storing whether the User is a student
  is_student = db.BooleanProperty(required=False, default=False,
      verbose_name=ugettext('Is student'))

  #: field storing whether the User is a mentor
  is_mentor = db.BooleanProperty(required=False, default=False,
      verbose_name=ugettext('Is Mentor'))

  #: field storing whether the User is an org amdin
  is_org_admin = db.BooleanProperty(required=False, default=False,
      verbose_name=ugettext('Is Organization Administrator'))

  #: List of organizations that the user with the role is a mentor for
  mentor_for = db.ListProperty(item_type=db.Key, default=[])
  mentor_for.help_text = ugettext('List of organizations for which the user '
      'is a mentor.')

  #: List of organizations that the user with the role is an org admin for
  org_admin_for = db.ListProperty(item_type=db.Key, default=[])
  org_admin_for.help_text = ugettext('List of organizations for which '
      'the user is an organization admin.')

  #: Points to student specific information if the user has a student role
  student_info = db.ReferenceProperty(required=False, default=None,
      reference_class=StudentInfo)

  created_on = db.DateTimeProperty(auto_now_add=True)

  modified_on = db.DateTimeProperty(auto_now=True)

  def _fix_name(self, commit=True):
    """Retrieves the name property from the parent user.
    """
    pass

  def name(self):
    """Property as 'name' for use in common templates.
    """
    return self.public_name

  def document_name(self):
    """Property as 'document_name' used on for example award certificates.
    """
    if self.name_on_documents:
      return self.name_on_documents
    else:
      return self.name()

  def full_name(self):
    """Property which returns given name followed by surname and separated
    by a single space character.
    """
    return '%s %s' % (self.given_name, self.surname)

  def shipping_name(self):
    """Property recipient_name that returns shipping name if shipping
    address is set else the given name and surname.
    """
    return self.ship_name if self.hasShippingAddress() else self.given_name + " " + self.surname

  def shipping_street(self):
    """Property shipping_street that returns shipping street if
    shipping address is set else the residential street.
    """
    return self.ship_street if self.hasShippingAddress() else self.res_street

  def shipping_street_extra(self):
    """Property shipping_street_extra that returns the 2nd shipping address line
    if shipping address is set else the residential 2nd address line.
    """
    return self.ship_street_extra if self.hasShippingAddress() else \
        self.res_street_extra

  def shipping_city(self):
    """Property shipping_city that returns shipping city if
    shipping address is set else the residential city.
    """
    return self.ship_city if self.hasShippingAddress() else self.res_city

  def shipping_state(self):
    """Property shipping_state that returns shipping state if
    shipping address is set else the residential state.
    """
    return self.ship_state if self.hasShippingAddress() else self.res_state

  def shipping_country(self):
    """Property shipping_country that returns shipping country if
    shipping address is set else the residential country.
    """
    return self.ship_country if self.hasShippingAddress() else self.res_country

  def shipping_postalcode(self):
    """Property shipping_postalcode that returns the shipping postal code if
    shipping address set else the residential postal code.
    """
    return self.ship_postalcode if self.hasShippingAddress() else \
        self.res_postalcode

  def hasShippingAddress(self):
    """Checks if the required fields for the shipping address are set.
    """
    return self.ship_city and self.ship_country and self.ship_postalcode and \
        self.ship_street

  def ccTld(self):
    """Property as 'ccTld' for use in Maps.
    """
    return countries.COUNTRIES_TO_CCTLD[self.res_country]
Beispiel #5
0
class Feedback(db.Model):
    name = db.LinkProperty()
class Post(db.Model):
    title = db.StringProperty(required=True)
    url = db.LinkProperty(required=False)
    message = db.TextProperty()
    user = db.ReferenceProperty(User, collection_name='posts')
    created = db.DateTimeProperty(auto_now_add=True)
    karma = db.FloatProperty()
    edited = db.BooleanProperty(default=False)
    twittered = db.BooleanProperty(default=False)

    def to_json(self):
        return {
            'id': str(self.key()),
            'title': self.title,
            'message': self.message,
            'created': self.created.strftime("%s"),
            'user': self.user.nickname,
            'comment_count': self.cached_comment_count,
            'url': self.url,
            'votes': self.prefetched_sum_votes
        }

    def url_netloc(self):
        return urlparse(self.url).netloc

    def can_edit(self):
        session = get_current_session()
        if session.has_key('user'):
            user = session['user']
            if self.user.key() == user.key() or user.admin:
                return True
        return False

    # This is duplicated code from the pre_fetcher
    # Do not edit if you don't update those functions too
    def sum_votes(self):
        val = memcache.get("p_" + str(self.key()))
        if val is not None:
            return val
        else:
            val = self.votes.count()
            memcache.add("p_" + str(self.key()), val, 3600)
            return val

    # This is duplicated code from the pre_fetcher
    # Do not edit if you don't update those functions too
    def already_voted(self):
        session = get_current_session()
        if session.has_key('user'):
            user = session['user']
            # hit memcache for this
            memValue = memcache.get("vp_" + str(self.key()) + "_" +
                                    str(user.key()))
            if memValue is not None:
                return memValue == 1
            else:
                vote = Vote.all().filter("user ="******"post =", self).fetch(1)
                memcache.add("vp_" + str(self.key()) + "_" + str(user.key()),
                             len(vote), 3600)
                return len(vote) == 1
        else:
            return False

    def remove_from_memcache(self):
        memcache.delete("pc_" + str(self.key()))
        memcache.delete("p_" + str(self.key()))
        session = get_current_session()
        if session.has_key('user'):
            user = session['user']
            user.remove_from_memcache()
            memcache.delete("vp_" + str(self.key()) + "_" + str(user.key()))
        self.calculate_karma()

    def calculate_karma(self):
        delta = (datetime.now() - self.created)
        seconds = delta.seconds + delta.days * 86400
        hours = seconds / 3600 + 1
        votes = self.sum_votes()
        gravity = 1.8
        karma = (votes - 1) / pow((hours + 2), gravity)
        self.karma = karma
        self.put()

    @staticmethod
    def remove_cached_count_from_memcache():
        memcache.delete("Post_count")

    @staticmethod
    def get_cached_count():
        memValue = memcache.get("Post_count")
        if memValue is not None:
            return memValue
        else:
            count = Post.all().count()
            memcache.add("Post_count", count, 3600)
            return count
Beispiel #7
0
class Website(db.Model):
    #person = db.ReferenceProperty(required = True, collection_name = 'persons')
    address = db.LinkProperty(required=True)
    group = db.ReferenceProperty(required=True,
                                 collection_name='research_groups')
    authors = db.ListProperty(db.Key, required=True)
class Menu(db.Model):
    user_id = db.StringProperty(required=True)
    dish_name = db.StringProperty()
    price = db.FloatProperty()
    photo_link = db.LinkProperty()
    restriction_list = db.StringListProperty()
Beispiel #9
0
class Agency(GeoModel):
    # properties straight out of the NTD import
    ntd_id                = db.StringProperty()
    gtfs_data_exchange_id = db.ListProperty(unicode)
    name                  = db.StringProperty(required=True)
    short_name            = db.StringProperty()
    city            = db.StringProperty(required=True)
    state           = db.StringProperty(required=True)
    country         = db.StringProperty(default="us")
    postal_code     = db.IntegerProperty()
    address         = db.StringProperty()
    agency_url      = db.LinkProperty()
    executive       = db.StringProperty()
    executive_email = db.EmailProperty()
    twitter         = db.StringProperty()
    contact_email   = db.EmailProperty()
    phone           = db.StringProperty()
    service_area_population = db.IntegerProperty()
    passenger_miles         = db.IntegerProperty()
    
    # bookkeeping
    updated         = db.DateTimeProperty()
    date_opened     = db.DateTimeProperty()
    
    # developer amenities
    dev_site         = db.LinkProperty() #None if no developer site
    arrival_data     = db.LinkProperty() #Link to arrival data source; None if no arrival data
    position_data    = db.LinkProperty() #Link to position data source; None if no position data
    standard_license = db.StringProperty() #String of standard license like "GPL"; None if no standard license    
    
    # slugs
    nameslug        = db.StringProperty()
    cityslug        = db.StringProperty()
    stateslug       = db.StringProperty()
    countryslug     = db.StringProperty()
    urlslug         = db.StringProperty()
    
    # whether or not the agency is a non-government organization
    private         = db.BooleanProperty(default=False)
    
    def __init__(self, *args, **kwargs):
        # this loads everything to self that's passed as a kwarg, making required and default attribs safe to use
        GeoModel.__init__(self, *args, **kwargs)
        if "location" in kwargs:
            self.update_location()
        self.update_slugs()
        
    def __str__(self):
        return "%s in %s, %s (%s)" % (self.name, self.city, self.state, self.country)
        
    def update_slugs(self):
        self.nameslug = slugify(self.name)
        self.cityslug = slugify(self.city)
        self.stateslug = slugify(self.state)
        self.countryslug = slugify(self.country)
        self.urlslug = "%s/%s/%s/%s"%(self.countryslug,self.stateslug,self.cityslug,self.nameslug)
    
    def to_jsonable(self):
        return {
            'ntd_id':self.ntd_id,
            'gtfs_data_exchange_id':self.gtfs_data_exchange_id,
            'date_opened':self.date_opened.isoformat(" ") if self.date_opened else None,
            'passenger_miles':self.passenger_miles,
            'is_public':self.is_public,
            'name': cgi.escape(self.name),
            'short_name': cgi.escape(self.short_name) if self.short_name else None,
            'city': cgi.escape(self.city),
            'urlslug': self.urlslug,
            'state': cgi.escape(self.state),
            'details_url': self.details_url,
            'key_encoded': str(self.key()),
            'has_real_time_data': self.has_real_time_data,
            'latitude':(self.location.lat if self.location else None),
            'longitude':(self.location.lon if self.location else None),
            'executive':cgi.escape(self.executive) if self.executive else None,
            'executive_email':cgi.escape(self.executive_email) if self.executive_email else None,
            'agency_url':cgi.escape(self.agency_url) if self.agency_url else None,
        }

    @staticmethod
    def fetch_all_agencies_as_jsonable():
        memcache_key = "all-agencies-as-jsonable"
        all_as_jsonable = memcache.get(memcache_key)
        if all_as_jsonable is None:
            all_as_jsonable = [agency.to_jsonable() for agency in Agency.all()]
            memcache.set(memcache_key, all_as_jsonable, time = settings.MEMCACHE_DEFAULT_SECONDS)
        return all_as_jsonable

    @property
    def details_url(self):
        return reverse("agencies_all_slugs", kwargs={"countryslug": self.countryslug, "stateslug": self.stateslug, "cityslug": self.cityslug, "nameslug": self.nameslug})
                
    @property
    def is_public(self):
        return (self.date_opened != None)

    @staticmethod
    def fetch_agencies_near(latitude, longitude, query = None, max_results = 50, bbox_side_in_miles = settings.BBOX_SIDE_IN_MILES):
        bounding_box = square_bounding_box_centered_at(latitude, longitude, bbox_side_in_miles)
        if query is None:
            query = Agency.all()
        return Agency.bounding_box_fetch(query, bounding_box, max_results = max_results)        
        
    @property
    def has_real_time_data(self):
        return (self.arrival_data != None) or (self.position_data != None)
        
    @staticmethod
    def all_public_agencies():
        """Return a query to all Agency entities marked 'public' by Brandon's import scripts."""
        return Agency.all().filter('date_opened !=', None)

    @staticmethod    
    def get_state_list():
        #factoring this out since we want all states all the time
        #and because we want to memcache this
        #todo: add other countries (return dict where value includes proper url)
        mem_result = memcache.get('all_states')
        if not mem_result:
            states = uniquify([(a.countryslug,a.stateslug) for a in Agency.all()])
            states.sort(key=lambda x:x[1])
            mc_added = memcache.add('all_states', states, settings.MEMCACHE_DEFAULT_SECONDS)
        else:
            states = mem_result

        return states
        
    @staticmethod    
    def get_country_list():
        #factoring this out since we want all states all the time
        #and because we want to memcache this
        #todo: add other countries (return dict where value includes proper url)
        mem_result = memcache.get('all_countries')
        if not mem_result:
            countries = uniquify([a.countryslug for a in Agency.all()])
            countries.sort()
            mc_added = memcache.add('all_countries', countries, settings.MEMCACHE_DEFAULT_SECONDS)
        else:
            countries = mem_result

        return countries
    
    @staticmethod
    def fetch_for_slugs(countryslug = None, stateslug = None, cityslug = None):
        agency_query = Agency.all()        
        if cityslug:
            agency_query = agency_query.filter('cityslug =', cityslug)            
        if stateslug:
            agency_query = agency_query.filter('stateslug =', stateslug)            
        if countryslug:
            agency_query = agency_query.filter('countryslug =',countryslug)            
        return [agency for agency in agency_query]
    
    @staticmethod
    def fetch_explicitly_supported_for_transit_app(transit_app):
        """Return a list of Agency entities that are explicitly supported by the transit app."""
        return Agency.get(transit_app.explicitly_supported_agency_keys)
        
    @staticmethod
    def iter_explicitly_supported_for_transit_app(transit_app):
        """Return an iterator over Agency entities that are explicitly supported by the transit app."""
        # Not a true lazy iterator, but this should be plenty fast
        for agency in Agency.fetch_explicitly_supported_for_transit_app(transit_app):
            yield agency
        
    @staticmethod
    def fetch_for_transit_app(transit_app, uniquify = True):
        """Return a list of Agency entities, by default unique, that the given transit app supports"""
        return [agency for agency in Agency.iter_for_transit_app(transit_app, uniquify)]
        
    @staticmethod
    def iter_for_transit_app(transit_app, uniquify = True):
        """Return an iterator over Agency entities, by default unique, that the given transit app supports"""
        seen_set = set()
        for explicit_agency in iter_uniquify(Agency.iter_explicitly_supported_for_transit_app(transit_app), seen_set, uniquify):
            yield explicit_agency
        if transit_app.supports_all_public_agencies:
            for public_agency in iter_uniquify(Agency.all_public_agencies(), seen_set, uniquify):
                yield public_agency
        
    @staticmethod
    def fetch_for_transit_apps(transit_apps, uniquify = True):
        """Return a list of Agency entities, by default unique, that at least one transit application in the transit_apps list supports."""
        return [agency for agency in Agency.iter_for_transit_apps(transit_apps, uniquify)]

    @staticmethod
    def iter_for_transit_apps(transit_apps, uniquify = True):
        """Return an iterator over Agency entities, by default unique, that at least one transit application in the transit_apps list supports."""
        seen_set = set()
        for transit_app in transit_apps:
            for agency in iter_uniquify(Agency.iter_for_transit_app(transit_app, uniquify = False), seen_set, uniquify):
                yield agency         
Beispiel #10
0
class Post(db.Model):
    title = db.StringProperty(required=True)
    url = db.LinkProperty(required=False)
    message = db.TextProperty()
    user = db.ReferenceProperty(User, collection_name='posts')
    created = db.DateTimeProperty(auto_now_add=True)
    karma = db.FloatProperty()

    def url_netloc(self):
        return urlparse(self.url).netloc

    def cached_comment_count(self):
        val = memcache.get("pc_" + str(self.key()))
        if val is not None:
            return str(val)
        else:
            val = self.comments.count()
            memcache.add("pc_" + str(self.key()), val, 3600)
            return str(val)

    def sum_votes(self):
        val = memcache.get("p_" + str(self.key()))
        if val is not None:
            return val
        else:
            val = self.votes.count()
            memcache.add("p_" + str(self.key()), val, 3600)
            return val

    def already_voted(self):
        session = get_current_session()
        if session.has_key('user'):
            user = session['user']
            # hit memcache for this
            memValue = data = memcache.get("vp_" + str(self.key()) + "_" +
                                           str(user.key()))
            if memValue is not None:
                return memValue == 1
            else:
                vote = Vote.all().filter("user ="******"post =", post).fetch(1)
                memcache.add("vp_" + str(self.key()) + "_" + str(user.key()),
                             len(vote), 3600)
                return len(vote) == 1
        else:
            return False

    def remove_from_memcache(self):
        memcache.delete("pc_" + str(self.key()))
        memcache.delete("p_" + str(self.key()))
        session = get_current_session()
        if session.has_key('user'):
            user = session['user']
            user.remove_from_memcache()
            memcache.delete("vp_" + str(self.key()) + "_" + str(user.key()))
        self.calculate_karma()

    def calculate_karma(self):
        delta = (datetime.now() - self.created)
        seconds = delta.seconds + delta.days * 86400
        hours = seconds / 3600 + 1
        self.karma = self.sum_votes() / float(hours)
        self.karma = self.karma * self.karma
        self.put()

    @staticmethod
    def remove_cached_count_from_memcache():
        memcache.delete("Post_count")

    @staticmethod
    def get_cached_count():
        memValue = memcache.get("Post_count")
        if memValue is not None:
            return memValue
        else:
            count = Post.all().count()
            memcache.add("Post_count", count, 3600)
            return count
Beispiel #11
0
class Role(soc.models.linkable.Linkable):
    """Information common to Program participation for all Roles.

  Some details of a Role are considered "public" information, and nearly
  all of these are optional (except for given_name, surname, and email).
  Other details of a Role are kept "private" and are only provided to
  other Users in roles that "need to know" this information.  How these
  fields are revealed is usually covered by Program terms of service.

  Role is the entity that is created when a User actually participates
  in some fashion in a Program. Role details could *possibly* be collected
  without actual participation (voluntary, opt-in, of course).

  A Role is a User's participation in a single Program.  To avoid
  duplication of data entry, facilities will be available for selecting
  an existing Role associated with a particular User to be duplicated for
  participation in a new Program.

  A User has to have at least one Role in order to be able to create
  any Work (such as a Document) on the site.  The easiest-to-obtain Role is
  probably Club Member (though Clubs can set their own membership criteria).

  A Role entity participates in the following relationships implemented
  as a db.ReferenceProperty elsewhere in another db.Model:

   documentation) a 1:many relationship of Documentation (tax forms,
     letters from schools, etc.) associated with the Role by Hosts.  This
     relation is implemented as the 'documentation' back-reference Query of
     the Documentation model 'role' reference.

   works) a many:many relationship with Works, stored in a separate
     WorksRoles model, representing the Work authored by this Role.
     See the WorksRoles model class for details.
  """

    #: A required many:1 relationship that ties (possibly multiple
    #: entities of) Role details to a unique User. A Role cannot
    #: exist unassociated from a login identity and credentials. The
    #: back-reference in the User model is a Query named 'roles'.
    user = db.ReferenceProperty(reference_class=soc.models.user.User,
                                required=True,
                                collection_name='roles')

    #====================================================================
    #  (public) name information
    #====================================================================

    #: Required field storing the parts of the Role's name
    #: corresponding to the field names; displayed publicly.
    #: given_name can only be ASCII, not UTF-8 text, because it is
    #: used, for example, as part of the shipping (mailing) address.
    given_name = db.StringProperty(required=True,
                                   verbose_name=ugettext('First (given) name'))
    given_name.help_text = ugettext(
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
    )
    given_name.group = ugettext("1. Public Info")

    #: Required field storing the parts of the Role's name
    #: corresponding to the field names; displayed publicly.
    #: Surname can only be ASCII, not UTF-8 text, because it is
    #: used, for example, as part of the shipping (mailing) address.
    surname = db.StringProperty(required=True,
                                verbose_name=ugettext('Last (family) name'))
    surname.help_text = ugettext(
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
    )
    surname.group = ugettext("1. Public Info")

    #: Optional field used as a display name, such as for awards
    #: certificates. Should be the entire name in the format
    #: the Role would like it displayed (could be surname followed by
    #: given name in some cultures, for example). Display names can be
    #: any valid UTF-8 text.
    name_on_documents = db.StringProperty(
        verbose_name=ugettext('Name on documents'))
    name_on_documents.help_text = ugettext(
        'Optional field used as a display name, such as for documents like '
        'awards certificates. Should be the entire name in the format '
        'the person would like it displayed (could be family name followed '
        'by given name in some cultures, for example). Name on documents can be '
        'any valid UTF-8 text.')
    name_on_documents.group = ugettext("1. Public Info")

    #====================================================================
    #  (public) contact information
    #====================================================================

    #: Optional field storing Instant Messaging network; displayed publicly.
    im_network = db.StringProperty(verbose_name=ugettext('IM Network'))
    im_network.help_text = ugettext(
        'examples: irc:irc.freenode.net xmpp:gmail.com/Home')
    im_network.group = ugettext("1. Public Info")

    #: Optional field storing Instant Messaging handle; displayed publicly.
    im_handle = db.StringProperty(verbose_name=ugettext('IM Handle'))
    im_handle.help_text = ugettext(
        'personal identifier, such as: screen name, IRC nick, user name')
    im_handle.group = ugettext("1. Public Info")

    #: Optional field storing a home page URL; displayed publicly.
    home_page = db.LinkProperty(verbose_name=ugettext('Home Page URL'))
    home_page.group = ugettext("1. Public Info")

    #: Optional field storing a blog URL; displayed publicly.
    blog = db.LinkProperty(verbose_name=ugettext('Blog URL'))
    blog.group = ugettext("1. Public Info")

    #: Optional field storing a URL to an image, expected to be a
    #: personal photo (or cartoon avatar, perhaps); displayed publicly.
    photo_url = db.LinkProperty(verbose_name=ugettext('Thumbnail Photo URL'))
    photo_url.help_text = ugettext('URL of 64x64 pixel thumbnail image')
    photo_url.group = ugettext("1. Public Info")

    #: Optional field storing the latitude provided by the Role; displayed
    #: publicly.
    latitude = db.FloatProperty(verbose_name=ugettext('Latitude'))
    latitude.help_text = ugettext(
        'decimal degrees northerly (N), use minus sign (-) for southerly (S)')
    latitude.group = ugettext("1. Public Info")

    #: Optional field storing the longitude provided by the Role; displayed
    #: publicly.
    longitude = db.FloatProperty(verbose_name=ugettext('Longitude'))
    longitude.help_text = ugettext(
        'decimal degrees easterly (E), use minus sign (-) for westerly (W)')
    longitude.group = ugettext("1. Public Info")

    #====================================================================
    # (private) contact information
    #====================================================================

    #: Required field used as the contact mechanism for the program
    #: Role (for example the address the system sends emails to).
    email = db.EmailProperty(required=True,
                             verbose_name=ugettext('Email Address'))
    email.group = ugettext("2. Contact Info (Private)")

    #: Required field containing residence street address; kept private.
    #: Residence street address can only be ASCII, not UTF-8 text, because
    #: it may be used as a shipping address.
    res_street = db.StringProperty(required=True,
                                   verbose_name=ugettext('Street address'))
    res_street.help_text = ugettext(
        'street number and name, '
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
    )
    res_street.group = ugettext("2. Contact Info (Private)")

    #: Required field containing residence address city; kept private.
    #: Residence city can only be ASCII, not UTF-8 text, because it
    #: may be used as a shipping address.
    res_city = db.StringProperty(required=True, verbose_name=ugettext('City'))
    res_city.help_text = ugettext(
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
    )
    res_city.group = ugettext("2. Contact Info (Private)")

    #: Optional field containing residence address state or province; kept
    #: private.  Residence state/province can only be ASCII, not UTF-8
    #: text, because it may be used as a shipping address.
    res_state = db.StringProperty(verbose_name=ugettext('State/Province'))
    res_state.help_text = ugettext(
        'optional if country/territory does not have states or provinces, '
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
    )
    res_state.group = ugettext("2. Contact Info (Private)")

    #: Required field containing residence address country or territory; kept
    #: private.
    res_country = db.StringProperty(
        required=True,
        verbose_name=ugettext('Country/Territory'),
        choices=countries.COUNTRIES_AND_TERRITORIES)
    res_country.group = ugettext("2. Contact Info (Private)")

    #: Required field containing residence address postal code (ZIP code in
    #: the United States); kept private.  Residence postal code can only be
    #: ASCII, not UTF-8 text, because it may be used as a shipping address.
    res_postalcode = db.StringProperty(
        required=True, verbose_name=ugettext('ZIP/Postal Code'))
    res_postalcode.help_text = ugettext(
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
    )
    res_postalcode.group = ugettext("2. Contact Info (Private)")

    #: Required field containing a phone number that will be used to
    #: contact the user, also supplied to shippers; kept private.
    phone = db.PhoneNumberProperty(required=True,
                                   verbose_name=ugettext('Phone Number'))
    phone.help_text = ugettext(
        'include complete international calling number with country code')
    phone.example_text = ugettext(
        "e.g. 1650253000 for Google's Corp HQ number in the United States")
    phone.group = ugettext("2. Contact Info (Private)")

    #: field storing whether the User has agreed to publish his location
    publish_location = db.BooleanProperty(
        required=False,
        default=False,
        verbose_name=ugettext('Publish my location'))
    publish_location.help_text = ugettext(
        'By checking this box, you are agreeing to allow your location to be'
        ' displayed, as given by the Marker below, on any map.'
        ' For instance on the map linking Students to Mentors or'
        ' by showing your location on your public profile page in the system.')
    publish_location.example_text = ugettext('You can set your location below')
    publish_location.group = ugettext("2. Contact Info (Private)")

    #: Optional field containing a separate shipping street address; kept
    #: private.  If shipping address is not present in its entirety, the
    #: residence address will be used instead.  Shipping street address can only
    #: be ASCII, not UTF-8 text, because, if supplied, it is used as a
    #: shipping address.
    ship_street = db.StringProperty(
        verbose_name=ugettext('Shipping Street address'))
    ship_street.help_text = ugettext(
        'street number and name, '
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
        'fill in only if not same as above')
    ship_street.group = ugettext("3. Shipping Info (Private and Optional)")

    #: Optional field containing shipping address city; kept private.
    #: Shipping city can only be ASCII, not UTF-8 text, because, if
    #: supplied, it is used as a shipping address.
    ship_city = db.StringProperty(verbose_name=ugettext('Shipping City'))
    ship_city.help_text = ugettext(
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
        'fill in only if not same as above')
    ship_city.group = ugettext("3. Shipping Info (Private and Optional)")

    #: Optional field containing shipping address state or province; kept
    #: private.  Shipping state/province can only be ASCII, not UTF-8
    #: text, because, if supplied, it is used as a shipping address.
    ship_state = db.StringProperty(
        verbose_name=ugettext('Shipping State/Province'))
    ship_state.help_text = ugettext(
        'optional if country/territory does not have states or provinces, '
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only '
        'fill in only if not same as above')
    ship_state.group = ugettext("3. Shipping Info (Private and Optional)")

    #: Optional field containing shipping address country or territory; kept
    #: private.
    ship_country = db.StringProperty(
        verbose_name=ugettext('Shipping Country/Territory'),
        choices=countries.COUNTRIES_AND_TERRITORIES)
    ship_country.help_text = ugettext('fill in only if not same as above')
    ship_country.group = ugettext("3. Shipping Info (Private and Optional)")

    #: Optional field containing shipping address postal code (ZIP code in
    #: the United States); kept private.  Shipping postal code can only be
    #: ASCII, not UTF-8 text, because, if supplied, it is used as a
    #: shipping address.
    ship_postalcode = db.StringProperty(
        verbose_name=ugettext('Shipping ZIP/Postal Code'))
    ship_postalcode.help_text = ugettext(
        '<a href="http://en.wikipedia.org/wiki/ASCII">ASCII</a> characters only'
        'fill in only if not same as above')
    ship_postalcode.group = ugettext("3. Shipping Info (Private and Optional)")

    #====================================================================
    # (private) personal information
    #====================================================================

    #: Required field containing the Role's birthdate (for
    #: determining Program participation eligibility); kept private.
    birth_date = db.DateProperty(required=True,
                                 verbose_name=ugettext('Birth Date'))
    birth_date.help_text = ugettext(
        'required for determining program eligibility')
    birth_date.group = ugettext("4. Private Info")
    birth_date.example_text = ugettext('e.g. 1999-12-31 or 12/31/1999')

    #: Optional field indicating choice of t-shirt fit; kept private.
    tshirt_style = db.StringProperty(verbose_name=ugettext('T-shirt Style'),
                                     choices=('male', 'female'))
    tshirt_style.group = ugettext("4. Private Info")

    #: Optional field indicating choice of t-shirt, from XXS to XXXL;
    #: kept private.
    tshirt_size = db.StringProperty(verbose_name=ugettext('T-shirt Size'),
                                    choices=('XXS', 'XS', 'S', 'M', 'L', 'XL',
                                             'XXL', 'XXXL'))
    tshirt_size.group = ugettext("4. Private Info")
    tshirt_size.example_text = ugettext(
        'See also '
        '<a href="http://en.wikipedia.org/wiki/US_standard_clothing_size">'
        'this article</a>.')

    #: field storing wheter the User has agreed to the site-wide Terms of Service.
    #: (Not a required field because the Terms of Service might not be present
    #: when the first User profile is created when bootstrapping the site.)
    agreed_to_tos = db.BooleanProperty(
        required=False,
        default=False,
        verbose_name=ugettext('I Agree to the Terms of Service'))
    agreed_to_tos.help_text = ugettext(
        'Indicates whether the user agreed to this role Terms of Service.')
    agreed_to_tos.group = ugettext("99. Terms of Service")

    #: field storing when the User has agreed to the site-wide Terms of Service.
    #: (Not a required field because the Terms of Service might not be present
    #: when the first User profile is created when bootstrapping the site.)
    agreed_to_tos_on = db.DateTimeProperty(
        required=False,
        default=None,
        verbose_name=ugettext('Has agreed to the Terms of Service on'))
    agreed_to_tos_on.help_text = ugettext(
        'Indicates when the user agreed to this role Terms of Service.')
    agreed_to_tos.group = ugettext("99. Terms of Service")

    #: field storing the status of this role
    #: Active means that this role can exercise all it's privileges.
    #: Invalid mean that this role cannot exercise it's privileges.
    #: Inactive means that this role cannot exercise it's data-editing
    #: privileges but should be able to see the data. For instance when a program
    #: has been marked inactive an Organization Admin should still be able to see
    #: the student applications.
    status = db.StringProperty(default='active',
                               choices=['active', 'invalid', 'inactive'],
                               verbose_name=ugettext('Status of this Role'))
    status.help_text = ugettext('Indicates the status of the role '
                                'concerning which privileges may be used.')

    def name(self):
        """Property as 'name' for use in common templates.
    """
        return '%s %s' % (self.given_name, self.surname)

    def document_name(self):
        """Property as 'document_name' used on for example award certificates.
    """
        if self.name_on_documents:
            return self.name_on_documents
        else:
            return self.name()

    def shipping_street(self):
        """Property shipping_street that returns shipping street if
    shipping address is set else the residential street.
    """
        return self.ship_street if self.hasShippingAddress(
        ) else self.res_street

    def shipping_city(self):
        """Property shipping_city that returns shipping city if
    shipping address is set else the residential city.
    """
        return self.ship_city if self.hasShippingAddress() else self.res_city

    def shipping_state(self):
        """Property shipping_state that returns shipping state if
    shipping address is set else the residential state.
    """
        return self.ship_state if self.hasShippingAddress() else self.res_state

    def shipping_country(self):
        """Property shipping_country that returns shipping country if
    shipping address is set else the residential country.
    """
        return self.ship_country if self.hasShippingAddress(
        ) else self.res_country

    def shipping_postalcode(self):
        """Property shipping_postalcode that returns the shipping postal code if
    shipping address set else the residential postal code.
    """
        return self.ship_postalcode if self.hasShippingAddress() else \
            self.res_postalcode

    def hasShippingAddress(self):
        """Checks if the required fields for the shipping address are set.
    """
        return self.ship_city and self.ship_country and self.ship_postalcode and \
            self.ship_street

    def ccTld(self):
        """Property as 'ccTld' for use in Maps.
    """
        return countries.COUNTRIES_TO_CCTLD[self.res_country]
Beispiel #12
0
class PugPe(db.Model):
    href = db.LinkProperty(required=True)
    created_at = db.DateTimeProperty(auto_now_add=True)

    KEY_BASE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    BASE = 64

    def code(self):
        '''
        Return our base-62 encoded id
        '''
        if not self.is_saved():
            return None

        nid = self.key().id()
        s = []
        while nid:
            nid, c = divmod(nid, PugPe.BASE)
            s.append(PugPe.KEY_BASE[c])
        s.reverse()
        return "".join(s)

    def to_text(self):
        return 'http://pug.pe/%s' % self.code()

    def to_json(self):
        return "{\"code\":\"%s\",\"href\":\"%s\"}\n" % ('http://pug.pe/' +
                                                        self.code(), self.href)

    def save_in_cache(self):
        """We don't really care if this fails"""
        memcache.set(self.code(), self)

    @staticmethod
    def find_or_create_by_href(href):
        query = db.Query(PugPe)
        query.filter('href =', href)
        u = query.get()
        if not u:
            u = PugPe(href=href)
            u.put()
            u.save_in_cache()
        return u

    @staticmethod
    def code_to_id(code):
        aid = 0L
        for c in code:
            aid *= PugPe.BASE
            aid += PugPe.KEY_BASE.index(c)
        return aid

    @staticmethod
    def find_by_code(code):
        try:
            u = memcache.get(code)
        except:
            # http://code.google.com/p/googleappengine/issues/detail?id=417
            logging.error("PugPe.find_by_code() memcached error")
            u = None

        if u is not None:
            logging.info("PugPe.find_by_code() cache HIT: %s", str(code))
            return u

        logging.info("PugPe.find_by_code() cache MISS: %s", str(code))
        aid = PugPe.code_to_id(code)
        try:
            u = PugPe.get_by_id(int(aid))
            if u is not None:
                u.save_in_cache()
            return u
        except db.BadValueError:
            return None
Beispiel #13
0
class Entity(db.Model):
    country = db.ReferenceProperty(Country, collection_name="country_entity")
    name = db.StringProperty()
    created = db.DateProperty()
    contact_info = db.StringProperty()
    myaiesec_link = db.LinkProperty()
    type = db.ReferenceProperty(EntityType,
                                collection_name="Entity_Entity_Type")

    @staticmethod
    def store_entities():
        '''        
        for et in EntityType.all():
            et.delete()
        for country in Country.all():
            country.delete()
        for entity in Entity.all():
            entity.delete()
        '''
        # create global and AI
        ai = EntityType(key_name="AI")
        ai.name = "AIESEC INTERNATIONAL"
        ai.level = 10
        ai.put()
        mc = EntityType(key_name="MC")
        mc.name = "MEMBER COMMITTEE"
        mc.level = 20
        mc.put()
        lc = EntityType(key_name="LC")
        lc.name = "LOCAL COMMITTEE"
        lc.level = 30
        lc.put()

        country = Country(key_name='GLOBAL')
        country.name = 'GLOBAL'
        country.put()
        entity = Entity(parent=country, key_name="AIESEC INTERNATIONAL")
        entity.country = country
        entity.name = "AIESEC INTERNATIONAL"
        entity.type = ai
        entity.put()
        for item in aiesec_list:
            country_entities = item.split("=")
            country = Country(key_name=country_entities[0],
                              name=country_entities[0])
            country.put()
            if len(country_entities) > 1:
                entity = Entity(parent=country,
                                key_name=mc.name + " " + country.name)
                entity.country = country
                entity.type = mc
                entity.name = country.name
                entity.put()
                entity_list = country_entities[1].split(";")
                for item in entity_list:
                    entity = Entity(country, item)
                    entity.name = item
                    entity.type = lc
                    entity.country = country
                    entity.put()

    def get_active_committee(self):
        return Committee.gql("WHERE parent = :entity_key",
                             entity_key=self.key()).get()

    def og_url(self):
        return "https://apps.facebook.com/iamanaiesecer/object_graph/entity/{0}/".format(
            self.key())

    def og_image(self):
        return "https://i-am-an-aiesecer.appspot.com/static/object_entity.jpg"
Beispiel #14
0
class GSoCProject(db.Model):
    """Model for a GSoC project used in the GSoC workflow.

  Parent:
    soc.modules.gsoc.models.profile.Profile
  """

    #: Required field indicating the "title" of the project
    title = db.StringProperty(required=True, verbose_name=ugettext('Title'))
    title.help_text = ugettext('Title of the project')

    #: Required, text field describing the project
    abstract = db.TextProperty(required=True,
                               verbose_name=ugettext('Project abstract'))
    abstract.help_text = ugettext(
        'Short abstract, summary, or snippet;'
        ' 500 characters or less, plain text displayed publicly')

    #: Text field containing all kinds of information about this project
    public_info = db.TextProperty(
        required=False,
        default='',
        verbose_name=ugettext('Additional information'))
    public_info.help_text = ugettext(
        'Additional information about this project to be shown publicly')

    #: Optional, URL which can give more information about this project
    additional_info = db.URLProperty(
        required=False, verbose_name=ugettext('External resource URL'))
    additional_info.help_text = ugettext(
        'Link to a resource containing more information about this project.')

    #: Optional field storing a feed URL; displayed publicly
    feed_url = db.LinkProperty(verbose_name=ugettext('Project Feed URL'))
    feed_url.help_text = ugettext(
        'The URL should be a valid ATOM or RSS feed. '
        'Feed entries are shown on the public page.')

    #: The project can be marked to be featured on program home page.
    is_featured = db.BooleanProperty(default=False,
                                     required=True,
                                     verbose_name=ugettext('Featured'))
    is_featured.help_text = ugettext(
        'Should this project be featured on the program homepage.')

    #: A property containing a list of Mentors assigned for this project
    mentors = db.ListProperty(item_type=db.Key, default=[], required=True)

    def getMentors(self):
        """Returns a list of profile_model.GSoCProfile entities which
    are mentors for this project.

    Returns:
      list of mentors for this project
    """
        mentor_ndb_keys = map(ndb.Key.from_old_key, self.mentors)
        return [mentor for mentor in ndb.get_multi(mentor_ndb_keys) if mentor]

    #: The status of this project
    status = db.StringProperty(required=True,
                               default=STATUS_ACCEPTED,
                               choices=[
                                   STATUS_ACCEPTED, STATUS_FAILED,
                                   STATUS_WITHDRAWN, STATUS_INVALID
                               ])

    #: List of all processed GradingRecords which state a pass for this project.
    #: This property can be used to determine how many evaluations someone has
    #: passed. And is also used to ensure that a GradingRecord has been
    #: processed.
    passed_evaluations = db.ListProperty(item_type=db.Key, default=[])

    #: List of all processed GradingRecords which state a fail for this project.
    #: This is a ListProperty to ensure that the system keeps functioning when
    #: manual changes in GradingRecords occur.
    failed_evaluations = db.ListProperty(item_type=db.Key, default=[])

    #: Organization which this project is in
    org = db.ReferenceProperty(
        reference_class=soc.models.organization.Organization,
        required=True,
        collection_name='student_projects')

    #: Program in which this project has been created
    program = db.ReferenceProperty(reference_class=soc.models.program.Program,
                                   required=True,
                                   collection_name='projects')

    #: Proposal to which this project corresponds to
    proposal = db.ReferenceProperty(
        reference_class=soc.modules.gsoc.models.proposal.GSoCProposal,
        required=False,
        collection_name='projects')

    #: Whether the student has submitted their code samples or not
    code_samples_submitted = db.BooleanProperty(default=False)

    def codeSamples(self):
        """Returns code_sample.GSoCCodeSample entities uploaded for this project.

    Returns:
      code sample entities for this project
    """
        query = code_sample_model.GSoCCodeSample.all()
        query.ancestor(self)
        return query.fetch(1000)

    def countCodeSamples(self):
        """Returns number of code_sample.GSoCCodeSample entities uploaded
    for this project.

    Returns:
      number of code samples uploaded for this project
    """
        query = code_sample_model.GSoCCodeSample.all(keys_only=True)
        query.ancestor(self)
        return query.count()
Beispiel #15
0
class Event(db.Model):
    title = db.StringProperty(required=True)
    start= db.DateTimeProperty(required=True)
    end=db.DateTimeProperty(required=True, indexed=True)
    location=db.PostalAddressProperty(required=False, indexed=False)
    link=db.LinkProperty(required=False, indexed=False)
    description=db.TextProperty()
    cost=db.TextProperty(required=False)
    submitted_by=db.ReferenceProperty(Profile,required=False, collection_name='events_submitted')
    submitted_at=db.DateTimeProperty(auto_now_add=True)
    site=db.ReferenceProperty(Eventsite, required=True)
    sort_dt=db.DateTimeProperty()
    status=db.StringProperty(required=True)
    score=db.IntegerProperty(indexed=False)
    approved_by=db.ReferenceProperty(Profile,indexed=False, collection_name="events_approved")
    approved_on=db.DateTimeProperty()
    tags=db.StringListProperty()
    credit_name=db.StringProperty(required=True, indexed=False)
    credit_link=db.LinkProperty(required=False, indexed=False)
    source=db.ReferenceProperty(required=False)
    last_seen=db.DateTimeProperty(required=False)
    source_uid=db.StringProperty(required=False)
    repeats_frequency=db.StringProperty(required=False)
    repeats_weekday=db.IntegerProperty(required=False)
    #repeats_setpos=db.IntegerProperty(required=False)
    repeats_monthday=db.IntegerProperty(required=False)

    def __unicode__(self):
        return "%s: %s" %(self.local_start.date().strftime("%a %b %d"), self.title)

    @DerivedProperty
    def local_start(self):
        if self.start.tzinfo == None:
            ls= utc.localize(self.start).astimezone(self.site.tz)
            return ls.replace(tzinfo=None)
        else:
            return self.start.astimezone(self.site.tz) + self.site.tz.utcoffset(self.site.tz)
    
    @DerivedProperty    
    def local_end(self):
        if self.end.tzinfo == None:
            ls= utc.localize(self.end).astimezone(self.site.tz)
            return ls.replace(tzinfo=None)
        else:
            return self.end.astimezone(self.site.tz) + self.site.tz.utcoffset(self.site.tz)
        
        
    @DerivedProperty
    def multiday(self):
         return ((self.local_start.date() < self.local_end.date()) and  (self.local_end -self.local_start) > timedelta(1))
        
    @DerivedProperty
    def allday(self):
        return ((self.local_start.time() == time(0) and self.local_end.time() == time(0)))
    
    @DerivedProperty
    def continues(self):
        if self.multiday:
            rule=rrule(DAILY, dtstart=self.local_start, until=self.local_end)
            return [str(dt.date()) for dt in list(rule)]
        else:
            return None
    
    
    @DerivedProperty
    def repeats_setpos(self):
        month_start=(self.local_start+relativedelta(day=1))
        weekday=(MO,TU,WE,TH,FR,SA,SU)[self.local_start.weekday()]
        tests=[(-1,month_start+relativedelta(day=31,weekday=weekday(-1))),
                (1,month_start+relativedelta(day=1,weekday=weekday(1))),
                (2,month_start+relativedelta(day=1,weekday=weekday(2))),
                (3,month_start+relativedelta(day=1,weekday=weekday(2))),]
        
        for pos, d in tests:
            logging.warning("comparing %s and %s" %(str(d),str(self.local_start.date()) ))
            if self.local_start.date()==d.date(): return pos
    
    
    @property
    def event_link(self):
        return self.link    
    
    @property
    def item_pubdate(self):
        return self.approved_on
    
    
    def copy(self, rule):
        copies=[]
        delta=self.end-self.start
        #search_after=utc.localize(datetime.now())
        logging.warning(rule)
        for dt in rule[1:6]:
            if not (dt.date() > self.local_start.date()): continue 
            logging.warning(dt)
            new_start=self.site.tz.localize(self.local_start.replace(tzinfo=None)).replace(dt.year,dt.month,dt.day)
            e=Event(parent=self,key_name=dt.strftime("%Y%m%j"),
            title = self.title,
            start= new_start,
            end=new_start+delta,
            location=self.location,
            link=self.link,
            description=self.description,
            cost=self.cost,
            site=self.site,
            sort_dt=self.sort_dt,
            status=self.status,
            tags=self.tags,
            credit_name=self.credit_name,
            credit_link=self.credit_link,
            last_seen=datetime.now()  
            )
            copies.append(e)
        return copies
    
    
    def check_scores(self):
        if (self.approved_on or (self.score > 2)):
            pass
    
    
    
    @classmethod
    def from_gdata(cls,gevent, source):
            #logging.warning(type(parser.parse(gevent.when[0].start_time)))
            dtstart=parser.parse(gevent.when[0].start_time)
            
            dtend=parser.parse(gevent.when[0].end_time)
            summary=gevent.title.text
            
            location= gevent.where[0].value_string or None
            link= source.source_link
            uid=gevent.id.text
            key_name=uid
            #first check for duplicate key name
            existing_event=Event.get_by_key_name(key_name)
            #fail-over to name and start

            if not existing_event:
                existing_event=source.event_set.filter('title = ', summary).filter('start = ',dtstart).get()


            logging.warning("searched for existing event with key %s, found %s" %(key_name,existing_event))
            if existing_event and source.trusted:
                        existing_event.title=summary or "Untitled Event"
                        existing_event.start=dtstart
                        existing_event.end=dtend
                        existing_event.last_seen=datetime.now()
                        if location:existing_event.location=location
                        if link: existing_event.link=link or source.source_link
                        existing_event.put()
                        return existing_event

            if existing_event and not source.trusted:
                return existing_event

            if source.trusted:
                    status='approved'
                    approved_on=datetime.now()
            else:
                    status='submitted'
                    approved_on=None
            event=Event(key_name=key_name,
                title=summary or "Untitled Event",
                start=dtstart,
                end=dtend,
                site=source.site,
                location=location,
                link=link,
                status=status,
                tags=source.default_tags,
                credit_name=source.name,
                credit_link=source.source_link,
                source=source,
                source_uid=uid,
                approved_on=approved_on,
                last_seen=datetime.now())
                #source_ical_hash=source_ical_hash)
            event.put()
            source.site.expire_assets()
            return event
            
            
    @classmethod
    def from_vcal(cls,vcal, source):
        def start_dt(dateobject):
            if type(dateobject) == datetime: 
                if hasattr (dateobject,'tzinfo') and dateobject.tzinfo:
                    return dateobject
                else:
                    return source.site.tz.localize(dateobject)
            if not dateobject: return None
            return source.site.tz.localize(datetime.combine(dateobject, time(0)))

        def end_dt(dateobject):
            if not dateobject: return None
            if type(dateobject) == datetime:
                    if hasattr (dateobject,'tzinfo') and dateobject.tzinfo:
                        return dateobject
                    else:
                        return source.site.tz.localize(dateobject)


            return source.site.tz.localize(datetime.combine(dateobject, time(0)))
        #logging.warning("hey!")
        parsedCal = vobject.readOne(vcal)
        vevent=parsedCal.vevent
        dtstart=start_dt(vevent.dtstart.value)
        if dtstart < utc.localize(datetime.today()) - timedelta(1):
            return logging.warning("skipping old event with dtstart %s" % dtstart)
        
        
        if (hasattr(vevent,'dtend') and vevent.dtend):
            dtend=(end_dt(vevent.dtend.value) or dtstart)
        else:
            dtend=dtstart
        summary=vevent.summary.value
        location= vevent.getChildValue('location') or None
        link=vevent.getChildValue('url') or source.source_link
        uid=vevent.uid.value or link or str(dtstart)
        key_name="%s-%s-%s"%(source.site.slug, source.slug,uid)
        #first check for duplicate key name
        existing_event=Event.get_by_key_name(key_name)
        #fail-over to name and start
        
        if not existing_event:
            existing_event=source.event_set.filter('title = ', summary).filter('start = ',dtstart).get()


        logging.warning("searched for existing event with key %s, found %s" %(key_name,existing_event))
        if existing_event and source.trusted:
                    existing_event.title=summary or "Untitled Event"
                    existing_event.start=dtstart
                    existing_event.end=dtend
                    existing_event.last_seen=datetime.now()
                    if location:existing_event.location=location
                    if link: existing_event.link=link or source.source_link
                    #existing_event.source_ical_hash=source_ical_hash
                    existing_event.put()
                    return existing_event
                    
        if existing_event and not source.trusted:
            return existing_event
                    
        if source.trusted:
                status='approved'
                approved_on=datetime.now()
        else:
                status='submitted'
                approved_on=None
        event=Event(key_name=key_name,
            title=summary or "Untitled Event",
            start=dtstart,
            end=dtend,
            site=source.site,
            location=location,
            link=link,
            status=status,
            tags=source.default_tags,
            credit_name=source.name,
            credit_link=source.source_link,
            source=source,
            source_uid=uid,
            approved_on=approved_on,
            last_seen=datetime.now())
            #source_ical_hash=source_ical_hash)
        event.put()
        source.site.expire_assets()
        return event

        @classmethod
        def for_site_week(cls,site,day):
            monday=day+relativedelta(weekday=MO(-1))
            sunday=monday+relativedelta(weekday=SU)
Beispiel #16
0
class Feature(DictModel):
  """Container for a feature."""

  DEFAULT_MEMCACHE_KEY = '%s|features' % (settings.MEMCACHE_KEY_PREFIX)

  def format_for_template(self):
    d = self.to_dict()
    d['id'] = self.key().id()
    d['category'] = FEATURE_CATEGORIES[self.category]
    d['visibility'] = VISIBILITY_CHOICES[self.visibility]
    d['impl_status_chrome'] = IMPLEMENTATION_STATUS[self.impl_status_chrome]
    d['meta'] = {
      'experimentalframework': self.impl_status_chrome == EXPERIMENTAL_FRAMEWORK,
      'needsflag': self.impl_status_chrome == BEHIND_A_FLAG,
      'milestone_str': self.shipped_milestone or d['impl_status_chrome']
      }
    d['ff_views'] = {'value': self.ff_views,
                     'text': VENDOR_VIEWS[self.ff_views]}
    d['ie_views'] = {'value': self.ie_views,
                     'text': VENDOR_VIEWS[self.ie_views]}
    d['safari_views'] = {'value': self.safari_views,
                         'text': VENDOR_VIEWS[self.safari_views]}
    d['standardization'] = {'value': self.standardization,
                            'text': STANDARDIZATION[self.standardization]}
    d['web_dev_views'] = {'value': self.web_dev_views,
                          'text': WEB_DEV_VIEWS[self.web_dev_views]}
    #d['owner'] = ', '.join(self.owner)
    return d

  def format_for_edit(self):
    d = self.to_dict()
    #d['id'] = self.key().id
    d['owner'] = ', '.join(self.owner)
    d['doc_links'] = '\r\n'.join(self.doc_links)
    d['sample_links'] = '\r\n'.join(self.sample_links)
    d['search_tags'] = ', '.join(self.search_tags)
    return d

  @classmethod
  def get_all(self, limit=None, order='-updated', filterby=None,
              update_cache=False):
    KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, order, limit)

    # TODO(ericbidelman): Support more than one filter.
    if filterby is not None:
      s = ('%s%s' % (filterby[0], filterby[1])).replace(' ', '')
      KEY += '|%s' % s

    feature_list = memcache.get(KEY)

    if feature_list is None or update_cache:
      query = Feature.all().order(order) #.order('name')

      # TODO(ericbidelman): Support more than one filter.
      if filterby:
        query.filter(filterby[0], filterby[1])

      features = query.fetch(limit)

      feature_list = [f.format_for_template() for f in features]

      memcache.set(KEY, feature_list)

    return feature_list

  @classmethod
  def get_all_with_statuses(self, statuses, update_cache=False):
    if not statuses:
      return []

    KEY = '%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, sorted(statuses))

    feature_list = memcache.get(KEY)

    if feature_list is None or update_cache:
      # There's no way to do an OR in a single datastore query, and there's a
      # very good chance that the self.get_all() results will already be in
      # memcache, so use an array comprehension to grab the features we
      # want from the array of everything.
      feature_list = [feature for feature in self.get_all(update_cache=update_cache)
                      if feature['impl_status_chrome'] in statuses]
      memcache.set(KEY, feature_list)

    return feature_list

  @classmethod
  def get_feature(self, feature_id, update_cache=False):
    KEY = '%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, feature_id)
    feature = memcache.get(KEY)

    if feature is None or update_cache:
      unformatted_feature = Feature.get_by_id(feature_id)
      if unformatted_feature:
        feature = unformatted_feature.format_for_template()
        feature['updated_display'] = unformatted_feature.updated.strftime("%Y-%m-%d")
        memcache.set(KEY, feature)

    return feature

  @classmethod
  def get_chronological(self, limit=None, update_cache=False):
    KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, 'cronorder', limit)

    feature_list = memcache.get(KEY)

    if feature_list is None or update_cache:
      q = Feature.all()
      q.order('-shipped_milestone')
      q.order('name')
      features = q.fetch(None)

      features = [f for f in features if (IN_DEVELOPMENT < f.impl_status_chrome < NO_LONGER_PURSUING)]

      # Append no active, in dev, proposed features.
      q = Feature.all()
      q.order('impl_status_chrome')
      q.order('name')
      q.filter('impl_status_chrome <=', IN_DEVELOPMENT)
      pre_release = q.fetch(None)
      pre_release.extend(features)

      # Append no longer pursuing features.
      q = Feature.all()
      q.order('impl_status_chrome')
      q.order('name')
      q.filter('impl_status_chrome =', NO_LONGER_PURSUING)
      no_longer_pursuing = q.fetch(None)
      pre_release.extend(no_longer_pursuing)

      feature_list = [f.format_for_template() for f in pre_release]

      memcache.set(KEY, feature_list)

    return feature_list

  @classmethod
  def get_shipping_samples(self, limit=None, update_cache=False):
    KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, 'samples', limit)

    feature_list = memcache.get(KEY)

    if feature_list is None or update_cache:
      # Get all shipping features. Ordered by shipping milestone (latest first).
      q = Feature.all()
      q.filter('impl_status_chrome IN', [ENABLED_BY_DEFAULT, EXPERIMENTAL_FRAMEWORK])
      q.order('-impl_status_chrome')
      q.order('-shipped_milestone')
      q.order('name')
      features = q.fetch(None)

      # Get non-shipping features (sans removed or deprecated ones) and
      # append to bottom of list.
      q = Feature.all()
      q.filter('impl_status_chrome <', ENABLED_BY_DEFAULT)
      q.order('-impl_status_chrome')
      q.order('-shipped_milestone')
      q.order('name')
      others = q.fetch(None)
      features.extend(others)

      # Filter out features without sample links.
      feature_list = [f.format_for_template() for f in features
                      if len(f.sample_links)]

      memcache.set(KEY, feature_list)

    return feature_list

  # Metadata.
  created = db.DateTimeProperty(auto_now_add=True)
  updated = db.DateTimeProperty(auto_now=True)
  updated_by = db.UserProperty(auto_current_user=True)
  created_by = db.UserProperty(auto_current_user_add=True)

  # General info.
  category = db.IntegerProperty(required=True)
  name = db.StringProperty(required=True)
  summary = db.StringProperty(required=True, multiline=True)

  # Chromium details.
  bug_url = db.LinkProperty()
  impl_status_chrome = db.IntegerProperty(required=True)
  shipped_milestone = db.IntegerProperty()
  shipped_android_milestone = db.IntegerProperty()
  shipped_ios_milestone = db.IntegerProperty()
  shipped_webview_milestone = db.IntegerProperty()
  shipped_opera_milestone = db.IntegerProperty()
  shipped_opera_android_milestone = db.IntegerProperty()

  owner = db.ListProperty(db.Email)
  footprint = db.IntegerProperty()
  visibility = db.IntegerProperty(required=True)

  #webbiness = db.IntegerProperty() # TODO: figure out what this is

  # Standards details.
  standardization = db.IntegerProperty(required=True)
  spec_link = db.LinkProperty()
  prefixed = db.BooleanProperty()

  ff_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
  ie_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
  safari_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)

  ff_views_link = db.LinkProperty()
  ie_views_link = db.LinkProperty()
  safari_views_link = db.LinkProperty()

  # Web dev details.
  web_dev_views = db.IntegerProperty(required=True)
  doc_links = db.StringListProperty()
  sample_links = db.StringListProperty()
  #tests = db.StringProperty()

  search_tags = db.StringListProperty()

  comments = db.StringProperty(multiline=True)
class User(db.Model):
    lowercase_nickname = db.StringProperty(required=True)
    nickname = db.StringProperty(required=True)
    password = db.StringProperty(required=True)
    created = db.DateTimeProperty(auto_now_add=True)
    about = db.TextProperty(required=False)
    hnuser = db.StringProperty(required=False, default="")
    github = db.StringProperty(required=False, default="")
    location = db.StringProperty(required=False, default="")
    twitter = db.StringProperty(required=False, default="")
    email = db.EmailProperty(required=False)
    url = db.LinkProperty(required=False)
    admin = db.BooleanProperty(default=False)
    karma = db.IntegerProperty(required=False)

    @staticmethod
    def slow_hash(password, iterations=1000):
        h = hashlib.sha1()
        h.update(password)
        h.update(keys.salt_key)
        for x in range(iterations):
            h.update(h.digest())
        return h.hexdigest()

    def average_karma(self):
        delta = (datetime.now() - self.created)
        days = delta.days
        votes = self.karma
        if votes is None:
            votes = 0
        if days > 0:
            return votes / float(days)
        else:
            return votes

    def sum_votes(self):
        val = memcache.get("u_" + str(self.key()))
        if val is not None:
            return val
        else:
            val = Vote.all().filter("user !=",
                                    self).filter("target_user ="******"u_" + str(self.key()), val, 3600)
            return val

    def remove_from_memcache(self):
        memcache.delete("u_" + str(self.key()))

    def has_notifications(self):
        count_notificationes = memcache.get("user_notification_" +
                                            str(self.key()))
        if count_notificationes is not None:
            return count_notificationes > 0
        else:
            count_notificationes = Notification.all().filter(
                "target_user ="******"read =", False).count()
            memcache.add("user_notification_" + str(self.key()),
                         count_notificationes, 3600)
            return count_notificationes > 0

    def remove_notifications_from_memcache(self):
        memcache.delete("user_notification_" + str(self.key()))
Beispiel #18
0
class ICalendarSource(db.Model):
    site = db.ReferenceProperty(Eventsite, required=True)
    name = db.StringProperty(required=True, indexed=False)
    source_link = db.LinkProperty(indexed=False, required=False)
    ical_href = db.LinkProperty(required=True, indexed=False)
    status = db.StringProperty(required=True)
    trusted = db.BooleanProperty()
    default_tags = db.StringListProperty()
    submitted_by = db.ReferenceProperty(Profile,
                                        required=False,
                                        collection_name='icals_submitted')
    submitted_at = db.DateTimeProperty(auto_now_add=True)
    approved_by = db.ReferenceProperty(Profile,
                                       indexed=False,
                                       collection_name="icals_approved")
    approved_on = db.DateTimeProperty(indexed=False)
    last_fetch = db.DateTimeProperty(required=False)
    content = db.TextProperty(required=False)
    is_rssfeed = db.BooleanProperty()

    @property
    def approval_form(self):
        return sources.forms.ICalApprovalForm(
            initial={
                'trusted': self.trusted,
                'tags': ','.join(self.default_tags)
            })

    @DerivedProperty
    def slug(self):
        return str(slugify(self.name))

    def fetch(self, started=None, timestamp=None):
        format_start = "%Y%m%d%H%M"
        if not started: started = str(datetime.now())
        if not timestamp: timestamp = datetime.now().strftime("%Y%m%d%H%M")

        if self.ical_href.startswith(
                'http://www.google.com/calendar/ical/'
        ) or self.ical_href.startswith(
                'https://www.google.com/calendar/ical/'):

            gcal_id = unquote(self.ical_href[36:].split('/')[0])
            query = gdata.calendar.service.CalendarEventQuery(
                gcal_id, 'public', 'full-noattendees')
            query.start_min = self.site.today.strftime("%Y-%m-%d")
            query.recurrence_expansion_end = (
                date.today() + relativedelta(months=3)).strftime("%Y-%m-%d")
            query.start_max = (date.today() +
                               relativedelta(months=3)).strftime("%Y-%m-%d")
            query.singleevents = 'true'
            result = urlfetch.fetch(query.ToUri(),
                                    allow_truncated=False,
                                    deadline=10)
            logging.warning("fetching %s" % result.content)
            if result.status_code == 200:
                detection = chardet.detect(result.content)
                self.last_fetch = datetime.now()
                self.content = result.content.decode(detection['encoding'])
                self.put()
                process_gdata(self)
                #cache_key="%s-%s-%s" %(self.site.slug, self.slug,timestamp)
                #memcache.add(cache_key, ,600)
                #logging.warning("cached gdata with key %s"% cache_key)
                #taskqueue.add(url='/sources/split_gdata/', params={'ical_key': self.key(),
                #                                                  'cache_key':cache_key,
                #                                                  'timestamp':timestamp},
                #                                                  name=cache_key
                #                                                  )
                #logging.warning("enqueued splitting of %s" % self.ical_href)
            return

        result = urlfetch.fetch(self.ical_href,
                                allow_truncated=False,
                                deadline=5)
        if result.status_code == 200:
            detection = chardet.detect(result.content)
            self.last_fetch = datetime.now()
            self.content = result.content.decode(detection['encoding'])
            self.put()
            process_ical(self)
class ChromiumTryTasks(BaseTelemetryModel):
  """Data model for Chromium Try tasks."""
  username = db.StringProperty(required=True)
  benchmark_name = db.StringProperty(required=True)
  benchmark_arguments = db.StringProperty()
  browser_args_1 = db.StringProperty()
  browser_args_2 = db.StringProperty()
  target_platform = db.StringProperty()
  pageset_type = db.StringProperty()
  skia_patch = db.BlobProperty()
  chromium_patch = db.BlobProperty()
  blink_patch = db.BlobProperty()
  num_repeated_runs = db.IntegerProperty()
  variance_threshold = db.FloatProperty(required=True)
  discard_outliers = db.FloatProperty(required=True)
  requested_time = db.DateTimeProperty(required=True)
  completed_time = db.DateTimeProperty()
  description = db.StringProperty()
  skia_patch_link = db.LinkProperty()
  chromium_patch_link = db.LinkProperty()
  blink_patch_link = db.LinkProperty()
  build_log_link = db.LinkProperty()
  telemetry_nopatch_log_link = db.LinkProperty()
  telemetry_withpatch_log_link = db.LinkProperty()
  html_output_link = db.LinkProperty()

  def get_json_repr(self):
    """Returns a JSON representation of this Data Model."""
    return {
        'ChromiumTryTask': {
            'key': self.key().id_or_name(),
            'username': self.username,
            'benchmark_name': self.benchmark_name,
            'benchmark_arguments': self.benchmark_arguments,
            'browser_args_1': self.browser_args_1,
            'browser_args_2': self.browser_args_2,
            'target_platform': self.target_platform,
            'pageset_type': self.pageset_type,
            'skia_patch': self.skia_patch,
            'chromium_patch': self.chromium_patch,
            'blink_patch': self.blink_patch,
            'num_repeated_runs': self.num_repeated_runs,
            'variance_threshold': self.variance_threshold,
            'discard_outliers': self.discard_outliers,
            'requested_time': str(self.requested_time)
        }
    }

  @classmethod
  def get_all_chromium_try_tasks(cls, offset):
    return (cls.all()
               .order('-requested_time')
               .fetch(offset=offset, limit=PAGINATION_LIMIT))

  @classmethod
  def get_all_chromium_try_tasks_of_user(cls, user):
    return (cls.all()
               .filter('username ='******'-requested_time')
               .fetch(limit=FETCH_LIMIT))

  @classmethod
  def get_chromium_try_task(cls, key):
    return db.GqlQuery(
        'SELECT * FROM ChromiumTryTasks WHERE __key__ = '
        'Key(\'ChromiumTryTasks\', %s);' % key)

  @classmethod
  def delete_chromium_try_task(cls, key):
    chromium_try_tasks = cls.get_chromium_try_task(key)
    if chromium_try_tasks.count():
      chromium_try_tasks[0].delete()
Beispiel #20
0
class Session(db.Expando):
    """An in-progress OpenID login."""
    claimed_id = db.StringProperty()
    server_url = db.LinkProperty()
Beispiel #21
0
class SubCategory(db.Model):
    name = db.StringProperty(required=True)
    image = db.LinkProperty()
    description = db.TextProperty()
    category = db.StringProperty()
    _id = db.IntegerProperty()
Beispiel #22
0
class StudentProject(soc.models.linkable.Linkable):
    """Model for a student project used in the GSoC workflow.
  """

    #: Required field indicating the "title" of the project
    title = db.StringProperty(required=True, verbose_name=ugettext('Title'))
    title.help_text = ugettext('Title of the project')

    #: Required, text field describing the project
    abstract = db.TextProperty(required=True)
    abstract.help_text = ugettext(
        'Short abstract, summary, or snippet;'
        ' 500 characters or less, plain text displayed publicly')

    #: Optional, text field containing all kinds of information about this project
    public_info = db.TextProperty(required=False, default='')
    public_info.help_text = ugettext(
        'Additional information about this project to be shown publicly')

    #: Optional, URL which can give more information about this project
    additional_info = db.URLProperty(required=False)
    additional_info.help_text = ugettext(
        'Link to a resource containing more information about this project.')

    #: Optional field storing a feed URL; displayed publicly
    feed_url = db.LinkProperty(verbose_name=ugettext('Project Feed URL'))
    feed_url.help_text = ugettext(
        'The URL should be a valid ATOM or RSS feed. '
        'Feed entries are shown on the public page.')

    #: A property containing which mentor has been assigned to this project.
    #: A project must have a mentor at all times.
    mentor = db.ReferenceProperty(reference_class=soc.models.mentor.Mentor,
                                  required=True,
                                  collection_name='student_projects')

    #: A property containing a list of additional Mentors for this project
    additional_mentors = db.ListProperty(item_type=db.Key, default=[])

    #: The status of this project
    #: accepted: This project has been accepted into the program
    #: failed: This project has failed an evaluation.
    #: completed: This project has completed the program successfully. This
    #:            should be set automatically when a program has been deemed
    #:            finished.
    #: withdrawn: This project has been withdrawn from the program by a Program
    #:            Administrator or higher.
    #: invalid: This project has been marked as invalid because it was deleted
    status = db.StringProperty(
        required=True,
        default='accepted',
        choices=['accepted', 'failed', 'completed', 'withdrawn', 'invalid'])

    #: List of all processed GradingRecords which state a pass for this project.
    #: This property can be used to determine how many evaluations someone has
    #: passed. And is also used to ensure that a GradingRecord has been
    #: processed.
    passed_evaluations = db.ListProperty(item_type=db.Key, default=[])

    #: List of all processed GradingRecords which state a fail for this project.
    #: This is a ListProperty to ensure that the system keeps functioning when
    #: manual changes in GradingRecords occur.
    failed_evaluations = db.ListProperty(item_type=db.Key, default=[])

    #: Student which this project is from
    student = db.ReferenceProperty(reference_class=soc.models.student.Student,
                                   required=True,
                                   collection_name='student_projects')

    #: Program in which this project has been created
    program = db.ReferenceProperty(reference_class=soc.models.program.Program,
                                   required=True,
                                   collection_name='student_projects')
Beispiel #23
0
class SplitLunch(db.Model):
    name = db.LinkProperty()
class Feature(DictModel):
    """Container for a feature."""

    DEFAULT_MEMCACHE_KEY = '%s|features' % (settings.MEMCACHE_KEY_PREFIX)

    def format_for_template(self):
        d = self.to_dict()
        d['id'] = self.key().id()
        d['category'] = FEATURE_CATEGORIES[self.category]
        d['visibility'] = VISIBILITY_CHOICES[self.visibility]
        d['impl_status_chrome'] = IMPLEMENATION_STATUS[self.impl_status_chrome]
        d['meta'] = {
            'needsflag': self.impl_status_chrome == BEHIND_A_FLAG,
            'milestone_str': self.shipped_milestone or d['impl_status_chrome']
        }
        d['ff_views'] = {
            'value': self.ff_views,
            'text': VENDOR_VIEWS[self.ff_views]
        }
        d['ie_views'] = {
            'value': self.ie_views,
            'text': VENDOR_VIEWS[self.ie_views]
        }
        d['safari_views'] = {
            'value': self.safari_views,
            'text': VENDOR_VIEWS[self.safari_views]
        }
        d['standardization'] = {
            'value': self.standardization,
            'text': STANDARDIZATION[self.standardization]
        }
        d['web_dev_views'] = {
            'value': self.web_dev_views,
            'text': WEB_DEV_VIEWS[self.web_dev_views]
        }
        #d['owner'] = ', '.join(self.owner)
        return d

    def format_for_edit(self):
        d = self.to_dict()
        #d['id'] = self.key().id
        d['owner'] = ', '.join(self.owner)
        d['doc_links'] = ', '.join(self.doc_links)
        d['sample_links'] = ', '.join(self.sample_links)
        return d

    @classmethod
    def get_all(self,
                limit=None,
                order='-updated',
                filterby=None,
                update_cache=False):
        KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, order, limit)

        # TODO(ericbidelman): Support more than one filter.
        if filterby is not None:
            s = ('%s%s' % (filterby[0], filterby[1])).replace(' ', '')
            KEY += '|%s' % s

        feature_list = memcache.get(KEY)

        if feature_list is None or update_cache:
            query = Feature.all().order(order)  #.order('name')

            # TODO(ericbidelman): Support more than one filter.
            if filterby:
                query.filter(filterby[0], filterby[1])

            features = query.fetch(limit)

            feature_list = [f.format_for_template() for f in features]

            memcache.set(KEY, feature_list)

        return feature_list

    @classmethod
    def get_chronological(limit=None, update_cache=False):
        KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, 'cronorder', limit)

        feature_list = memcache.get(KEY)

        if feature_list is None or update_cache:
            q = Feature.all()
            q.order('-shipped_milestone')
            q.order('name')
            features = q.fetch(None)

            features = [
                f for f in features
                if (IN_DEVELOPMENT < f.impl_status_chrome < NO_LONGER_PURSUING)
            ]

            # Get no active, in dev, proposed features.
            q = Feature.all()
            q.order('impl_status_chrome')
            q.order('name')
            q.filter('impl_status_chrome <=', IN_DEVELOPMENT)
            pre_release = q.fetch(None)

            pre_release.extend(features)

            # Get no longer pursuing features.
            q = Feature.all()
            q.order('impl_status_chrome')
            q.order('name')
            q.filter('impl_status_chrome =', NO_LONGER_PURSUING)
            no_longer_pursuing = q.fetch(None)

            pre_release.extend(no_longer_pursuing)

            feature_list = [f.format_for_template() for f in pre_release]

            memcache.set(KEY, feature_list)

        return feature_list

    # Metadata.
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    updated_by = db.UserProperty(auto_current_user=True)
    created_by = db.UserProperty(auto_current_user_add=True)

    # General info.
    category = db.IntegerProperty(required=True)
    name = db.StringProperty(required=True)
    summary = db.StringProperty(required=True, multiline=True)

    # Chromium details.
    bug_url = db.LinkProperty()
    impl_status_chrome = db.IntegerProperty(required=True)
    shipped_milestone = db.IntegerProperty()
    shipped_android_milestone = db.IntegerProperty()
    shipped_ios_milestone = db.IntegerProperty()
    shipped_webview_milestone = db.IntegerProperty()
    shipped_opera_milestone = db.IntegerProperty()
    shipped_opera_android_milestone = db.IntegerProperty()

    owner = db.ListProperty(db.Email)
    footprint = db.IntegerProperty()
    visibility = db.IntegerProperty(required=True)

    #webbiness = db.IntegerProperty() # TODO: figure out what this is

    # Standards details.
    standardization = db.IntegerProperty(required=True)
    spec_link = db.LinkProperty()
    prefixed = db.BooleanProperty()

    ff_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
    ie_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
    safari_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)

    ff_views_link = db.LinkProperty()
    ie_views_link = db.LinkProperty()
    safari_views_link = db.LinkProperty()

    # Web dev details.
    web_dev_views = db.IntegerProperty(required=True)
    doc_links = db.StringListProperty()
    sample_links = db.StringListProperty()
    #tests = db.StringProperty()

    comments = db.StringProperty(multiline=True)
Beispiel #25
0
class CrawlUrl(db.Model):
    url = db.LinkProperty()
    lastseen = db.DateTimeProperty(auto_now_add=True)
    headers = db.TextProperty()
class Feature(DictModel):
    """Container for a feature."""

    DEFAULT_MEMCACHE_KEY = '%s|features' % (settings.MEMCACHE_KEY_PREFIX)

    def format_for_template(self, version=None):
        d = self.to_dict()

        if version == 2:
            d['id'] = self.key().id()
            d['category'] = FEATURE_CATEGORIES[self.category]
            d['created'] = {
                'by': d.pop('created', None),
                'when': d.pop('created_by', None),
            }
            d['updated'] = {
                'by': d.pop('updated', None),
                'when': d.pop('updated_by', None),
            }
            d['standards'] = {
                'spec': d.pop('spec_link', None),
                'status': {
                    'text': STANDARDIZATION[self.standardization],
                    'val': d.pop('standardization', None),
                },
                'visibility': {
                    'text': VISIBILITY_CHOICES[self.visibility],
                    'val': d.pop('visibility', None),
                },
                'footprint': {
                    'val': d.pop('footprint', None),
                    #'text': FOOTPRINT_CHOICES[self.footprint]
                }
            }
            d['resources'] = {
                'samples': d.pop('sample_links', []),
                'docs': d.pop('doc_links', []),
            }
            d['tags'] = d.pop('search_tags', [])
            d['browsers'] = {
                'chrome': {
                    'bug': d.pop('bug_url', None),
                    'crbug_component': d.pop('bug_component', None),
                    'owners': d.pop('owner', []),
                    'origintrial': self.impl_status_chrome == ORIGIN_TRIAL,
                    'intervention': self.impl_status_chrome == INTERVENTION,
                    'prefixed': d.pop('prefixed', False),
                    'flag': self.impl_status_chrome == BEHIND_A_FLAG,
                    'status': {
                        'text': IMPLEMENTATION_STATUS[self.impl_status_chrome],
                        'val': d.pop('impl_status_chrome', None)
                    },
                    'desktop': d.pop('shipped_milestone', None),
                    'android': d.pop('shipped_android_milestone', None),
                    'webview': d.pop('shipped_webview_milestone', None),
                    'ios': d.pop('shipped_ios_milestone', None),
                },
                'opera': {
                    'desktop': d.pop('shipped_opera_milestone', None),
                    'android': d.pop('shipped_opera_android_milestone', None),
                },
                'ff': {
                    'view': {
                        'text': VENDOR_VIEWS[self.ff_views],
                        'val': d.pop('ff_views', None),
                        'url': d.pop('ff_views_link', None),
                    }
                },
                'edge': {
                    'view': {
                        'text': VENDOR_VIEWS[self.ie_views],
                        'val': d.pop('ie_views', None),
                        'url': d.pop('ie_views_link', None),
                    }
                },
                'safari': {
                    'view': {
                        'text': VENDOR_VIEWS[self.safari_views],
                        'val': d.pop('safari_views', None),
                        'url': d.pop('safari_views_link', None),
                    }
                },
                'webdev': {
                    'view': {
                        'text': WEB_DEV_VIEWS[self.web_dev_views],
                        'val': d.pop('web_dev_views', None),
                    }
                }
            }

            if self.shipped_milestone:
                d['browsers']['chrome']['status'][
                    'milestone_str'] = self.shipped_milestone
            elif self.shipped_milestone is None and self.shipped_android_milestone:
                d['browsers']['chrome']['status'][
                    'milestone_str'] = self.shipped_android_milestone
            else:
                d['browsers']['chrome']['status']['milestone_str'] = d[
                    'browsers']['chrome']['status']['text']

            del d['created']
            del d['updated']

            del_none(d)  # Further prune response by removing null/[] values.

        else:
            d['id'] = self.key().id()
            d['category'] = FEATURE_CATEGORIES[self.category]
            d['visibility'] = VISIBILITY_CHOICES[self.visibility]
            d['impl_status_chrome'] = IMPLEMENTATION_STATUS[
                self.impl_status_chrome]
            d['meta'] = {
                'origintrial': self.impl_status_chrome == ORIGIN_TRIAL,
                'intervention': self.impl_status_chrome == INTERVENTION,
                'needsflag': self.impl_status_chrome == BEHIND_A_FLAG,
            }
            if self.shipped_milestone:
                d['meta']['milestone_str'] = self.shipped_milestone
            elif self.shipped_milestone is None and self.shipped_android_milestone:
                d['meta']['milestone_str'] = self.shipped_android_milestone
            else:
                d['meta']['milestone_str'] = d['impl_status_chrome']
            d['ff_views'] = {
                'value': self.ff_views,
                'text': VENDOR_VIEWS[self.ff_views]
            }
            d['ie_views'] = {
                'value': self.ie_views,
                'text': VENDOR_VIEWS[self.ie_views]
            }
            d['safari_views'] = {
                'value': self.safari_views,
                'text': VENDOR_VIEWS[self.safari_views]
            }
            d['standardization'] = {
                'value': self.standardization,
                'text': STANDARDIZATION[self.standardization]
            }
            d['web_dev_views'] = {
                'value': self.web_dev_views,
                'text': WEB_DEV_VIEWS[self.web_dev_views]
            }

        return d

    def format_for_edit(self):
        d = self.to_dict()
        #d['id'] = self.key().id
        d['owner'] = ', '.join(self.owner)
        d['doc_links'] = '\r\n'.join(self.doc_links)
        d['sample_links'] = '\r\n'.join(self.sample_links)
        d['search_tags'] = ', '.join(self.search_tags)
        return d

    @classmethod
    def get_all(self,
                limit=None,
                order='-updated',
                filterby=None,
                update_cache=False):
        KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, order, limit)

        # TODO(ericbidelman): Support more than one filter.
        if filterby is not None:
            s = ('%s%s' % (filterby[0], filterby[1])).replace(' ', '')
            KEY += '|%s' % s

        feature_list = memcache.get(KEY)

        if feature_list is None or update_cache:
            query = Feature.all().order(order)  #.order('name')

            # TODO(ericbidelman): Support more than one filter.
            if filterby:
                query.filter(filterby[0], filterby[1])

            features = query.fetch(limit)

            feature_list = [f.format_for_template() for f in features]

            memcache.set(KEY, feature_list)

        return feature_list

    @classmethod
    def get_all_with_statuses(self, statuses, update_cache=False):
        if not statuses:
            return []

        KEY = '%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, sorted(statuses))

        feature_list = memcache.get(KEY)

        if feature_list is None or update_cache:
            # There's no way to do an OR in a single datastore query, and there's a
            # very good chance that the self.get_all() results will already be in
            # memcache, so use an array comprehension to grab the features we
            # want from the array of everything.
            feature_list = [
                feature for feature in self.get_all(update_cache=update_cache)
                if feature['impl_status_chrome'] in statuses
            ]
            memcache.set(KEY, feature_list)

        return feature_list

    @classmethod
    def get_feature(self, feature_id, update_cache=False):
        KEY = '%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, feature_id)
        feature = memcache.get(KEY)

        if feature is None or update_cache:
            unformatted_feature = Feature.get_by_id(feature_id)
            if unformatted_feature:
                feature = unformatted_feature.format_for_template()
                feature[
                    'updated_display'] = unformatted_feature.updated.strftime(
                        "%Y-%m-%d")
                feature['new_crbug_url'] = unformatted_feature.new_crbug_url()
                memcache.set(KEY, feature)

        return feature

    @classmethod
    def get_chronological(self, limit=None, update_cache=False, version=None):
        KEY = '%s|%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, 'cronorder',
                               limit, version)

        feature_list = memcache.get(KEY)

        if feature_list is None or update_cache:

            # Features with no active, in dev, proposed features.
            q = Feature.all()
            q.order('impl_status_chrome')
            q.order('name')
            q.filter('impl_status_chrome <=', IN_DEVELOPMENT)
            pre_release = q.fetch(None)

            # Shipping features. Exclude features that do not have a desktop
            # shipping milestone.
            q = Feature.all()
            q.order('-shipped_milestone')
            q.order('name')
            q.filter('shipped_milestone !=', None)
            shipping_features = q.fetch(None)

            # Features with an android shipping milestone but no desktop milestone.
            q = Feature.all()
            q.order('-shipped_android_milestone')
            q.order('name')
            q.filter('shipped_milestone =', None)
            android_only_shipping_features = q.fetch(None)

            # No longer pursuing features.
            q = Feature.all()
            q.order('impl_status_chrome')
            q.order('name')
            q.filter('impl_status_chrome =', NO_LONGER_PURSUING)
            no_longer_pursuing_features = q.fetch(None)

            shipping_features.extend(android_only_shipping_features)

            shipping_features = [
                f for f in shipping_features
                if (IN_DEVELOPMENT < f.impl_status_chrome < NO_LONGER_PURSUING)
            ]

            def getSortingMilestone(feature):
                feature._sort_by_milestone = (
                    feature.shipped_milestone
                    or feature.shipped_android_milestone)
                return feature

            # Sort the feature list on either Android shipping milestone or desktop
            # shipping milestone, depending on which is specified. If a desktop
            # milestone is defined, that will take default.
            shipping_features = map(getSortingMilestone, shipping_features)

            # First sort by name, then sort by feature milestone (latest first).
            shipping_features.sort(key=lambda f: f.name, reverse=False)
            shipping_features.sort(key=lambda f: f._sort_by_milestone,
                                   reverse=True)

            # Constructor the proper ordering.
            pre_release.extend(shipping_features)
            pre_release.extend(no_longer_pursuing_features)

            feature_list = [
                f.format_for_template(version) for f in pre_release
            ]

            memcache.set(KEY, feature_list)

        return feature_list

    @classmethod
    def get_shipping_samples(self, limit=None, update_cache=False):
        KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, 'samples', limit)

        feature_list = memcache.get(KEY)

        if feature_list is None or update_cache:
            # Get all shipping features. Ordered by shipping milestone (latest first).
            q = Feature.all()
            q.filter('impl_status_chrome IN',
                     [ENABLED_BY_DEFAULT, ORIGIN_TRIAL, INTERVENTION])
            q.order('-impl_status_chrome')
            q.order('-shipped_milestone')
            q.order('name')
            features = q.fetch(None)

            # Get non-shipping features (sans removed or deprecated ones) and
            # append to bottom of list.
            q = Feature.all()
            q.filter('impl_status_chrome <', ENABLED_BY_DEFAULT)
            q.order('-impl_status_chrome')
            q.order('-shipped_milestone')
            q.order('name')
            others = q.fetch(None)
            features.extend(others)

            # Filter out features without sample links.
            feature_list = [
                f.format_for_template() for f in features
                if len(f.sample_links)
            ]

            memcache.set(KEY, feature_list)

        return feature_list

    def crbug_number(self):
        if not self.bug_url:
            return
        m = re.search(r'[\/|?id=]([0-9]+)$', self.bug_url)
        if m:
            return m.group(1)

    def new_crbug_url(self):
        url = 'https://bugs.chromium.org/p/chromium/issues/entry'
        params = ['components=' + self.bug_component or DEFAULT_BUG_COMPONENT]
        crbug_number = self.crbug_number()
        if crbug_number and self.impl_status_chrome in (
                NO_ACTIVE_DEV, PROPOSED, IN_DEVELOPMENT, BEHIND_A_FLAG,
                ORIGIN_TRIAL, INTERVENTION):
            params.append('blocking=' + crbug_number)
        if self.owner:
            params.append('cc=' + ','.join(self.owner))
        return url + '?' + '&'.join(params)

    # Metadata.
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    updated_by = db.UserProperty(auto_current_user=True)
    created_by = db.UserProperty(auto_current_user_add=True)

    # General info.
    category = db.IntegerProperty(required=True)
    name = db.StringProperty(required=True)
    summary = db.StringProperty(required=True, multiline=True)

    # Chromium details.
    bug_url = db.LinkProperty()
    bug_component = db.StringProperty(required=False,
                                      default=DEFAULT_BUG_COMPONENT)
    impl_status_chrome = db.IntegerProperty(required=True)
    shipped_milestone = db.IntegerProperty()
    shipped_android_milestone = db.IntegerProperty()
    shipped_ios_milestone = db.IntegerProperty()
    shipped_webview_milestone = db.IntegerProperty()
    shipped_opera_milestone = db.IntegerProperty()
    shipped_opera_android_milestone = db.IntegerProperty()

    owner = db.ListProperty(db.Email)
    footprint = db.IntegerProperty()
    visibility = db.IntegerProperty(required=True)

    #webbiness = db.IntegerProperty() # TODO: figure out what this is

    # Standards details.
    standardization = db.IntegerProperty(required=True)
    spec_link = db.LinkProperty()
    prefixed = db.BooleanProperty()

    ff_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
    ie_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
    safari_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)

    ff_views_link = db.LinkProperty()
    ie_views_link = db.LinkProperty()
    safari_views_link = db.LinkProperty()

    # Web dev details.
    web_dev_views = db.IntegerProperty(required=True)
    doc_links = db.StringListProperty()
    sample_links = db.StringListProperty()
    #tests = db.StringProperty()

    search_tags = db.StringListProperty()

    comments = db.StringProperty(multiline=True)
Beispiel #27
0
class Feature(DictModel):
  """Container for a feature."""

  DEFAULT_MEMCACHE_KEY = '%s|features' % (settings.MEMCACHE_KEY_PREFIX)
  MAX_CHUNK_SIZE = 500 # max num features to save for each memcache chunk.

  @classmethod
  def get_feature_chunk_memcache_keys(self, key_prefix):
    num_features = len(Feature.all().fetch(limit=None, keys_only=True))
    l = list_to_chunks(range(0, num_features), self.MAX_CHUNK_SIZE)
    return ['%s|chunk%s' % (key_prefix, i) for i,val in enumerate(l)]

  @classmethod
  def set_feature_chunk_memcache_keys(self, key_prefix, feature_list):
    chunks = list_to_chunks(feature_list, self.MAX_CHUNK_SIZE)
    vals = []
    for i, chunk in enumerate(chunks):
      vals.append(('%s|chunk%s' % (key_prefix, i), chunk))
    # d = OrderedDict(sorted(dict(vals).items(), key=lambda t: t[0]))
    d = dict(vals)
    return d

  @classmethod
  def _first_of_milestone(self, feature_list, milestone, start=0):
    for i in xrange(start, len(feature_list)):
      f = feature_list[i]
      if (str(f['shipped_milestone']) == str(milestone) or
          f['impl_status_chrome'] == str(milestone)):
        return i
      elif (f['shipped_milestone'] == None and
            str(f['shipped_android_milestone']) == str(milestone)):
        return i

    return -1

  @classmethod
  def _first_of_milestone_v2(self, feature_list, milestone, start=0):
    for i in xrange(start, len(feature_list)):
      f = feature_list[i]
      desktop_milestone = f['browsers']['chrome'].get('desktop', None)
      android_milestone = f['browsers']['chrome'].get('android', None)
      status = f['browsers']['chrome']['status'].get('text', None)

      if (str(desktop_milestone) == str(milestone) or status == str(milestone)):
        return i
      elif (desktop_milestone == None and str(android_milestone) == str(milestone)):
        return i

    return -1

  @classmethod
  def _annotate_first_of_milestones(self, feature_list, version=None):
    try:
      omaha_data = util.get_omaha_data()

      win_versions = omaha_data[0]['versions']

      # Find the latest canary major version from the list of windows versions.
      canary_versions = [x for x in win_versions if x.get('channel') and x.get('channel').startswith('canary')]
      LATEST_VERSION = int(canary_versions[0].get('version').split('.')[0])

      milestones = range(1, LATEST_VERSION + 1)
      milestones.reverse()
      versions = [
        IMPLEMENTATION_STATUS[NO_ACTIVE_DEV],
        IMPLEMENTATION_STATUS[PROPOSED],
        IMPLEMENTATION_STATUS[IN_DEVELOPMENT],
        ]
      versions.extend(milestones)
      versions.append(IMPLEMENTATION_STATUS[NO_LONGER_PURSUING])

      first_of_milestone_func = Feature._first_of_milestone
      if version == 2:
        first_of_milestone_func = Feature._first_of_milestone_v2

      last_good_idx = 0
      for i, ver in enumerate(versions):
        idx = first_of_milestone_func(feature_list, ver, start=last_good_idx)
        if idx != -1:
          feature_list[idx]['first_of_milestone'] = True
          last_good_idx = idx
    except Exception as e:
      logging.error(e)

  def format_for_template(self, version=None):
    d = self.to_dict()

    if version == 2:
      if self.is_saved():
        d['id'] = self.key().id()
      else:
        d['id'] = None
      d['category'] = FEATURE_CATEGORIES[self.category]
      if self.intent_stage is not None:
        d['intent_stage'] = INTENT_STAGES[self.intent_stage]
      d['created'] = {
        'by': d.pop('created_by', None),
        'when': d.pop('created', None),
      }
      d['updated'] = {
        'by': d.pop('updated_by', None),
        'when': d.pop('updated', None),
      }
      d['standards'] = {
        'spec': d.pop('spec_link', None),
        'status': {
          'text': STANDARDIZATION[self.standardization],
          'val': d.pop('standardization', None),
        },
        'visibility': {
          'text': VISIBILITY_CHOICES[self.visibility],
          'val': d.pop('visibility', None),
        },
        'footprint': {
          'val': d.pop('footprint', None),
          #'text': FOOTPRINT_CHOICES[self.footprint]
        }
      }
      d['resources'] = {
        'samples': d.pop('sample_links', []),
        'docs': d.pop('doc_links', []),
      }
      d['tags'] = d.pop('search_tags', [])
      d['browsers'] = {
        'chrome': {
          'bug': d.pop('bug_url', None),
          'blink_components': d.pop('blink_components', []),
          'owners': d.pop('owner', []),
          'origintrial': self.impl_status_chrome == ORIGIN_TRIAL,
          'intervention': self.impl_status_chrome == INTERVENTION,
          'prefixed': d.pop('prefixed', False),
          'flag': self.impl_status_chrome == BEHIND_A_FLAG,
          'status': {
            'text': IMPLEMENTATION_STATUS[self.impl_status_chrome],
            'val': d.pop('impl_status_chrome', None)
          },
          'desktop': d.pop('shipped_milestone', None),
          'android': d.pop('shipped_android_milestone', None),
          'webview': d.pop('shipped_webview_milestone', None),
          'ios': d.pop('shipped_ios_milestone', None),
        },
        'ff': {
          'view': {
            'text': VENDOR_VIEWS[self.ff_views],
            'val': d.pop('ff_views', None),
            'url': d.pop('ff_views_link', None),
            'notes': d.pop('ff_views_notes', None),
          }
        },
        'edge': {
          'view': {
            'text': VENDOR_VIEWS[self.ie_views],
            'val': d.pop('ie_views', None),
            'url': d.pop('ie_views_link', None),
            'notes': d.pop('ie_views_notes', None),
          }
        },
        'safari': {
          'view': {
            'text': VENDOR_VIEWS[self.safari_views],
            'val': d.pop('safari_views', None),
            'url': d.pop('safari_views_link', None),
            'notes': d.pop('safari_views_notes', None),
          }
        },
        'webdev': {
          'view': {
            'text': WEB_DEV_VIEWS[self.web_dev_views],
            'val': d.pop('web_dev_views', None),
            'url': d.pop('web_dev_views_link', None),
            'notes': d.pop('web_dev_views_notes', None),
          }
        }
      }

      if self.shipped_milestone:
        d['browsers']['chrome']['status']['milestone_str'] = self.shipped_milestone
      elif self.shipped_milestone is None and self.shipped_android_milestone:
        d['browsers']['chrome']['status']['milestone_str'] = self.shipped_android_milestone
      else:
        d['browsers']['chrome']['status']['milestone_str'] = d['browsers']['chrome']['status']['text']

      del d['created']

      del_none(d) # Further prune response by removing null/[] values.

    else:
      if self.is_saved():
        d['id'] = self.key().id()
      else:
        d['id'] = None
      d['category'] = FEATURE_CATEGORIES[self.category]
      if self.intent_stage is not None:
        d['intent_stage'] = INTENT_STAGES[self.intent_stage]
      d['visibility'] = VISIBILITY_CHOICES[self.visibility]
      d['impl_status_chrome'] = IMPLEMENTATION_STATUS[self.impl_status_chrome]
      d['meta'] = {
        'origintrial': self.impl_status_chrome == ORIGIN_TRIAL,
        'intervention': self.impl_status_chrome == INTERVENTION,
        'needsflag': self.impl_status_chrome == BEHIND_A_FLAG,
        }
      if self.shipped_milestone:
        d['meta']['milestone_str'] = self.shipped_milestone
      elif self.shipped_milestone is None and self.shipped_android_milestone:
        d['meta']['milestone_str'] = self.shipped_android_milestone
      else:
        d['meta']['milestone_str'] = d['impl_status_chrome']
      d['ff_views'] = {'value': self.ff_views,
                       'text': VENDOR_VIEWS[self.ff_views]}
      d['ie_views'] = {'value': self.ie_views,
                       'text': VENDOR_VIEWS[self.ie_views]}
      d['safari_views'] = {'value': self.safari_views,
                           'text': VENDOR_VIEWS[self.safari_views]}
      d['standardization'] = {'value': self.standardization,
                              'text': STANDARDIZATION[self.standardization]}
      d['web_dev_views'] = {'value': self.web_dev_views,
                            'text': WEB_DEV_VIEWS[self.web_dev_views]}

    return d

  def format_for_edit(self):
    d = self.to_dict()
    #d['id'] = self.key().id
    d['owner'] = ', '.join(self.owner)
    d['explainer_links'] = '\r\n'.join(self.explainer_links)
    d['doc_links'] = '\r\n'.join(self.doc_links)
    d['sample_links'] = '\r\n'.join(self.sample_links)
    d['search_tags'] = ', '.join(self.search_tags)
    d['blink_components'] = self.blink_components[0] #TODO: support more than one component.
    return d

  @classmethod
  def get_all(self, limit=None, order='-updated', filterby=None,
              update_cache=False):
    KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, order, limit)

    # TODO(ericbidelman): Support more than one filter.
    if filterby is not None:
      s = ('%s%s' % (filterby[0], filterby[1])).replace(' ', '')
      KEY += '|%s' % s

    feature_list = memcache.get(KEY)

    if feature_list is None or update_cache:
      query = Feature.all().order(order) #.order('name')

      # TODO(ericbidelman): Support more than one filter.
      if filterby:
        query.filter(filterby[0], filterby[1])

      features = query.fetch(limit)

      feature_list = [f.format_for_template() for f in features]

      memcache.set(KEY, feature_list)

    return feature_list

  @classmethod
  def get_all_with_statuses(self, statuses, update_cache=False):
    if not statuses:
      return []

    KEY = '%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, sorted(statuses))

    feature_list = memcache.get(KEY)

    if feature_list is None or update_cache:
      # There's no way to do an OR in a single datastore query, and there's a
      # very good chance that the self.get_all() results will already be in
      # memcache, so use an array comprehension to grab the features we
      # want from the array of everything.
      feature_list = [feature for feature in self.get_all(update_cache=update_cache)
                      if feature['impl_status_chrome'] in statuses]
      memcache.set(KEY, feature_list)

    return feature_list

  @classmethod
  def get_feature(self, feature_id, update_cache=False):
    KEY = '%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, feature_id)
    feature = memcache.get(KEY)

    if feature is None or update_cache:
      unformatted_feature = Feature.get_by_id(feature_id)
      if unformatted_feature:
        feature = unformatted_feature.format_for_template()
        feature['updated_display'] = unformatted_feature.updated.strftime("%Y-%m-%d")
        feature['new_crbug_url'] = unformatted_feature.new_crbug_url()
        memcache.set(KEY, feature)

    return feature

  @classmethod
  def get_chronological(self, limit=None, update_cache=False, version=None):
    KEY = '%s|%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY,
                           'cronorder', limit, version)

    keys = Feature.get_feature_chunk_memcache_keys(KEY)
    feature_list = memcache.get_multi(keys)

    # If we didn't get the expected number of chunks back (or a cache update
    # was requested), do a db query.
    if len(feature_list.keys()) != len(keys) or update_cache:
      # Features with no active, in dev, proposed features.
      q = Feature.all()
      q.order('impl_status_chrome')
      q.order('name')
      q.filter('impl_status_chrome <=', IN_DEVELOPMENT)
      pre_release = q.fetch(None)

      # Shipping features. Exclude features that do not have a desktop
      # shipping milestone.
      q = Feature.all()
      q.order('-shipped_milestone')
      q.order('name')
      q.filter('shipped_milestone !=', None)
      shipping_features = q.fetch(None)

      # Features with an android shipping milestone but no desktop milestone.
      q = Feature.all()
      q.order('-shipped_android_milestone')
      q.order('name')
      q.filter('shipped_milestone =', None)
      android_only_shipping_features = q.fetch(None)

      # No longer pursuing features.
      q = Feature.all()
      q.order('impl_status_chrome')
      q.order('name')
      q.filter('impl_status_chrome =', NO_LONGER_PURSUING)
      no_longer_pursuing_features = q.fetch(None)

      shipping_features.extend(android_only_shipping_features)

      shipping_features = [f for f in shipping_features if (IN_DEVELOPMENT < f.impl_status_chrome < NO_LONGER_PURSUING)]

      def getSortingMilestone(feature):
        feature._sort_by_milestone = (feature.shipped_milestone or
                                      feature.shipped_android_milestone)
        return feature

      # Sort the feature list on either Android shipping milestone or desktop
      # shipping milestone, depending on which is specified. If a desktop
      # milestone is defined, that will take default.
      shipping_features = map(getSortingMilestone, shipping_features)

      # First sort by name, then sort by feature milestone (latest first).
      shipping_features.sort(key=lambda f: f.name, reverse=False)
      shipping_features.sort(key=lambda f: f._sort_by_milestone, reverse=True)

      # Constructor the proper ordering.
      pre_release.extend(shipping_features)
      pre_release.extend(no_longer_pursuing_features)

      feature_list = [f.format_for_template(version) for f in pre_release]

      self._annotate_first_of_milestones(feature_list, version=version)

      # Memcache doesn't support saving values > 1MB. Break up features list into
      # chunks so we don't hit the limit.
      memcache.set_multi(Feature.set_feature_chunk_memcache_keys(KEY, feature_list))
    else:
      temp_feature_list = []
      # Reconstruct feature list by ordering chunks.
      for key in sorted(feature_list.keys()):
        temp_feature_list.extend(feature_list[key])
      feature_list = temp_feature_list

    return feature_list

  @classmethod
  def get_shipping_samples(self, limit=None, update_cache=False):
    KEY = '%s|%s|%s' % (Feature.DEFAULT_MEMCACHE_KEY, 'samples', limit)

    feature_list = memcache.get(KEY)

    if feature_list is None or update_cache:
      # Get all shipping features. Ordered by shipping milestone (latest first).
      q = Feature.all()
      q.filter('impl_status_chrome IN', [ENABLED_BY_DEFAULT, ORIGIN_TRIAL, INTERVENTION])
      q.order('-impl_status_chrome')
      q.order('-shipped_milestone')
      q.order('name')
      features = q.fetch(None)

      # Get non-shipping features (sans removed or deprecated ones) and
      # append to bottom of list.
      q = Feature.all()
      q.filter('impl_status_chrome <', ENABLED_BY_DEFAULT)
      q.order('-impl_status_chrome')
      q.order('-shipped_milestone')
      q.order('name')
      others = q.fetch(None)
      features.extend(others)

      # Filter out features without sample links.
      feature_list = [f.format_for_template() for f in features
                      if len(f.sample_links)]

      memcache.set(KEY, feature_list)

    return feature_list

  def crbug_number(self):
    if not self.bug_url:
      return
    m = re.search(r'[\/|?id=]([0-9]+)$', self.bug_url)
    if m:
      return m.group(1)

  def new_crbug_url(self):
    url = 'https://bugs.chromium.org/p/chromium/issues/entry'
    params = ['components=' + self.blink_components[0] or BlinkComponent.DEFAULT_COMPONENT]
    crbug_number = self.crbug_number()
    if crbug_number and self.impl_status_chrome in (
        NO_ACTIVE_DEV,
        PROPOSED,
        IN_DEVELOPMENT,
        BEHIND_A_FLAG,
        ORIGIN_TRIAL,
        INTERVENTION):
      params.append('blocking=' + crbug_number)
    if self.owner:
      params.append('cc=' + ','.join(self.owner))
    return url + '?' + '&'.join(params)

  def __init__(self, *args, **kwargs):
    super(Feature, self).__init__(*args, **kwargs)

    # Stash existing values when entity is created so we can diff property
    # values later in put() to know what's changed. https://stackoverflow.com/a/41344898
    for prop_name, prop in self.properties().iteritems():
      old_val = getattr(self, prop_name, None)
      setattr(self, '_old_' + prop_name, old_val)

  def __notify_feature_subscribers_of_changes(self, is_update):
    """Async notifies subscribers of new features and property changes to features by
       posting to a task queue."""
    # Diff values to see what properties have changed.
    changed_props = []
    for prop_name, prop in self.properties().iteritems():
      new_val = getattr(self, prop_name, None)
      old_val = getattr(self, '_old_' + prop_name, None)
      if new_val != old_val:
        changed_props.append({
            'prop_name': prop_name, 'old_val': old_val, 'new_val': new_val})

    payload = json.dumps({
      'changes': changed_props,
      'is_update': is_update,
      'feature': self.format_for_template(version=2)
    })

    # Create task to email subscribers.
    queue = taskqueue.Queue()#name='emailer')
    task = taskqueue.Task(method="POST", url='/tasks/email-subscribers',
        target='notifier', payload=payload)
    queue.add(task)

    # Create task to send push notifications
    queue = taskqueue.Queue()
    task = taskqueue.Task(method="POST", url='/tasks/send_notifications',
        target='notifier', payload=payload)
    queue.add(task)


  def put(self, **kwargs):
    is_update = self.is_saved()
    key = super(Feature, self).put(**kwargs)
    self.__notify_feature_subscribers_of_changes(is_update)
    return key

  # Metadata.
  created = db.DateTimeProperty(auto_now_add=True)
  updated = db.DateTimeProperty(auto_now=True)
  updated_by = db.UserProperty(auto_current_user=True)
  created_by = db.UserProperty(auto_current_user_add=True)

  intent_template_use_count = db.IntegerProperty(default = 0)

  # General info.
  category = db.IntegerProperty(required=True)
  name = db.StringProperty(required=True)
  intent_stage = db.IntegerProperty(default=0)
  summary = db.StringProperty(required=True, multiline=True)
  intent_to_implement_url = db.LinkProperty()
  origin_trial_feedback_url = db.LinkProperty()

  # A list of intent threads in the format "date|subject|url"
  intent_threads = db.StringListProperty()
  motivation = db.StringProperty(multiline=True)

  # Chromium details.
  bug_url = db.LinkProperty()
  blink_components = db.StringListProperty(required=True, default=[BlinkComponent.DEFAULT_COMPONENT])

  impl_status_chrome = db.IntegerProperty(required=True)
  shipped_milestone = db.IntegerProperty()
  shipped_android_milestone = db.IntegerProperty()
  shipped_ios_milestone = db.IntegerProperty()
  shipped_webview_milestone = db.IntegerProperty()

  owner = db.ListProperty(db.Email)
  footprint = db.IntegerProperty()
  interop_compat_risks = db.StringProperty(multiline=True)
  ergonomics_risks = db.StringProperty(multiline=True)
  activation_risks = db.StringProperty(multiline=True)
  security_risks = db.StringProperty(multiline=True)
  debuggability = db.StringProperty(multiline=True)
  all_platforms = db.BooleanProperty()
  all_platforms_descr = db.StringProperty(multiline=True)
  wpt = db.BooleanProperty()
  wpt_descr = db.StringProperty(multiline=True)

  visibility = db.IntegerProperty(required=True)

  #webbiness = db.IntegerProperty() # TODO: figure out what this is

  # Standards details.
  standardization = db.IntegerProperty(required=True)
  spec_link = db.LinkProperty()
  tag_review = db.StringProperty(multiline=True)
  prefixed = db.BooleanProperty()

  explainer_links = db.StringListProperty()

  ff_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
  ie_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
  safari_views = db.IntegerProperty(required=True, default=NO_PUBLIC_SIGNALS)
  web_dev_views = db.IntegerProperty(required=True)

  ff_views_link = db.LinkProperty()
  ie_views_link = db.LinkProperty()
  safari_views_link = db.LinkProperty()
  web_dev_views_link = db.LinkProperty()

  ff_views_notes = db.StringProperty(multiline=True)
  ie_views_notes = db.StringProperty(multiline=True)
  safari_views_notes = db.StringProperty(multiline=True)
  web_dev_views_notes = db.StringProperty(multiline=True)

  doc_links = db.StringListProperty()
  sample_links = db.StringListProperty()
  #tests = db.StringProperty()

  search_tags = db.StringListProperty()

  comments = db.StringProperty(multiline=True)

  experiment_goals = db.StringProperty(multiline=True)
  experiment_timeline = db.StringProperty(multiline=True)
  experiment_risks = db.StringProperty(multiline=True)
  experiment_extension_reason = db.StringProperty(multiline=True)
  ongoing_constraints = db.StringProperty(multiline=True)
Beispiel #28
0
class Student(soc.models.role.Role):
  """Student details for a specific Program.
  """

  school_name = db.StringProperty(required=True, 
      verbose_name=ugettext('School Name'))
  school_name.group = ugettext("5. Education")
  school_name.help_text = ugettext(
      'Please enter the full name of your school, college or university in'
      ' this field. Please use the complete formal name of your school, e.g.'
      ' UC Berkeley instead of Cal or UCB. It would be most wonderful if you'
      ' could provide your school\'s name in English, as all the program '
      'administrators speak English as their first language and it will make'
      ' it much easier for us to assemble program statistics, etc., later if'
      ' we can easily read the name of your school.')

  school_country = db.StringProperty(required=True,
      verbose_name=ugettext('School Country/Territory'),
      choices=countries.COUNTRIES_AND_TERRITORIES)
  school_country.group = ugettext("5. Education")

  #: School home page URL, not required here but enforced in the form for
  #: backwards compatibility.
  school_home_page = db.LinkProperty(
      required=False, verbose_name=ugettext("School Home Page URL"))
  school_home_page.group = ugettext("5. Education")

  #: School type can be only High school for GCI and can be University
  #: for GSoC.
  school_type = db.StringProperty(required=False,
                                  verbose_name=ugettext('School Type'),
                                  choices=['University', 'High School'])
  school_type.group = ugettext("5. Education")

  major = db.StringProperty(required=False,
      verbose_name=ugettext('Major Subject'))
  major.group = ugettext("5. Education")

  degree = db.StringProperty(required=False,
      verbose_name=ugettext('Degree'),
      choices=['Undergraduate', 'Master', 'PhD'])
  degree.group = ugettext("5. Education")

  expected_graduation = db.IntegerProperty(required=True,
      verbose_name=ugettext('Expected Graduation Year'))
  expected_graduation.help_text = ugettext("Pick your expected graduation year")
  expected_graduation.group = ugettext("5. Education")

  #: A many:1 relationship that ties multiple Students to the
  #: School that they attend.
  school = db.ReferenceProperty(reference_class=soc.models.school.School,
                                required=False, collection_name='the_students')

  can_we_contact_you = db.BooleanProperty(verbose_name=ugettext(
      'Can we contact you?'))
  can_we_contact_you.help_text = ugettext(
      'Please check here if you would not mind being contacted by the Program'
      ' Administrators for follow up with members of the press who would like'
      ' to interview you about the program. You will not be contacted unless '
      ' you successfully complete your project. <br />'
      '<b>Please note that checking this  box has no effect on your chances'
      ' of being accepted into the program</b>.')
  can_we_contact_you.group = ugettext("2. Contact Info (Private)")
Beispiel #29
0
class Link(db.Model):
    name = db.StringProperty()
    href = db.LinkProperty()
    status = db.StringProperty()
Beispiel #30
0
class Dbevent(db.Model):
    """豆瓣同城事件数据模型"""

    id = db.IntegerProperty(required=True)
    title = db.StringProperty(required=True)
    self_link = db.StringProperty(required=True)
    image_link = db.LinkProperty() #TODO 活动照片
    alternate_link = db.StringProperty(required=True) #TODO 关联对象
    category = db.StringProperty(required=True)
    summary = db.TextProperty(required=True)
    content = db.TextProperty() #TODO 是否必填
    invite_only = db.BooleanProperty() #需要邀请才能参加
    can_invite = db.BooleanProperty() #允许参加者邀请其友邻来参加
    participants = db.IntegerProperty() #参与人数
    wishers = db.IntegerProperty() #想参加的人
    album = db.StringProperty() #TODO 这个属性干嘛的?
    status = db.StringProperty() #TODO 
    location_id = db.StringProperty(required=True) #城市id/拼音
    location_name = db.StringProperty(required=True) #城市/名称
    start_time = db.DateTimeProperty()
    end_time = db.DateTimeProperty(required=True)
    length = db.IntegerProperty(required=True)
    where = db.StringProperty() #地点
    geo_point = db.StringProperty() #坐标
    create_at = db.DateTimeProperty(required=True) # 时间戳

    @staticmethod
    def getDbevents(location_id, category, length=None):
        """
        从数据库查询 Dbevents
        """

        query = db.Query(Dbevent)
        query.filter('location_id =', location_id) #地点
        if category != 'all': #类别
            query.filter('category =', 'event.' + category)
        if isinstance(length, int) and length > 0: #活动长度
            query.filter('length <=', length)

        dbevents = query.fetch(limit=1000)
        if len(dbevents) == 0:
            db.put(SyncQueue(key_name=location_id, location_id=location_id))
        return dbevents

    def parse_event(self):
        """转换豆瓣数据模型到iCal数据模型"""
        event = Event()
        event.add('summary', self.title)
        desc = self.summary
        if isinstance(self.participants, int):
            desc += '\n\n' + u'参与人数 %d, 感兴趣人数 %d' \
                    %(self.participants, self.wishers)
        desc += '\n\n' + self.alternate_link
        event.add('DESCRIPTION', desc)
        #event.add('dtstart', self.start_time)
        event['dtstart'] = datetime.strftime(
            get_utc_datetime(self.start_time),
            '%Y%m%dT%H%M%SZ'
            )
        #event.add('dtend', self.end_time)
        event['dtend'] = datetime.strftime(
            get_utc_datetime(self.end_time),
            '%Y%m%dT%H%M%SZ'
            )
        event.add('STATUS', 'CONFIRMED')
        location = self.where
        if self.geo_point != None:
            location += u' @(%s)' %self.geo_point
        event.add('location', location)
        #event.add('dtstamp', datetime.now())
        event['dtstamp'] = datetime.strftime(self.create_at, '%Y%m%dT%H%M%SZ')
        event['uid'] = self.id
        return event

    def isMoreThenAWeek(self):
        """活动距今时间是否大于一周了"""
        delta = datetime.utcnow() - get_utc_datetime(self.end_time)
        return delta.days > 7

    @staticmethod
    def updateDb(location_id):
        """更新日历中活动"""
        dbevents = []
        start = 1
        max = config['sync']['max']
        fetch_page_count = config['sync']['fetch_page_count']

        # 当出现类型筛选时候
        while len(dbevents) < max:
            try:
                xml = fetchEvent(location_id,
                                 max=fetch_page_count,
                                 start=start)
            except GetDoubanDataError, e1:
                logging.error(u'获取数据超时了,先存一些')
                break
            except OverQuotaError, e2:
                logging.error(u'url fetch 中断,限额了')
                break
            dbevents_new = Dbevent.xml2dbevents(xml)
            dbevents += dbevents_new
            if len(dbevents_new) < fetch_page_count: # 到最后一页了
                break
            start += fetch_page_count