Пример #1
0
class Gesture(ndb.Model):
    name = ndb.TextProperty()
    raw_data = ndb.TextProperty()
Пример #2
0
class UserMessage(ndb.Model):
    real_fb_uid = ndb.StringProperty()
    creation_time = ndb.DateTimeProperty()
    message = ndb.TextProperty(indexed=False)
Пример #3
0
class Greeting(ndb.Model):
    author = ndb.UserProperty()
    content = ndb.TextProperty()
    date = ndb.DateTimeProperty(auto_now_add=True)
Пример #4
0
class FeedbackThreadModel(base_models.BaseModel):
    """Threads for each exploration.

    The id/key of instances of this class has the form
        [EXPLORATION_ID].[THREAD_ID]
    """
    # ID of the exploration the thread is about.
    exploration_id = ndb.StringProperty(required=True, indexed=True)
    # ID of state the thread is for. Does not exist if the thread is about the
    # entire exploration.
    state_name = ndb.StringProperty(indexed=True)
    # ID of the user who started the thread. This may be None if the feedback
    # was given anonymously by a learner.
    original_author_id = ndb.StringProperty(indexed=True)
    # Latest status of the thread.
    status = ndb.StringProperty(
        default=STATUS_CHOICES_OPEN,
        choices=STATUS_CHOICES,
        required=True,
        indexed=True,
    )
    # Latest subject of the thread.
    subject = ndb.StringProperty(indexed=False)
    # Summary text of the thread.
    summary = ndb.TextProperty(indexed=False)

    @classmethod
    def generate_new_thread_id(cls, exploration_id):
        """Generates a new thread id, unique within the exploration.

        Exploration ID + the generated thread ID is globally unique.
        """
        MAX_RETRIES = 10
        RAND_RANGE = 127 * 127
        for i in range(MAX_RETRIES):
            thread_id = (
                utils.base64_from_int(utils.get_current_time_in_millisecs()) +
                utils.base64_from_int(utils.get_random_int(RAND_RANGE)))
            if not cls.get_by_exp_and_thread_id(exploration_id, thread_id):
                return thread_id
        raise Exception(
            'New thread id generator is producing too many collisions.')

    @classmethod
    def _generate_id(cls, exploration_id, thread_id):
        return '.'.join([exploration_id, thread_id])

    @classmethod
    def create(cls, exploration_id, thread_id):
        """Creates a new FeedbackThreadModel entry.

        Throws an exception if a thread with the given exploration ID and
        thread ID combination exists already.
        """
        instance_id = cls._generate_id(exploration_id, thread_id)
        if cls.get_by_id(instance_id):
            raise Exception('Feedback thread ID conflict on create.')
        return cls(id=instance_id)

    @classmethod
    def get_by_exp_and_thread_id(cls, exploration_id, thread_id):
        """Gets the FeedbackThreadModel entry for the given ID.

        Returns None if the thread is not found or is already deleted.
        """
        return cls.get_by_id(cls._generate_id(exploration_id, thread_id))

    @classmethod
    def get(cls, instance_id):
        """Gets the FeedbackThreadModel entry for the given ID.

        Returns None if the thread is not found or is already deleted.
        """
        return super(FeedbackThreadModel, cls).get(instance_id, strict=False)

    @classmethod
    def get_threads(cls, exploration_id):
        """Returns an array of threads associated to the exploration.

        Does not include the deleted entries.
        """
        return cls.get_all().filter(
            cls.exploration_id == exploration_id).fetch(QUERY_LIMIT)
Пример #5
0
class ExpSummaryModel(base_models.BaseModel):
    """Summary model for an Oppia exploration.

    This should be used whenever the content blob of the exploration is not
    needed (e.g. gallery, search, etc).

    A ExpSummaryModel instance stores the following information:

        id, title, category, objective, language_code, tags,
        last_updated, created_on, status (private, public or
        publicized), community_owned, owner_ids, editor_ids,
        viewer_ids, version.

    The key of each instance is the exploration id.
    """

    # What this exploration is called.
    title = ndb.StringProperty(required=True)
    # The category this exploration belongs to.
    category = ndb.StringProperty(required=True, indexed=True)
    # The objective of this exploration.
    objective = ndb.TextProperty(required=True, indexed=False)
    # The ISO 639-1 code for the language this exploration is written in.
    language_code = ndb.StringProperty(required=True, indexed=True)
    # Tags associated with this exploration.
    tags = ndb.StringProperty(repeated=True, indexed=True)

    # Aggregate user-assigned ratings of the exploration
    ratings = ndb.JsonProperty(default=None, indexed=False)

    # Time when the exploration model was last updated (not to be
    # confused with last_updated, which is the time when the
    # exploration *summary* model was last updated)
    exploration_model_last_updated = ndb.DateTimeProperty(indexed=True)
    # Time when the exploration model was created (not to be confused
    # with created_on, which is the time when the exploration *summary*
    # model was created)
    exploration_model_created_on = ndb.DateTimeProperty(indexed=True)

    # The publication status of this exploration.
    status = ndb.StringProperty(default=EXPLORATION_STATUS_PRIVATE,
                                indexed=True,
                                choices=[
                                    EXPLORATION_STATUS_PRIVATE,
                                    EXPLORATION_STATUS_PUBLIC,
                                    EXPLORATION_STATUS_PUBLICIZED
                                ])

    # Whether this exploration is owned by the community.
    community_owned = ndb.BooleanProperty(required=True, indexed=True)

    # The user_ids of owners of this exploration.
    owner_ids = ndb.StringProperty(indexed=True, repeated=True)
    # The user_ids of users who are allowed to edit this exploration.
    editor_ids = ndb.StringProperty(indexed=True, repeated=True)
    # The user_ids of users who are allowed to view this exploration.
    viewer_ids = ndb.StringProperty(indexed=True, repeated=True)
    # The version number of the exploration after this commit. Only populated
    # for commits to an exploration (as opposed to its rights, etc.)
    version = ndb.IntegerProperty()

    @classmethod
    def get_non_private(cls):
        """Returns an iterable with non-private exp summary models."""
        return ExpSummaryModel.query().filter(
            ExpSummaryModel.status != EXPLORATION_STATUS_PRIVATE).filter(
                ExpSummaryModel.deleted == False).fetch(
                    feconf.DEFAULT_QUERY_LIMIT)

    @classmethod
    def get_private_at_least_viewable(cls, user_id):
        """Returns an iterable with private exp summaries that are at least
        viewable by the given user.
        """
        return ExpSummaryModel.query().filter(
            ExpSummaryModel.status == EXPLORATION_STATUS_PRIVATE).filter(
                ndb.OR(ExpSummaryModel.owner_ids == user_id,
                       ExpSummaryModel.editor_ids == user_id,
                       ExpSummaryModel.viewer_ids == user_id)).filter(
                           ExpSummaryModel.deleted == False).fetch(
                               feconf.DEFAULT_QUERY_LIMIT)

    @classmethod
    def get_at_least_editable(cls, user_id):
        """Returns an iterable with exp summaries that are at least
        editable by the given user.
        """
        return ExpSummaryModel.query().filter(
            ndb.OR(ExpSummaryModel.owner_ids == user_id,
                   ExpSummaryModel.editor_ids == user_id)).filter(
                       ExpSummaryModel.deleted == False).fetch(
                           feconf.DEFAULT_QUERY_LIMIT)
Пример #6
0
class Action(ndb.Model):
    nickname = ndb.StringProperty()
    type = ndb.IntegerProperty()
    payload = ndb.StringProperty()
    description = ndb.TextProperty()
Пример #7
0
class Event(ndb.Model):
    """
    Events represent FIRST Robotics Competition events, both official and unofficial.
    key_name is like '2010ct'
    """
    name = ndb.StringProperty()
    event_type_enum = ndb.IntegerProperty(required=True)
    short_name = ndb.StringProperty(
        indexed=False
    )  # Should not contain "Regional" or "Division", like "Hartford"
    event_short = ndb.StringProperty(
        required=True, indexed=False)  # Smaller abbreviation like "CT"
    year = ndb.IntegerProperty(required=True)
    event_district_enum = ndb.IntegerProperty(default=DistrictType.NO_DISTRICT)
    start_date = ndb.DateTimeProperty()
    end_date = ndb.DateTimeProperty()
    venue = ndb.StringProperty(indexed=False)  # Name of the event venue
    venue_address = ndb.StringProperty(
        indexed=False
    )  # Most detailed venue address (includes venue, street, and location separated by \n)
    city = ndb.StringProperty()  # Equivalent to locality. From FRCAPI
    state_prov = ndb.StringProperty()  # Equivalent to region. From FRCAPI
    country = ndb.StringProperty()  # From FRCAPI
    postalcode = ndb.StringProperty(
    )  # From ElasticSearch only. String because it can be like "95126-1215"
    timezone_id = ndb.StringProperty(
    )  # such as 'America/Los_Angeles' or 'Asia/Jerusalem'
    official = ndb.BooleanProperty(
        default=False)  # Is the event FIRST-official?
    first_eid = ndb.StringProperty()  # from USFIRST
    facebook_eid = ndb.StringProperty(indexed=False)  # from Facebook
    custom_hashtag = ndb.StringProperty(indexed=False)  # Custom HashTag
    website = ndb.StringProperty(indexed=False)
    webcast_json = ndb.TextProperty(
        indexed=False
    )  # list of dicts, valid keys include 'type' and 'channel'

    created = ndb.DateTimeProperty(auto_now_add=True, indexed=False)
    updated = ndb.DateTimeProperty(auto_now=True, indexed=False)

    def __init__(self, *args, **kw):
        # store set of affected references referenced keys for cache clearing
        # keys must be model properties
        self._affected_references = {
            'key': set(),
            'year': set(),
            'event_district_abbrev': set(),
            'event_district_key': set()
        }
        self._awards = None
        self._details = None
        self._location = None
        self._matches = None
        self._teams = None
        self._venue_address_safe = None
        self._webcast = None
        self._updated_attrs = [
        ]  # Used in EventManipulator to track what changed
        self._rankings_enhanced = None
        self._week = None
        super(Event, self).__init__(*args, **kw)

    @ndb.tasklet
    def get_awards_async(self):
        from database import award_query
        self._awards = yield award_query.EventAwardsQuery(
            self.key_name).fetch_async()

    @property
    def alliance_selections(self):
        if self.details is None:
            return None
        else:
            return self.details.alliance_selections

    @property
    def alliance_teams(self):
        """
        Load a list of team keys playing in elims
        """
        alliances = self.alliance_selections
        if alliances is None:
            return []
        teams = []
        for alliance in alliances:
            for pick in alliance['picks']:
                teams.append(pick)
        return teams

    @property
    def awards(self):
        if self._awards is None:
            self.get_awards_async().wait()
        return self._awards

    @property
    def details(self):
        if self._details is None:
            self._details = EventDetails.get_by_id(self.key.id())
        elif type(self._details) == Future:
            self._details = self._details.get_result()
        return self._details

    def prep_details(self):
        if self._details is None:
            self._details = ndb.Key(EventDetails, self.key.id()).get_async()

    @property
    def district_points(self):
        if self.details is None:
            return None
        else:
            return self.details.district_points

    @ndb.tasklet
    def get_matches_async(self):
        from database import match_query
        self._matches = yield match_query.EventMatchesQuery(
            self.key_name).fetch_async()

    @property
    def matches(self):
        if self._matches is None:
            if self._matches is None:
                self.get_matches_async().wait()
        return self._matches

    def local_time(self):
        now = datetime.datetime.now()
        if self.timezone_id is not None:
            tz = pytz.timezone(self.timezone_id)
            try:
                now = now + tz.utcoffset(now)
            except pytz.NonExistentTimeError:  # may happen during DST
                now = now + tz.utcoffset(now + datetime.timedelta(
                    hours=1))  # add offset to get out of non-existant time
        return now

    def withinDays(self, negative_days_before, days_after):
        if not self.start_date or not self.end_date:
            return False
        now = self.local_time()
        after_start = self.start_date.date() + datetime.timedelta(
            days=negative_days_before) <= now.date()
        before_end = self.end_date.date() + datetime.timedelta(
            days=days_after) >= now.date()

        return (after_start and before_end)

    @property
    def now(self):
        if self.timezone_id is not None:
            return self.withinDays(0, 0)
        else:
            return self.within_a_day  # overestimate what is "now" if no timezone

    @property
    def within_a_day(self):
        return self.withinDays(-1, 1)

    @property
    def past(self):
        return self.end_date.date() < datetime.date.today(
        ) and not self.within_a_day

    @property
    def future(self):
        return self.start_date.date() > datetime.date.today(
        ) and not self.within_a_day

    @property
    def starts_today(self):
        return self.start_date.date() == self.local_time().date()

    @property
    def ends_today(self):
        return self.end_date.date() == self.local_time().date()

    @property
    def week(self):
        """
        Returns the week of the event relative to the first official season event as an integer
        Returns None if the event is not of type NON_CMP_EVENT_TYPES or is not official
        """
        if self.event_type_enum not in EventType.NON_CMP_EVENT_TYPES or not self.official:
            return None

        # Cache week_start for the same context
        cache_key = '{}_week_start:{}'.format(self.year,
                                              ndb.get_context().__hash__())
        week_start = context_cache.get(cache_key)
        if week_start is None:
            e = Event.query(
                Event.year == self.year,
                Event.event_type_enum.IN(EventType.NON_CMP_EVENT_TYPES),
                Event.start_date != None).order(Event.start_date).fetch(
                    1, projection=[Event.start_date])
            if e:
                first_start_date = e[0].start_date
                diff_from_wed = (first_start_date.weekday() -
                                 2) % 7  # 2 is Wednesday
                week_start = first_start_date - datetime.timedelta(
                    days=diff_from_wed)
            else:
                week_start = None
        context_cache.set(cache_key, week_start)

        if self._week is None and week_start is not None:
            days = (self.start_date - week_start).days
            self._week = days / 7

        return self._week

    @property
    def is_season_event(self):
        return self.event_type_enum in EventType.SEASON_EVENT_TYPES

    @ndb.tasklet
    def get_teams_async(self):
        from database import team_query
        self._teams = yield team_query.EventTeamsQuery(
            self.key_name).fetch_async()

    @property
    def teams(self):
        if self._teams is None:
            self.get_teams_async().wait()
        return self._teams

    @ndb.toplevel
    def prepAwardsMatchesTeams(self):
        yield self.get_awards_async(), self.get_matches_async(
        ), self.get_teams_async()

    @ndb.toplevel
    def prepTeams(self):
        yield self.get_teams_async()

    @ndb.toplevel
    def prepTeamsMatches(self):
        yield self.get_matches_async(), self.get_teams_async()

    @property
    def matchstats(self):
        if self.details is None:
            return None
        else:
            return self.details.matchstats

    @property
    def rankings(self):
        if self.details is None:
            return None
        else:
            return self.details.rankings

    @property
    def rankings_enhanced(self):
        valid_years = RankingIndexes.CUMULATIVE_RANKING_YEARS
        rankings = self.rankings
        if rankings is not None and self.year in valid_years and self.official:
            self._rankings_enhanced = {
                "ranking_score_per_match": {},
                "match_offset": None,
            }
            team_index = RankingIndexes.TEAM_NUMBER
            rp_index = RankingIndexes.CUMULATIVE_RANKING_SCORE[self.year]
            matches_played_index = RankingIndexes.MATCHES_PLAYED[self.year]

            max_matches = 0
            if self.within_a_day:
                max_matches = max(
                    [int(el[matches_played_index]) for el in rankings[1:]])
                self._rankings_enhanced["match_offset"] = {}

            for ranking in rankings[1:]:
                team_number = ranking[team_index]
                ranking_score = float(ranking[rp_index])
                matches_played = int(ranking[matches_played_index])
                if matches_played == 0:
                    ranking_score_per_match = 0
                else:
                    ranking_score_per_match = round(
                        ranking_score / matches_played, 2)
                self._rankings_enhanced["ranking_score_per_match"][
                    team_number] = ranking_score_per_match
                if self.within_a_day:
                    self._rankings_enhanced["match_offset"][
                        team_number] = matches_played - max_matches
        else:
            self._rankings_enhanced = None
        return self._rankings_enhanced

    def get_lat_lon(self):
        return LocationHelper.get_event_lat_lon(self)

    @property
    def location(self):
        if self._location is None:
            split_location = []
            if self.city:
                split_location.append(self.city)
            if self.state_prov:
                if self.postalcode:
                    split_location.append(self.state_prov + ' ' +
                                          self.postalcode)
                else:
                    split_location.append(self.state_prov)
            if self.country:
                split_location.append(self.country)
            self._location = ', '.join(split_location)
        return self._location

    @property
    def venue_or_venue_from_address(self):
        if self.venue:
            return self.venue
        else:
            try:
                return self.venue_address.split('\r\n')[0]
            except:
                return None

    @property
    def venue_address_safe(self):
        """
        Construct (not detailed) venue address if detailed venue address doesn't exist
        """
        if not self.venue_address:
            if not self.venue or not self.location:
                self._venue_address_safe = None
            else:
                self._venue_address_safe = "{}\n{}".format(
                    self.venue.encode('utf-8'), self.location.encode('utf-8'))
        else:
            self._venue_address_safe = self.venue_address.replace('\r\n', '\n')
        return self._venue_address_safe

    @property
    def webcast(self):
        """
        Lazy load parsing webcast JSON
        """
        if self._webcast is None:
            try:
                self._webcast = json.loads(self.webcast_json)
            except Exception, e:
                self._webcast = None
        return self._webcast
Пример #8
0
class Environment(SysLog):
    created = ndb.DateTimeProperty(auto_now_add=True)
    updated = ndb.DateTimeProperty(auto_now=True)
    owner = ndb.KeyProperty(kind='User')
    users = ndb.KeyProperty(repeated=True)
    description = ndb.TextProperty()
    title = ndb.StringProperty()
    invited_users = ndb.StringProperty(repeated=True)
    user_groups = ndb.KeyProperty(repeated=True)
    users_email = ndb.StringProperty(repeated=True)
    private = ndb.BooleanProperty(default=True)

    def to_object(self):
        data = {}
        created = self.created
        created += datetime.timedelta(hours=8)
        data["created_time"] = created.strftime("%b %d, %Y %I:%M:%S %p")
        data['created'] = time.mktime(created.timetuple())
        data['updated'] = time.mktime(self.updated.timetuple())
        data['users'] = [user.urlsafe() for user in self.users]
        data['title'] = self.title
        data['description'] = self.description
        data['key'] = self.key.urlsafe()
        data['id'] = str(self.key.id())
        data['members'] = []
        data['invited_users'] = self.invited_users
        data['users_email'] = self.users_email
        data['user_groups'] = []
        data['user_groups_list'] = []
        data['private_setting'] = self.private
        data['owner'] = self.owner.get().to_object()

        if self.user_groups:
            for g in self.user_groups:
                if g:
                    data['user_groups'].append(g.id())

                    group = g.get()
                    if group:
                        data['user_groups_list'].append(group.to_object())

        if self.users:
            for u in self.users:
                user = u.get()
                if user:
                    data['members'].append(user.to_object())

        return data

    def to_api_object(self):
        data = {}
        created = self.created
        created += datetime.timedelta(hours=8)
        data["created_time"] = created.strftime("%b %d, %Y %I:%M:%S %p")
        data['created'] = time.mktime(created.timetuple())
        data['updated'] = time.mktime(self.updated.timetuple())
        data['title'] = self.title
        data['description'] = self.description
        data['key'] = self.key.urlsafe()
        data['id'] = str(self.key.id())
        data['users_email'] = self.users_email
        data['private_setting'] = self.private

        return data
Пример #9
0
class StudentPost(ndb.Model):
    name = ndb.StringProperty(required=True)
    content = ndb.TextProperty(required=True)
    office_hours_id = ndb.StringProperty(required=True)
    created = ndb.DateTimeProperty(auto_now_add=True)
Пример #10
0
class KSU(ndb.Model):

    theory = ndb.KeyProperty(kind=Theory, required=True)
    created = ndb.DateTimeProperty(auto_now_add=True)
    last_modified = ndb.DateTimeProperty(auto_now=True)

    description = ndb.StringProperty(required=True)
    secondary_description = ndb.StringProperty()

    comments = ndb.TextProperty()
    ksu_type = ndb.StringProperty()
    ksu_subtype = ndb.StringProperty()
    kpts_value = ndb.FloatProperty()

    importance = ndb.IntegerProperty(default=3)
    tags = ndb.StringProperty()
    parent_id = ndb.KeyProperty(
    )  # Ahora me esta dando un error porque lo estoy ligando a la misma clase que estoy definiendo

    is_active = ndb.BooleanProperty(default=True)
    is_critical = ndb.BooleanProperty(default=False)
    is_private = ndb.BooleanProperty(default=False)

    is_visible = ndb.BooleanProperty(default=True)
    in_graveyard = ndb.BooleanProperty(default=False)
    is_deleted = ndb.BooleanProperty(default=False)

    next_event = ndb.DateProperty()
    pretty_next_event = ndb.StringProperty()
    frequency = ndb.IntegerProperty(default=1)
    repeats = ndb.StringProperty()  # KAS1 Specific
    repeats_on = ndb.JsonProperty(
    )  #Day's of the week when it repeats if the frequency is Weekly, elese the repetition date is the same day of the month or year

    mission_view = ndb.StringProperty(default='Principal')
    best_time = ndb.TimeProperty()
    pretty_best_time = ndb.StringProperty()

    is_mini_o = ndb.BooleanProperty(default=False)
    is_jg = ndb.BooleanProperty(default=False)
    target = ndb.JsonProperty(
    )  # For ksus that generate kpts and indicators target min, target max, reverse target etc
    birthday = ndb.DateProperty()

    timer = ndb.JsonProperty(default={
        'hours': 0,
        'minutes': 0,
        'seconds': 0,
        'value': '00:00:00'
    })
    cost = ndb.JsonProperty(default={
        'money_cost': 0,
        'days_cost': 0,
        'hours_cost': 0
    })

    picture = ndb.BlobProperty()  #Might be used in the future
    times_reviewed = ndb.IntegerProperty(default=0)
    next_critical_burn = ndb.IntegerProperty(
    )  #Define siguiente fecha como ordinal en la que si no se cumplio la accion esta quema

    effort_denominator = ndb.IntegerProperty(default=3)
    wish_type = ndb.StringProperty(default='doing')
    ImIn_details = ndb.JsonProperty(
        default={
            'positive_label': 'Delighted',
            'neutral_label': 'Satisfied',
            'negative_label': 'Dissapointed',
            'units': 'Units'
        })
Пример #11
0
class Job(ndb.Model):
    """A Pinpoint job."""

    state = ndb.PickleProperty(required=True, compressed=True)

    #####
    # Job arguments passed in through the API.
    #####

    # Request parameters.
    arguments = ndb.JsonProperty(required=True)

    # TODO: The bug id is only used for posting bug comments when a job starts and
    # completes. This probably should not be the responsibility of Pinpoint.
    bug_id = ndb.IntegerProperty()

    comparison_mode = ndb.StringProperty()

    # The Gerrit server url and change id of the code review to update upon
    # completion.
    gerrit_server = ndb.StringProperty()
    gerrit_change_id = ndb.StringProperty()

    # User-provided name of the job.
    name = ndb.StringProperty()

    tags = ndb.JsonProperty()

    # Email of the job creator.
    user = ndb.StringProperty()

    #####
    # Job state generated by running the job.
    #####

    created = ndb.DateTimeProperty(required=True, auto_now_add=True)

    # This differs from "created" since there may be a lag between the time it
    # was queued and when the scheduler actually starts the job.
    started_time = ndb.DateTimeProperty(required=False)

    # Don't use `auto_now` for `updated`. When we do data migration, we need
    # to be able to modify the Job without changing the Job's completion time.
    updated = ndb.DateTimeProperty(required=True, auto_now_add=True)

    started = ndb.BooleanProperty(default=True)
    completed = ndb.ComputedProperty(
        lambda self: self.started and not self.task)
    failed = ndb.ComputedProperty(
        lambda self: bool(self.exception_details_dict))
    running = ndb.ComputedProperty(
        lambda self: self.started and not self.cancelled and self.task and len(
            self.task) > 0)
    cancelled = ndb.BooleanProperty(default=False)
    cancel_reason = ndb.TextProperty()

    # The name of the Task Queue task this job is running on. If it's present, the
    # job is running. The task is also None for Task Queue retries.
    task = ndb.StringProperty()

    # The contents of any Exception that was thrown to the top level.
    # If it's present, the job failed.
    exception = ndb.TextProperty()
    exception_details = ndb.JsonProperty()

    difference_count = ndb.IntegerProperty()

    retry_count = ndb.IntegerProperty(default=0)

    # We expose the configuration as a first-class property of the Job.
    configuration = ndb.ComputedProperty(
        lambda self: self.arguments.get('configuration'))

    # Pull out the benchmark, chart, and statistic as a structured property at the
    # top-level, so that we can analyse these in a structured manner.
    benchmark_arguments = ndb.StructuredProperty(BenchmarkArguments)

    # TODO(simonhatch): After migrating all Pinpoint entities, this can be
    # removed.
    # crbug.com/971370
    @classmethod
    def _post_get_hook(cls, key, future):  # pylint: disable=unused-argument
        e = future.get_result()
        if not e:
            return

        if not getattr(e, 'exception_details'):
            e.exception_details = e.exception_details_dict

        if not getattr(e, 'benchmark_arguments'):
            e.benchmark_arguments = BenchmarkArguments.FromArgs(e.arguments)

    # TODO(simonhatch): After migrating all Pinpoint entities, this can be
    # removed.
    # crbug.com/971370
    @property
    def exception_details_dict(self):
        if hasattr(self, 'exception_details'):
            if self.exception_details:
                return self.exception_details

        if hasattr(self, 'exception'):
            exc = self.exception
            if exc:
                return {'message': exc.splitlines()[-1], 'traceback': exc}

        return None

    @classmethod
    def New(cls,
            quests,
            changes,
            arguments=None,
            bug_id=None,
            comparison_mode=None,
            comparison_magnitude=None,
            gerrit_server=None,
            gerrit_change_id=None,
            name=None,
            pin=None,
            tags=None,
            user=None):
        """Creates a new Job, adds Changes to it, and puts it in the Datstore.

    Args:
      quests: An iterable of Quests for the Job to run.
      changes: An iterable of the initial Changes to run on.
      arguments: A dict with the original arguments used to start the Job.
      bug_id: A monorail issue id number to post Job updates to.
      comparison_mode: Either 'functional' or 'performance', which the Job uses
          to figure out whether to perform a functional or performance bisect.
          If None, the Job will not automatically add any Attempts or Changes.
      comparison_magnitude: The estimated size of the regression or improvement
          to look for. Smaller magnitudes require more repeats.
      gerrit_server: Server of the Gerrit code review to update with job
          results.
      gerrit_change_id: Change id of the Gerrit code review to update with job
          results.
      name: The user-provided name of the Job.
      pin: A Change (Commits + Patch) to apply to every Change in this Job.
      tags: A dict of key-value pairs used to filter the Jobs listings.
      user: The email of the Job creator.

    Returns:
      A Job object.
    """
        state = job_state.JobState(quests,
                                   comparison_mode=comparison_mode,
                                   comparison_magnitude=comparison_magnitude,
                                   pin=pin)
        args = arguments or {}
        job = cls(state=state,
                  arguments=args,
                  bug_id=bug_id,
                  comparison_mode=comparison_mode,
                  gerrit_server=gerrit_server,
                  gerrit_change_id=gerrit_change_id,
                  name=name,
                  tags=tags,
                  user=user,
                  started=False,
                  cancelled=False)

        for c in changes:
            job.AddChange(c)

        # Pull out the benchmark arguments to the top-level.
        job.benchmark_arguments = BenchmarkArguments.FromArgs(args)
        job.put()

        # At this point we already have an ID, so we should go through each of the
        # quests associated with the state, and provide the Job ID through a common
        # API.
        job.state.PropagateJob(job)
        job.put()
        return job

    def PostCreationUpdate(self):
        title = _ROUND_PUSHPIN + ' Pinpoint job created and queued.'
        pending = 0
        if self.configuration:
            try:
                pending = scheduler.QueueStats(self.configuration).get(
                    'queued_jobs', 0)
            except (scheduler.QueueNotFound, ndb.BadRequestError) as e:
                logging.warning(
                    'Error encountered fetching queue named "%s": %s ',
                    self.configuration, e)

        comment = CREATED_COMMENT_FORMAT.format(
            title=title,
            url=self.url,
            configuration=self.configuration
            if self.configuration else '(None)',
            pending=pending)
        deferred.defer(_PostBugCommentDeferred,
                       self.bug_id,
                       comment,
                       send_email=True,
                       _retry_options=RETRY_OPTIONS)

    @property
    def job_id(self):
        return '%x' % self.key.id()

    @property
    def status(self):
        if self.failed:
            return 'Failed'

        if self.cancelled:
            return 'Cancelled'

        if self.completed:
            return 'Completed'

        if self.running:
            return 'Running'

        # By default, we assume that the Job is queued.
        return 'Queued'

    @property
    def url(self):
        host = os.environ['HTTP_HOST']
        # TODO(crbug.com/939723): Remove this workaround when not needed.
        if host == 'pinpoint.chromeperf.appspot.com':
            host = 'pinpoint-dot-chromeperf.appspot.com'
        return 'https://%s/job/%s' % (host, self.job_id)

    @property
    def results_url(self):
        if not self.task:
            url = results2.GetCachedResults2(self)
            if url:
                return url
        # Point to the default status page if no results are available.
        return '/results2/%s' % self.job_id

    @property
    def auto_name(self):
        if self.name:
            return self.name

        if self.comparison_mode == job_state.FUNCTIONAL:
            name = 'Functional bisect'
        elif self.comparison_mode == job_state.PERFORMANCE:
            name = 'Performance bisect'
        else:
            name = 'Try job'

        if self.configuration:
            name += ' on ' + self.configuration
            if 'benchmark' in self.arguments:
                name += '/' + self.arguments['benchmark']

        return name

    def AddChange(self, change):
        self.state.AddChange(change)

    def Start(self):
        """Starts the Job and updates it in the Datastore.

    This method is designed to return fast, so that Job creation is responsive
    to the user. It schedules the Job on the task queue without running
    anything. It also posts a bug comment, and updates the Datastore.
    """
        self._Schedule()
        self.started = True
        self.started_time = datetime.datetime.now()
        self.put()

        title = _ROUND_PUSHPIN + ' Pinpoint job started.'
        comment = '\n'.join((title, self.url))
        deferred.defer(_PostBugCommentDeferred,
                       self.bug_id,
                       comment,
                       send_email=True,
                       _retry_options=RETRY_OPTIONS)

    def _IsTryJob(self):
        return not self.comparison_mode or self.comparison_mode == job_state.TRY

    def _Complete(self):
        logging.debug('Job [%s]: Completed', self.job_id)
        if not self._IsTryJob():
            self.difference_count = len(self.state.Differences())

        try:
            results2.ScheduleResults2Generation(self)
        except taskqueue.Error as e:
            logging.debug('Failed ScheduleResults2Generation: %s', str(e))

        self._FormatAndPostBugCommentOnComplete()
        self._UpdateGerritIfNeeded()
        scheduler.Complete(self)

    def _FormatAndPostBugCommentOnComplete(self):
        if self._IsTryJob():
            # There is no comparison metric.
            title = "<b>%s Job complete. See results below.</b>" % _ROUND_PUSHPIN
            deferred.defer(_PostBugCommentDeferred,
                           self.bug_id,
                           '\n'.join((title, self.url)),
                           _retry_options=RETRY_OPTIONS)
            return

        # There is a comparison metric.
        differences = self.state.Differences()

        if not differences:
            title = "<b>%s Couldn't reproduce a difference.</b>" % _ROUND_PUSHPIN
            deferred.defer(_PostBugCommentDeferred,
                           self.bug_id,
                           '\n'.join((title, self.url)),
                           _retry_options=RETRY_OPTIONS)
            return

        difference_details = []
        authors_with_deltas = {}
        commit_infos = []
        for change_a, change_b in differences:
            if change_b.patch:
                commit_info = change_b.patch.AsDict()
            else:
                commit_info = change_b.last_commit.AsDict()

            values_a = self.state.ResultValues(change_a)
            values_b = self.state.ResultValues(change_b)
            difference = _FormatDifferenceForBug(commit_info, values_a,
                                                 values_b, self.state.metric)
            difference_details.append(difference)
            commit_infos.append(commit_info)
            if values_a and values_b:
                authors_with_deltas[commit_info['author']] = job_state.Mean(
                    values_b) - job_state.Mean(values_a)

        deferred.defer(_UpdatePostAndMergeDeferred,
                       difference_details,
                       commit_infos,
                       authors_with_deltas,
                       self.bug_id,
                       self.tags,
                       self.url,
                       _retry_options=RETRY_OPTIONS)

    def _UpdateGerritIfNeeded(self):
        if self.gerrit_server and self.gerrit_change_id:
            deferred.defer(_UpdateGerritDeferred,
                           self.gerrit_server,
                           self.gerrit_change_id,
                           '%s Job complete.\n\nSee results at: %s' %
                           (_ROUND_PUSHPIN, self.url),
                           _retry_options=RETRY_OPTIONS)

    def Fail(self, exception=None):
        tb = traceback.format_exc() or ''
        title = _CRYING_CAT_FACE + ' Pinpoint job stopped with an error.'
        exc_info = sys.exc_info()
        exc_message = ''
        if exception:
            exc_message = exception
        elif exc_info[1]:
            exc_message = sys.exc_info()[1].message

        self.exception_details = {
            'message': exc_message,
            'traceback': tb,
        }
        self.task = None

        comment = '\n'.join((title, self.url, '', exc_message))
        deferred.defer(_PostBugCommentDeferred,
                       self.bug_id,
                       comment,
                       _retry_options=RETRY_OPTIONS)
        scheduler.Complete(self)

    def _Schedule(self, countdown=_TASK_INTERVAL):
        # Set a task name to deduplicate retries. This adds some latency, but we're
        # not latency-sensitive. If Job.Run() works asynchronously in the future,
        # we don't need to worry about duplicate tasks.
        # https://github.com/catapult-project/catapult/issues/3900
        task_name = str(uuid.uuid4())
        try:
            task = taskqueue.add(queue_name='job-queue',
                                 url='/api/run/' + self.job_id,
                                 name=task_name,
                                 countdown=countdown)
        except (apiproxy_errors.DeadlineExceededError,
                taskqueue.TransientError):
            raise errors.RecoverableError()

        self.task = task.name

    def _MaybeScheduleRetry(self):
        if not hasattr(self, 'retry_count') or self.retry_count is None:
            self.retry_count = 0

        if self.retry_count >= _MAX_RECOVERABLE_RETRIES:
            return False

        self.retry_count += 1

        # Back off exponentially
        self._Schedule(countdown=_TASK_INTERVAL * (2**self.retry_count))

        return True

    def Run(self):
        """Runs this Job.

    Loops through all Attempts and checks the status of each one, kicking off
    tasks as needed. Does not block to wait for all tasks to finish. Also
    compares adjacent Changes' results and adds any additional Attempts or
    Changes as needed. If there are any incomplete tasks, schedules another
    Run() call on the task queue.
    """
        self.exception_details = None  # In case the Job succeeds on retry.
        self.task = None  # In case an exception is thrown.

        try:
            if not self._IsTryJob():
                self.state.Explore()
            work_left = self.state.ScheduleWork()

            # Schedule moar task.
            if work_left:
                self._Schedule()
            else:
                self._Complete()

            self.retry_count = 0
        except errors.RecoverableError:
            try:
                if not self._MaybeScheduleRetry():
                    self.Fail(errors.RETRY_LIMIT)
            except errors.RecoverableError:
                self.Fail(errors.RETRY_FAILED)
        except BaseException:
            self.Fail()
            raise
        finally:
            # Don't use `auto_now` for `updated`. When we do data migration, we need
            # to be able to modify the Job without changing the Job's completion time.
            self.updated = datetime.datetime.now()

            if self.completed:
                timing_record.RecordJobTiming(self)

            try:
                self.put()
            except (datastore_errors.Timeout,
                    datastore_errors.TransactionFailedError):
                # Retry once.
                self.put()
            except datastore_errors.BadRequestError:
                if self.task:
                    queue = taskqueue.Queue('job-queue')
                    queue.delete_tasks(taskqueue.Task(name=self.task))
                self.task = None

                # The _JobState is too large to fit in an ndb property.
                # Load the Job from before we updated it, and fail it.
                job = self.key.get(use_cache=False)
                job.task = None
                job.Fail()
                job.updated = datetime.datetime.now()
                job.put()
                raise

    def AsDict(self, options=None):
        d = {
            'job_id': self.job_id,
            'configuration': self.configuration,
            'results_url': self.results_url,
            'arguments': self.arguments,
            'bug_id': self.bug_id,
            'comparison_mode': self.comparison_mode,
            'name': self.auto_name,
            'user': self.user,
            'created': self.created.isoformat(),
            'updated': self.updated.isoformat(),
            'difference_count': self.difference_count,
            'exception': self.exception_details_dict,
            'status': self.status,
            'cancel_reason': self.cancel_reason,
        }

        if not options:
            return d

        if OPTION_STATE in options:
            d.update(self.state.AsDict())
        if OPTION_ESTIMATE in options and not self.started:
            d.update(self._GetRunTimeEstimate())
        if OPTION_TAGS in options:
            d['tags'] = {'tags': self.tags}
        return d

    def _GetRunTimeEstimate(self):
        result = timing_record.GetSimilarHistoricalTimings(self)
        if not result:
            return {}

        timings = [t.total_seconds() for t in result.timings]
        return {
            'estimate': {
                'timings': timings,
                'tags': result.tags
            },
            'queue_stats': scheduler.QueueStats(self.configuration)
        }

    def Cancel(self, user, reason):
        # We cannot cancel an already cancelled job.
        if self.cancelled:
            logging.warning(
                'Attempted to cancel a cancelled job "%s"; user = %s, reason = %s',
                self.job_id, user, reason)
            raise errors.CancelError('Job already cancelled.')

        if not scheduler.Cancel(self):
            raise errors.CancelError('Scheduler failed to cancel job.')

        self.cancelled = True
        self.cancel_reason = '{}: {}'.format(user, reason)

        # Remove any "task" identifiers.
        self.task = None
        self.put()

        title = _ROUND_PUSHPIN + ' Pinpoint job cancelled.'
        comment = u'{}\n{}\n\nCancelled by {}, reason given: {}'.format(
            title, self.url, user, reason)
        deferred.defer(_PostBugCommentDeferred,
                       self.bug_id,
                       comment,
                       send_email=True,
                       _retry_options=RETRY_OPTIONS)
Пример #12
0
class CodeFile(ndb.Model):
    author = ndb.UserProperty()
    title = ndb.StringProperty()
    content = ndb.TextProperty(indexed=False)
    date = ndb.DateTimeProperty(auto_now_add=True)
Пример #13
0
class Facebook_CommandsValue(ndb.Model):
    # key name: command_name
    codeValue = ndb.TextProperty(indexed=False, default='')
Пример #14
0
class ExampleModel(ndb.Model):
    """Example Model"""
    example_name = ndb.StringProperty(required=True)
    example_description = ndb.TextProperty(required=True)
    added_by = ndb.UserProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
Пример #15
0
class GeneralVoiceoverApplicationModel(base_models.BaseModel):
    """A general model for voiceover application of an entity.

    The ID of the voiceover application will be a random hashed value.
    """

    # The type of entity to which the user will be assigned as a voice artist
    # once the application will get approved.
    target_type = ndb.StringProperty(required=True, indexed=True)
    # The ID of the entity to which the application belongs.
    target_id = ndb.StringProperty(required=True, indexed=True)
    # The language code for the voiceover audio.
    language_code = ndb.StringProperty(required=True, indexed=True)
    # The status of the application. One of: accepted, rejected, in-review.
    status = ndb.StringProperty(required=True,
                                indexed=True,
                                choices=STATUS_CHOICES)
    # The HTML content written in the given language_code.
    # This will typically be a snapshot of the content of the initial card of
    # the target.
    content = ndb.TextProperty(required=True)
    # The filename of the voiceover audio. The filename will have
    # datetime-randomId(length 6)-language_code.mp3 pattern.
    filename = ndb.StringProperty(required=True, indexed=True)
    # The ID of the author of the voiceover application.
    author_id = ndb.StringProperty(required=True, indexed=True)
    # The ID of the reviewer who accepted/rejected the voiceover application.
    final_reviewer_id = ndb.StringProperty(indexed=True)
    # The plain text message submitted by the reviewer while rejecting the
    # application.
    rejection_message = ndb.TextProperty()

    @staticmethod
    def get_deletion_policy():
        """General voiceover application needs to be pseudonymized for the
        user.
        """
        return base_models.DELETION_POLICY.LOCALLY_PSEUDONYMIZE

    @classmethod
    def has_reference_to_user_id(cls, user_id):
        """Check whether GeneralVoiceoverApplicationModel exists for the user.

        Args:
            user_id: str. The ID of the user whose data should be checked.

        Returns:
            bool. Whether any models refer to the given user ID.
        """
        return cls.query(
            ndb.OR(cls.author_id == user_id,
                   cls.final_reviewer_id == user_id)).get(
                       keys_only=True) is not None

    @classmethod
    def get_user_voiceover_applications(cls, author_id, status=None):
        """Returns a list of voiceover application submitted by the given user.

        Args:
            author_id: str. The id of the user created the voiceover
                application.
            status: str|None. The status of the voiceover application.
                If the status is None, the query will fetch all the
                voiceover applications.

        Returns:
            list(GeneralVoiceoverApplicationModel). The list of voiceover
            applications submitted by the given user.
        """
        if status in STATUS_CHOICES:
            return cls.query(
                ndb.AND(cls.author_id == author_id,
                        cls.status == status)).fetch()
        else:
            return cls.query(cls.author_id == author_id).fetch()

    @classmethod
    def get_reviewable_voiceover_applications(cls, user_id):
        """Returns a list of voiceover application which a given user can
        review.

        Args:
            user_id: str. The id of the user trying to make this query.
                As a user cannot review their own voiceover application, so the
                voiceover application created by the user will be excluded.

        Returns:
            list(GeneralVoiceoverApplicationModel). The list of voiceover
            applications which the given user can review.
        """
        return cls.query(
            ndb.AND(cls.author_id != user_id,
                    cls.status == STATUS_IN_REVIEW)).fetch()

    @classmethod
    def get_voiceover_applications(cls, target_type, target_id, language_code):
        """Returns a list of voiceover applications submitted for a give entity
        in a given language.

        Args:
            target_type: str. The type of entity.
            target_id: str. The ID of the targeted entity.
            language_code: str. The code of the language in which the voiceover
                application is submitted.

        Returns:
            list(GeneralVoiceoverApplicationModel). The list of voiceover
            application which is submitted to a give entity in a given language.
        """
        return cls.query(
            ndb.AND(cls.target_type == target_type, cls.target_id == target_id,
                    cls.language_code == language_code)).fetch()

    @staticmethod
    def get_export_policy():
        """Model contains user data."""
        return base_models.EXPORT_POLICY.CONTAINS_USER_DATA

    @classmethod
    def export_data(cls, user_id):
        """(Takeout) Exports the data from GeneralVoiceoverApplicationModel
        into dict format.

        Args:
            user_id: str. The ID of the user whose data should be exported.

        Returns:
            dict. Dictionary of the data from GeneralVoiceoverApplicationModel.
        """
        user_data = dict()

        voiceover_models = (cls.query(cls.author_id == user_id).fetch())

        for voiceover_model in voiceover_models:
            user_data[voiceover_model.id] = {
                'target_type': voiceover_model.target_type,
                'target_id': voiceover_model.target_id,
                'language_code': voiceover_model.language_code,
                'status': voiceover_model.status,
                'content': voiceover_model.content,
                'filename': voiceover_model.filename,
                'rejection_message': voiceover_model.rejection_message
            }
        return user_data
Пример #16
0
class Post(ndb.Model):
    """ Represents a blog post. """
    title = ndb.StringProperty(required = True)
    content = ndb.TextProperty(required = True)
    created = ndb.DateTimeProperty(auto_now_add = True)
    last_modified = ndb.DateTimeProperty(auto_now = True)
    user_id = ndb.IntegerProperty(required = True)
    username = ndb.StringProperty(required = True)
    likes = ndb.KeyProperty(kind = "BlogUser", repeated = True)
    comments = ndb.KeyProperty(kind = "Comment", repeated = True)

    @property
    def likes_count(self):
        return len(self.likes)   

    @classmethod
    def list_all(cls):
        return Post.query().order(-Post.created).fetch()

    @classmethod
    def by_id(cls, post_id):
        return Post.get_by_id(post_id)

    @classmethod
    def by_user(cls, user_id):
        q = Post.query().filter(Post.user_id == user_id).order(-Post.created)
        return q.fetch()

    @classmethod
    def create(cls, title, content, user_id, username):
        return Post(title = title,
                    content = content,
                    user_id = user_id,
                    username = username)

    def delete_comments(self):
        ndb.delete_multi(self.comments)    

    def list_comments(self):
        return Comment.by_post(self.key)

    def comments_count(self):
        return len(self.comments)

    def user_can_like(self, user):
        """ Checks whether a user can like the post. """
        return user and not (user.key.id() == self.user_id or
                             user.key in self.likes)

    def user_can_unlike(self, user):
        """ Checks whether a user can unlike the post. """
        return user and user.key in self.likes

    def prep_render(self):
        """ Preprocesses the post for rendering. """
        self._render_content = self.content.replace('\n', '<br>')

    def prep_render_comments(self):
        """ Preprocesses the post's comment list for rendering. """
        comments = self.list_comments()
        for c in comments:
            c.prep_render()
        return comments
Пример #17
0
class Beacon(ndb.Model):
    nickname = ndb.StringProperty(indexed=True)
    uuid = ndb.StringProperty(indexed=True)
    description = ndb.TextProperty()
Пример #18
0
class DemoUserInteraction(ndb.Model):
    asof = ndb.DateTimeProperty(auto_now_add=True)
    ds_key = ndb.StringProperty()
    fetching = ndb.IntegerProperty(default = 0)
    calculating = ndb.IntegerProperty(default = 0)
    calc_done = ndb.BooleanProperty(default = False)
    tweets = ndb.PickleProperty(default = [])
    calc_stats = ndb.TextProperty()

    def filename(self):
        return 'user_id: {user_id}, asof: {asof}'.format(asof = self.asof.isoformat()[:19], user_id = self.key.parent().id())

    @ndb.transactional
    def refresh(self):
        key = self.key
        ent = key.get()
        ent.fetching += 0
        ent.put()
        return ent

    @ndb.transactional
    def indicate_fetch_begun(self):
        key = self.key
        ent = key.get()
        ent.fetching += 1
        ent.put()
        return ent

    @ndb.transactional
    def indicate_fetch_ended(self):
        key = self.key
        ent = key.get()
        ent.fetching -= 1
        ent.put()
        return ent

    @ndb.transactional
    def indicate_calc_begun(self):
        key = self.key
        ent = key.get()
        if 0 == ent.calculating:
            ent.calc_stats = json.dumps(dict())
        ent.calculating += 1
        ent.calc_done = False
        ent.put()
        return ent

    @ndb.transactional
    def indicate_calc_ended(self, batch_stats):
        key = self.key
        ent = key.get()
        ent.calculating -= 1
#         logging.debug('%d', self.calculating)
        if 0 == ent.calculating:
            ent.calc_done = True
        calc_stats = json.loads(ent.calc_stats)
        for stat in batch_stats:
            if stat not in calc_stats.keys():
                calc_stats[stat] = 0.0
            calc_stats[stat] += batch_stats[stat]
        ent.calc_stats = json.dumps(calc_stats)
        ent.put()
        logging.info('<indicate_calc_ended %d %s %s/>', ent.calculating, ent.calc_done, ent.calc_stats)
        return ent
    
    @ndb.transactional
    def extend_tweets(self, tweets):
        key = self.key
        ent = key.get()
        ent.tweets.extend(tweets)
        ent.put()
        return ent

    @ndb.transactional
    def set_ds_key(self, ds_key):
        key = self.key
        ent = key.get()
        if not ent.ds_key:
            ent.ds_key = ds_key
            ent.put()
        else:
            if ds_key != ent.ds_key:
                logging.error('changing ds_key from %s to %s? Makes no sense!', ent.ds_key, ds_key)
        return ent

    @staticmethod
    def latest_for_user(user):
        if not user:
            return None
        demo_user_key = ndb.Key(DemoUser, user.user_id())
        dui = DemoUserInteraction.query(ancestor=demo_user_key).order(-DemoUserInteraction.asof).get()
        return dui

    def purge(self):
        if self.ds_key:
            matrix = Matrix.find(ds_key = self.ds_key)
            if matrix:
                matrix.purge()
Пример #19
0
class Rule(ndb.Model):
    nickname = ndb.StringProperty(indexed=True)
    actionid = ndb.KeyProperty(Action)
    rules = ndb.StructuredProperty(SimpleRule, repeated=True)
    description = ndb.TextProperty()
Пример #20
0
class Poll(ndb.Model):
    admin_uid = ndb.StringProperty()
    title = ndb.TextProperty()
    title_short = ndb.StringProperty()
    active = ndb.BooleanProperty(default=True)
    multi = ndb.BooleanProperty(default=True, indexed=False)

    options = ndb.PickleProperty(repeated=True)

    created = ndb.DateTimeProperty(auto_now_add=True)
    updated = ndb.DateTimeProperty(auto_now=True, indexed=False)

    @classmethod
    def new(cls, admin_uid, title):
        title_short = util.uslice(title, 0, 512).lower()
        return cls(admin_uid=admin_uid, title=title, title_short=title_short)

    @staticmethod
    @ndb.transactional
    def toggle(poll_id, opt_id, uid, user_profile):
        poll = Poll.get_by_id(poll_id)
        if not poll:
            return None, 'Sorry, this poll has been deleted'
        if opt_id >= len(poll.options):
            return None, 'Sorry, that\'s an invalid option'
        status = poll.options[opt_id].toggle(uid, user_profile)
        poll.put()
        return poll, status

    def get_friendly_id(self):
        return util.uslice(self.title, 0, 512)

    def generate_options_summary(self):
        return u' / '.join([option.title for option in self.options])

    def generate_respondents_summary(self):
        all_uids_by_option = [option.people.keys() for option in self.options]
        all_uids = util.flatten(all_uids_by_option)
        num_respondents = len(set(all_uids))
        if num_respondents == 0:
            output = 'Nobody responded'
        elif num_respondents == 1:
            output = '1 person responded'
        else:
            output = '{} people responded'.format(num_respondents)
        return output

    def generate_poll_summary_with_link(self):
        short_bold_title = util.make_html_bold(util.uslice(self.title, 0, 65))
        respondents_summary = self.generate_respondents_summary()
        link = '/view_{}'.format(self.key.id())
        return u'{} {}.\n{}'.format(short_bold_title, respondents_summary, link)

    def render_text(self):
        header = [util.make_html_bold_first_line(self.title)]
        body = [option.render_text() for option in self.options]
        footer = [util.emoji_people_unicode() + ' ' + self.generate_respondents_summary()]
        return u'\n\n'.join(header + body + footer)

    def render_html(self):
        from datetime import timedelta

        user = User.get_by_id(int(self.admin_uid))
        user_description = user.get_description() if user else 'unknown ({})'.format(self.admin_uid)
        timestamp = (self.created + timedelta(hours=8)).strftime('%a, %d %b \'%y, %H:%M:%S')
        details = u' <small>by {} on {}</small>'.format(user_description, timestamp)

        text = self.render_text()
        idx = text.find('\n')
        text = (text[:idx] + details + text[idx:])

        return '<p>' + text.replace('\n', '<br>\n') + '</p>'

    def build_vote_buttons(self, admin=False):
        poll_id = self.key.id()
        buttons = []
        for i, option in enumerate(self.options):
            data = '{} {}'.format(poll_id, i)
            button = InlineKeyboardButton(option.title, callback_data=data)
            buttons.append([button])
        if admin:
            back_data = '{} back'.format(poll_id)
            back_button = InlineKeyboardButton('Back', callback_data=back_data)
            buttons.append([back_button])
        return InlineKeyboardMarkup(buttons).to_dict()

    def build_admin_buttons(self):
        poll_id = self.key.id()
        insert_key = self.get_friendly_id().encode('utf-8')
        publish_button = InlineKeyboardButton('Publish poll', switch_inline_query=insert_key)
        refresh_data = '{} refresh'.format(poll_id)
        refresh_button = InlineKeyboardButton('Update results', callback_data=refresh_data)
        vote_data = '{} vote'.format(poll_id)
        vote_button = InlineKeyboardButton('Vote', callback_data=vote_data)
        delete_data = '{} delete'.format(poll_id)
        delete_button = InlineKeyboardButton('Delete', callback_data=delete_data)
        buttons = [[publish_button], [refresh_button], [vote_button, delete_button]]
        return InlineKeyboardMarkup(buttons).to_dict()
Пример #21
0
class GithubWebhookRaw(ndb.Model):
    repo = ndb.StringProperty()
    number = ndb.IntegerProperty(indexed=False)
    event = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    body = ndb.TextProperty(compressed=True)
Пример #22
0
class Media(ndb.Model):
    """
    The Media model represents different forms of media, such as YouTube Videos
    or ChiefDelphi photos, that are associated with other models, such as Teams.
    """

    # Do not change! key_names are generated based on this
    SLUG_NAMES = {
        MediaType.YOUTUBE_VIDEO: 'youtube',
        MediaType.CD_PHOTO_THREAD: 'cdphotothread',
        MediaType.IMGUR: 'imgur',
        MediaType.FACEBOOK_PROFILE: 'facebook-profile',
        MediaType.YOUTUBE_CHANNEL: 'youtube-channel',
        MediaType.TWITTER_PROFILE: 'twitter-profile',
        MediaType.GITHUB_PROFILE: 'github-profile',
        MediaType.INSTAGRAM_PROFILE: 'instagram-profile',
        MediaType.PERISCOPE_PROFILE: 'periscope-profile',
        MediaType.GRABCAD: 'grabcad',
        MediaType.ONSHAPE: 'onshape',
        MediaType.INSTAGRAM_IMAGE: 'instagram-image',
        MediaType.EXTERNAL_LINK: 'external-link',
        MediaType.AVATAR: 'avatar',
    }

    REFERENCE_MAP = {
        'team': Team,
        'event': Event,
    }

    MAX_PREFERRED = 3  # Loosely enforced. Not a big deal.

    # media_type and foreign_key make up the key_name
    media_type_enum = ndb.IntegerProperty(required=True)
    media_tag_enum = ndb.IntegerProperty(repeated=True)
    foreign_key = ndb.StringProperty(required=True)  # Unique id for the particular media type. Ex: the Youtube Video key at the end of a YouTube url

    details_json = ndb.TextProperty()  # Additional details required for rendering
    private_details_json = ndb.TextProperty()  # Additional properties we don't want to expose via API
    year = ndb.IntegerProperty()  # None if year is not relevant
    references = ndb.KeyProperty(repeated=True)  # Other models that are linked to this object
    preferred_references = ndb.KeyProperty(repeated=True)  # Other models for which this media is "Preferred". All preferred_references MUST also be in references

    created = ndb.DateTimeProperty(auto_now_add=True, indexed=False)
    updated = ndb.DateTimeProperty(auto_now=True, indexed=False)

    def __init__(self, *args, **kw):
        # store set of affected references referenced keys for cache clearing
        # keys must be model properties
        self._affected_references = {
            'references': set(),
            'preferred_references': set(),
            'year': set(),
            'media_tag_enum': set(),
        }
        self._details = None
        self._private_details = None
        self._updated_attrs = []  # Used in MediaManipulator to track what changed
        super(Media, self).__init__(*args, **kw)

    @property
    def details(self):
        if self._details is None and self.details_json is not None:
            self._details = json.loads(self.details_json)
        return self._details

    @property
    def private_details(self):
        if self._private_details is None and self.private_details_json is not None:
            self._private_details = json.loads(self.private_details_json)
        return self._private_details

    @classmethod
    def create_reference(self, reference_type, reference_key):
        return ndb.Key(self.REFERENCE_MAP[reference_type], reference_key)

    @property
    def key_name(self):
        return self.render_key_name(self.media_type_enum, self.foreign_key)

    @property
    def slug_name(self):
        return self.SLUG_NAMES[self.media_type_enum]

    @classmethod
    def render_key_name(self, media_type_enum, foreign_key):
        return "{}_{}".format(self.SLUG_NAMES[media_type_enum], foreign_key)

    # URL renderers
    @property
    def cdphotothread_image_url(self):
        return 'https://web.archive.org/web/0im_/https://www.chiefdelphi.com/media/img/{}'.format(self.details['image_partial'])

    @property
    def cdphotothread_image_url_med(self):
        return self.cdphotothread_image_url.replace('_l', '_m')

    @property
    def cdphotothread_image_url_sm(self):
        return self.cdphotothread_image_url.replace('_l', '_s')

    @property
    def cdphotothread_thread_url(self):
        return 'https://web.archive.org/web/https://www.chiefdelphi.com/media/photos/{}'.format(self.foreign_key)

    @property
    def external_link(self):
        return self.foreign_key

    @property
    def youtube_url(self):
        return 'https://www.youtube.com/embed/{}'.format(self.foreign_key)

    @property
    def youtube_url_link(self):
        return 'https://youtu.be/{}'.format(self.foreign_key)

    @property
    def imgur_url(self):
        return 'https://imgur.com/{}'.format(self.foreign_key)

    @property
    def imgur_direct_url(self):
        return 'https://i.imgur.com/{}h.jpg'.format(self.foreign_key)

    @property
    def imgur_direct_url_med(self):
        return 'https://i.imgur.com/{}m.jpg'.format(self.foreign_key)

    @property
    def imgur_direct_url_sm(self):
        return 'https://i.imgur.com/{}s.jpg'.format(self.foreign_key)

    @property
    def instagram_url(self):
        return "https://www.instagram.com/p/{}".format(self.foreign_key)

    @property
    def instagram_direct_url(self):
        return self.instagram_url_helper("l")

    @property
    def instagram_direct_url_med(self):
        return self.instagram_url_helper("m")

    @property
    def instagram_direct_url_sm(self):
        return self.instagram_url_helper("t")

    def instagram_url_helper(self, size):
        # Supported size values are t (thumbnail), m (medium), l (large)
        # See the Instagram developer docs for more information:
        # https://www.instagram.com/developer/embedding/#media_redirect!
        return "{}/media/?size={}".format(self.instagram_url, size)

    @property
    def view_image_url(self):
        if self.media_type_enum == MediaType.CD_PHOTO_THREAD:
            return self.cdphotothread_image_url
        elif self.media_type_enum == MediaType.IMGUR:
            return self.imgur_url
        elif self.media_type_enum == MediaType.GRABCAD:
            return "https://grabcad.com/library/{}".format(self.foreign_key)
        elif self.media_type_enum == MediaType.ONSHAPE:
            return "https://cad.onshape.com/documents/{}".format(self.foreign_key)
        elif self.media_type_enum == MediaType.INSTAGRAM_IMAGE:
            return self.instagram_url
        else:
            return ""

    @property
    def image_direct_url(self):
        # Largest image that isn't max resolution (which can be arbitrarily huge)
        if self.media_type_enum == MediaType.CD_PHOTO_THREAD:
            return self.cdphotothread_image_url_med
        elif self.media_type_enum == MediaType.IMGUR:
            return self.imgur_direct_url
        elif self.media_type_enum == MediaType.GRABCAD:
            return self.details['model_image'].replace('card.jpg', 'large.png')
        elif self.media_type_enum == MediaType.ONSHAPE:
            return self.details['model_image'].replace('300x300', '600x340')
        elif self.media_type_enum == MediaType.INSTAGRAM_IMAGE:
            return self.instagram_direct_url
        else:
            return ""

    @property
    def social_profile_url(self):
        if self.media_type_enum in MediaType.social_types:
            return MediaType.profile_urls[self.media_type_enum].format(self.foreign_key)
        return ""

    @property
    def type_name(self):
        return MediaType.type_names[self.media_type_enum]

    @property
    def tag_names(self):
        return [MediaTag.tag_names[t] for t in self.media_tag_enum]

    @property
    def is_image(self):
        return self.media_type_enum in MediaType.image_types

    @property
    def image_direct_url_med(self):
        if self.media_type_enum == MediaType.CD_PHOTO_THREAD:
            return self.cdphotothread_image_url_med
        elif self.media_type_enum == MediaType.IMGUR:
            return self.imgur_direct_url_med
        elif self.media_type_enum == MediaType.GRABCAD:
            return self.details['model_image']
        elif self.media_type_enum == MediaType.ONSHAPE:
            return self.details['model_image']
        elif self.media_type_enum == MediaType.INSTAGRAM_IMAGE:
            return self.instagram_direct_url_med
        else:
            return ""

    @property
    def image_direct_url_sm(self):
        if self.media_type_enum == MediaType.CD_PHOTO_THREAD:
            return self.cdphotothread_image_url_sm
        elif self.media_type_enum == MediaType.IMGUR:
            return self.imgur_direct_url_sm
        elif self.media_type_enum == MediaType.GRABCAD:
            return self.details['model_image'].replace('large.jpg', 'tiny.jpg')
        elif self.media_type_enum == MediaType.ONSHAPE:
            return self.details['model_image'].replace('300x300', '300x170')
        elif self.media_type_enum == MediaType.INSTAGRAM_IMAGE:
            return self.instagram_direct_url_sm
        else:
            return ""

    @property
    def avatar_image_source(self):
        image = json.loads(self.details_json)
        return 'data:image/png;base64, {}'.format(image['base64Image'])
Пример #23
0
class Company(ndb.Model):
    """A model representing a company."""
    name = ndb.StringProperty()
    description = ndb.TextProperty()
    company_address = ndb.StringProperty()
Пример #24
0
class LogEmail(ndb.Model):
    sender = ndb.StringProperty(required=True)
    to = ndb.StringProperty(required=True)
    subject = ndb.StringProperty(required=True)
    body = ndb.TextProperty()
    when = ndb.DateTimeProperty()
Пример #25
0
class ExplorationModel(base_models.VersionedModel):
    """Versioned storage model for an Oppia exploration.

    This class should only be imported by the exploration domain file, the
    exploration services file, and the Exploration model test file.
    """
    SNAPSHOT_METADATA_CLASS = ExplorationSnapshotMetadataModel
    SNAPSHOT_CONTENT_CLASS = ExplorationSnapshotContentModel
    ALLOW_REVERT = True

    # What this exploration is called.
    title = ndb.StringProperty(required=True)
    # The category this exploration belongs to.
    category = ndb.StringProperty(required=True, indexed=True)
    # The objective of this exploration.
    objective = ndb.TextProperty(default='', indexed=False)
    # The ISO 639-1 code for the language this exploration is written in.
    language_code = ndb.StringProperty(default=feconf.DEFAULT_LANGUAGE_CODE,
                                       indexed=True)
    # Tags (topics, skills, concepts, etc.) associated with this
    # exploration.
    tags = ndb.StringProperty(repeated=True, indexed=True)
    # DEPRECATED in v2.0.0.rc.2. Do not use. Retaining it here because deletion
    # caused GAE to raise an error on fetching a specific version of the
    # exploration model.
    # TODO(sll): Fix this error and remove this property.
    skill_tags = ndb.StringProperty(repeated=True, indexed=True)
    # A blurb for this exploration.
    blurb = ndb.TextProperty(default='', indexed=False)
    # 'Author notes' for this exploration.
    author_notes = ndb.TextProperty(default='', indexed=False)
    # The default HTML template to use for displaying the exploration to the
    # reader. This is a filename in data/skins (without the .html suffix).
    default_skin = ndb.StringProperty(default='conversation_v1')

    # Schema storing specifications of the contents of any gadget panels,
    # along with associated customizations for each gadget instance.
    skin_customizations = ndb.JsonProperty(
        default=feconf.DEFAULT_SKIN_CUSTOMIZATIONS, indexed=False)

    # The version of the states blob schema.
    states_schema_version = ndb.IntegerProperty(required=True,
                                                default=0,
                                                indexed=True)
    # The name of the initial state of this exploration.
    init_state_name = ndb.StringProperty(required=True, indexed=False)
    # A dict representing the states of this exploration. This dict should
    # not be empty.
    states = ndb.JsonProperty(default={}, indexed=False)
    # The dict of parameter specifications associated with this exploration.
    # Each specification is a dict whose keys are param names and whose values
    # are each dicts with a single key, 'obj_type', whose value is a string.
    param_specs = ndb.JsonProperty(default={}, indexed=False)
    # The list of parameter changes to be performed once at the start of a
    # reader's encounter with an exploration.
    param_changes = ndb.JsonProperty(repeated=True, indexed=False)

    @classmethod
    def get_exploration_count(cls):
        """Returns the total number of explorations."""
        return cls.get_all().count()

    def commit(self, committer_id, commit_message, commit_cmds):
        """Updates the exploration using the properties dict, then saves it."""
        super(ExplorationModel, self).commit(committer_id, commit_message,
                                             commit_cmds)

    def _trusted_commit(self, committer_id, commit_type, commit_message,
                        commit_cmds):
        """Record the event to the commit log after the model commit.

        Note that this extends the superclass method.
        """
        super(ExplorationModel,
              self)._trusted_commit(committer_id, commit_type, commit_message,
                                    commit_cmds)

        committer_user_settings_model = (
            user_models.UserSettingsModel.get_by_id(committer_id))
        committer_username = (committer_user_settings_model.username
                              if committer_user_settings_model else '')

        exp_rights = ExplorationRightsModel.get_by_id(self.id)

        # TODO(msl): test if put_async() leads to any problems (make
        # sure summary dicts get updated correctly when explorations
        # are changed)
        ExplorationCommitLogEntryModel(
            id=('exploration-%s-%s' % (self.id, self.version)),
            user_id=committer_id,
            username=committer_username,
            exploration_id=self.id,
            commit_type=commit_type,
            commit_message=commit_message,
            commit_cmds=commit_cmds,
            version=self.version,
            post_commit_status=exp_rights.status,
            post_commit_community_owned=exp_rights.community_owned,
            post_commit_is_private=(
                exp_rights.status == EXPLORATION_STATUS_PRIVATE)).put_async()
Пример #26
0
class Comment(ndb.Model):
    content = ndb.TextProperty()
    author_email = ndb.StringProperty()
    topic_id = ndb.IntegerProperty()
    topic_title = ndb.StringProperty()
    created = ndb.DateTimeProperty(auto_now_add=True)
    updated = ndb.DateTimeProperty(auto_now=True)
    deleted = ndb.BooleanProperty(default=False)

    @classmethod
    def create(cls, content, user, topic):
        """Class method to create new comment.

        :param content: Content text
        :type content: str
        :param user: Author user
        :type user: User
        :param topic: Topic where the comment belongs to
        :type topic: Topic
        :return: New comment
        """
        user_email = normalize_email(user.email())

        new_comment = cls(
            content=escape_html(content),
            topic_id=topic.key.id(),
            topic_title=topic.title,
            author_email=user_email,
        )
        new_comment.put()

        subscriptions = TopicSubscription.query(
            TopicSubscription.topic_id == topic.key.id()).fetch()

        subscribers = [
            topic.author_email,
        ]

        for subscription in subscriptions:
            if subscription.user_email != user_email:
                subscribers.append(subscription.user_email)

        # Send notification to topic author and subscribers.
        for email in subscribers:
            params = {
                'topic-author-email': email,
                'topic-title': topic.title,
                'topic-id': topic.key.id(),
            }
            taskqueue.add(url='/task/email-new-comment', params=params)

        return new_comment

    @classmethod
    def delete(cls, comment_id):
        comment = Comment.get_by_id(int(comment_id))
        comment.deleted = True
        comment.put()
        return comment

    @classmethod
    def filter_by_topic(cls, topic):
        '''Classmethod to filter comments by topic

        :param topic: Topic instance
        :return: Query
        '''
        query = cls.query(cls.deleted == False).filter(
            cls.topic_id == topic.key.id())
        return query

    @classmethod
    def filter_by_author_email(cls, email):
        '''Classmethod to filter comments by author's email.

        :param email: string
        :return: Query
        '''
        query = cls.query(cls.deleted == False).filter(
            cls.author_email == email)
        return query
Пример #27
0
class Session(ndb.Model):

    patient_id = ndb.StringProperty()

    is_billed = ndb.BooleanProperty()
    billing_time = ndb.DateTimeProperty(indexed=False)
    insurance = ndb.StringProperty()
    mod_code = ndb.StringProperty(indexed=False)

    session_number = ndb.IntegerProperty(indexed=False)

    date = ndb.StringProperty(indexed=False)
    date_object = ndb.DateProperty()
    timestamp = ndb.DateTimeProperty(indexed=False)

    name = ndb.StringProperty()

    dob = ndb.StringProperty(indexed=False)
    diag = ndb.StringProperty(indexed=False)
    diag_code = ndb.StringProperty(indexed=False)
    diag_2 = ndb.StringProperty(indexed=False)
    diag_2_code = ndb.StringProperty(indexed=False)
    modality = ndb.StringProperty(indexed=False)
    new_issue = ndb.StringProperty(indexed=False)
    no_new_issue = ndb.StringProperty(indexed=False)

    ASS_ABLE= ndb.StringProperty(indexed=False)
    ASS_CONST= ndb.StringProperty(indexed=False)
    ASS_COOP= ndb.StringProperty(indexed=False)
    ASS_EFFRT= ndb.StringProperty(indexed=False)
    ASS_INSIG= ndb.StringProperty(indexed=False)
    ASS_OR= ndb.StringProperty(indexed=False)
    ASS_other_txt= ndb.StringProperty(indexed=False)
    ASS_present= ndb.StringProperty(indexed=False)
    ASS_present_txt= ndb.StringProperty(indexed=False)
    G_1_decr= ndb.StringProperty(indexed=False)
    G_1_decr_txt= ndb.StringProperty(indexed=False)
    G_1_impr= ndb.StringProperty(indexed=False)
    G_1_impr_txt= ndb.StringProperty(indexed=False)
    G_2_decr= ndb.StringProperty(indexed=False)
    G_2_decr_txt= ndb.StringProperty(indexed=False)
    G_2_impr= ndb.StringProperty(indexed=False)
    G_2_impr_txt= ndb.StringProperty(indexed=False)
    G_3_decr= ndb.StringProperty(indexed=False)
    G_3_decr_txt= ndb.StringProperty(indexed=False)
    G_3_impr= ndb.StringProperty(indexed=False)
    G_3_impr_txt= ndb.StringProperty(indexed=False)
    G_cop_skills= ndb.StringProperty(indexed=False)
    G_expr= ndb.StringProperty(indexed=False)
    G_id_res= ndb.StringProperty(indexed=False)
    G_other_txt= ndb.StringProperty(indexed=False)
    G_sc_skills= ndb.StringProperty(indexed=False)
    G_verb= ndb.StringProperty(indexed=False)
    PLN_CONT= ndb.StringProperty(indexed=False)
    PLN_FREQ= ndb.StringProperty(indexed=False)
    PLN_NXT= ndb.StringProperty(indexed=False)
    PLN_PSY= ndb.StringProperty(indexed=False)
    PLN_other_txt= ndb.StringProperty(indexed=False)
    RA_none= ndb.StringProperty(indexed=False)
    RA_others_att= ndb.StringProperty(indexed=False)
    RA_others_idea= ndb.StringProperty(indexed=False)
    RA_others_plan= ndb.StringProperty(indexed=False)
    RA_prop_att= ndb.StringProperty(indexed=False)
    RA_prop_idea= ndb.StringProperty(indexed=False)
    RA_prop_plan= ndb.StringProperty(indexed=False)
    RA_self_att= ndb.StringProperty(indexed=False)
    RA_self_idea= ndb.StringProperty(indexed=False)
    RA_self_plan= ndb.StringProperty(indexed=False)
    SPA_ACTOUT= ndb.StringProperty(indexed=False)
    SPA_AGI= ndb.StringProperty(indexed=False)
    SPA_AHA= ndb.StringProperty(indexed=False)
    SPA_ALCHUSE= ndb.StringProperty(indexed=False)
    SPA_ANG= ndb.StringProperty(indexed=False)
    SPA_ARG= ndb.StringProperty(indexed=False)
    SPA_AX= ndb.StringProperty(indexed=False)
    SPA_DIFTRAN= ndb.StringProperty(indexed=False)
    SPA_DIT= ndb.StringProperty(indexed=False)
    SPA_DM= ndb.StringProperty(indexed=False)
    SPA_DRGUSE= ndb.StringProperty(indexed=False)
    SPA_DRT= ndb.StringProperty(indexed=False)
    SPA_DWF= ndb.StringProperty(indexed=False)
    SPA_EABOR= ndb.StringProperty(indexed=False)
    SPA_EW= ndb.StringProperty(indexed=False)
    SPA_FA= ndb.StringProperty(indexed=False)
    SPA_FDP= ndb.StringProperty(indexed=False)
    SPA_FINDIF= ndb.StringProperty(indexed=False)
    SPA_FRU= ndb.StringProperty(indexed=False)
    SPA_GF= ndb.StringProperty(indexed=False)
    SPA_HSC= ndb.StringProperty(indexed=False)
    SPA_HV= ndb.StringProperty(indexed=False)
    SPA_I= ndb.StringProperty(indexed=False)
    SPA_IMPU= ndb.StringProperty(indexed=False)
    SPA_INT= ndb.StringProperty(indexed=False)
    SPA_INTI= ndb.StringProperty(indexed=False)
    SPA_INTP= ndb.StringProperty(indexed=False)
    SPA_IRR= ndb.StringProperty(indexed=False)
    SPA_LE= ndb.StringProperty(indexed=False)
    SPA_LF= ndb.StringProperty(indexed=False)
    SPA_LI= ndb.StringProperty(indexed=False)
    SPA_LM= ndb.StringProperty(indexed=False)
    SPA_MARC= ndb.StringProperty(indexed=False)
    SPA_MEDDIF= ndb.StringProperty(indexed=False)
    SPA_MEDNC= ndb.StringProperty(indexed=False)
    SPA_ML= ndb.StringProperty(indexed=False)
    SPA_MOTREST= ndb.StringProperty(indexed=False)
    SPA_MS= ndb.StringProperty(indexed=False)
    SPA_MUT= ndb.StringProperty(indexed=False)
    SPA_OT= ndb.StringProperty(indexed=False)
    SPA_PACH= ndb.StringProperty(indexed=False)
    SPA_PAP= ndb.StringProperty(indexed=False)
    SPA_PER= ndb.StringProperty(indexed=False)
    SPA_PHY= ndb.StringProperty(indexed=False)
    SPA_PS= ndb.StringProperty(indexed=False)
    SPA_PSC= ndb.StringProperty(indexed=False)
    SPA_PSEC= ndb.StringProperty(indexed=False)
    SPA_PSL= ndb.StringProperty(indexed=False)
    SPA_RECREL= ndb.StringProperty(indexed=False)
    SPA_RRA= ndb.StringProperty(indexed=False)
    SPA_S= ndb.StringProperty(indexed=False)
    SPA_SIDI= ndb.StringProperty(indexed=False)
    SPA_SM= ndb.StringProperty(indexed=False)
    SPA_SPP= ndb.StringProperty(indexed=False)
    SPA_SSTR= ndb.StringProperty(indexed=False)
    SPA_URGSUSE= ndb.StringProperty(indexed=False)
    SPA_VHA= ndb.StringProperty(indexed=False)
    SPA_WPP= ndb.StringProperty(indexed=False)
    SPA_WSTR= ndb.StringProperty(indexed=False)
    SPA_other_txt= ndb.StringProperty(indexed=False)
    TI_CSB= ndb.StringProperty(indexed=False)
    TI_PSB= ndb.StringProperty(indexed=False)
    TI_PSCR= ndb.StringProperty(indexed=False)
    TI_conf_behav= ndb.StringProperty(indexed=False)
    TI_decis_balnc= ndb.StringProperty(indexed=False)
    TI_emot_supp= ndb.StringProperty(indexed=False)
    TI_encour= ndb.StringProperty(indexed=False)
    TI_explore= ndb.StringProperty(indexed=False)
    TI_other_txt= ndb.StringProperty(indexed=False)
    TI_play_therapy= ndb.StringProperty(indexed=False)
    TI_pos_reinforce= ndb.StringProperty(indexed=False)
    TI_prob_solv= ndb.StringProperty(indexed=False)
    TI_real_test= ndb.StringProperty(indexed=False)
    TI_refl_listen= ndb.StringProperty(indexed=False)
    TI_valid= ndb.StringProperty(indexed=False)

    notes = ndb.TextProperty(indexed=False)
    notes_img_id = ndb.StringProperty(indexed=False)
Пример #28
0
class Comments(ndb.Model):
    comment_date = ndb.DateTimeProperty(auto_now_add=True)
    comment = ndb.TextProperty(indexed=False)
    author = ndb.UserProperty(required=True)
    application = ndb.StringProperty(required=True)
Пример #29
0
class GeneralFeedbackThreadModel(base_models.BaseModel):
    """Threads for each entity.

    The id of instances of this class has the form
        [ENTITY_TYPE].[ENTITY_ID].[GENERATED_STRING]
    """
    # The type of entity the thread is linked to.
    entity_type = ndb.StringProperty(required=True, indexed=True)
    # The ID of the entity the thread is linked to.
    entity_id = ndb.StringProperty(required=True, indexed=True)
    # ID of the user who started the thread. This may be None if the feedback
    # was given anonymously by a learner.
    original_author_id = ndb.StringProperty(indexed=True)
    # Latest status of the thread.
    status = ndb.StringProperty(
        default=STATUS_CHOICES_OPEN,
        choices=STATUS_CHOICES,
        required=True,
        indexed=True,
    )
    # Latest subject of the thread.
    subject = ndb.StringProperty(indexed=True, required=True)
    # Summary text of the thread.
    summary = ndb.TextProperty(indexed=False)
    # Specifies whether this thread has a related suggestion.
    has_suggestion = ndb.BooleanProperty(
        indexed=True, default=False, required=True)
    # The number of messages in the thread.
    message_count = ndb.IntegerProperty(indexed=True, default=0)

    @staticmethod
    def get_deletion_policy():
        """General feedback thread needs to be pseudonymized for the user."""
        return base_models.DELETION_POLICY.LOCALLY_PSEUDONYMIZE

    @classmethod
    def has_reference_to_user_id(cls, user_id):
        """Check whether GeneralFeedbackThreadModel exists for user.

        Args:
            user_id: str. The ID of the user whose data should be checked.

        Returns:
            bool. Whether any models refer to the given user ID.
        """
        return cls.query(cls.original_author_id == user_id).get() is not None

    @classmethod
    def export_data(cls, user_id):
        """Exports the data from GeneralFeedbackThreadModel
        into dict format for Takeout.

        Args:
            user_id: str. The ID of the user whose data should be exported.

        Returns:
            dict. Dictionary of the data from GeneralFeedbackThreadModel.
        """

        user_data = dict()
        feedback_models = cls.get_all().filter(
            cls.original_author_id == user_id).fetch()

        for feedback_model in feedback_models:
            user_data[feedback_model.id] = {
                'entity_type': feedback_model.entity_type,
                'entity_id': feedback_model.entity_id,
                'status': feedback_model.status,
                'subject': feedback_model.subject,
                'has_suggestion': feedback_model.has_suggestion,
                'summary': feedback_model.summary,
                'message_count': feedback_model.message_count,
                'last_updated': feedback_model.last_updated
            }

        return user_data

    @classmethod
    def generate_new_thread_id(cls, entity_type, entity_id):
        """Generates a new thread ID which is unique.

        Args:
            entity_type: str. The type of the entity.
            entity_id: str. The ID of the entity.

        Returns:
            str. A thread ID that is different from the IDs of all
                the existing threads within the given entity.

        Raises:
           Exception: There were too many collisions with existing thread IDs
               when attempting to generate a new thread ID.
        """
        for _ in python_utils.RANGE(_MAX_RETRIES):
            thread_id = (
                entity_type + '.' + entity_id + '.' +
                utils.base64_from_int(utils.get_current_time_in_millisecs()) +
                utils.base64_from_int(utils.get_random_int(_RAND_RANGE)))
            if not cls.get_by_id(thread_id):
                return thread_id
        raise Exception(
            'New thread id generator is producing too many collisions.')

    @classmethod
    def create(cls, thread_id):
        """Creates a new FeedbackThreadModel entry.

        Args:
            thread_id: str. Thread ID of the newly-created thread.

        Returns:
            GeneralFeedbackThreadModel. The newly created FeedbackThreadModel
                instance.

        Raises:
            Exception: A thread with the given thread ID exists already.
        """
        if cls.get_by_id(thread_id):
            raise Exception('Feedback thread ID conflict on create.')
        return cls(id=thread_id)

    @classmethod
    def get_threads(
            cls, entity_type, entity_id, limit=feconf.DEFAULT_QUERY_LIMIT):
        """Returns a list of threads associated with the entity, ordered
        by their "last updated" field. The number of entities fetched is
        limited by the `limit` argument to this method, whose default
        value is equal to the default query limit.

        Args:
            entity_type: str. The type of the entity.
            entity_id: str. The ID of the entity.
            limit: int. The maximum possible number of items in the returned
                list.

        Returns:
            list(GeneralFeedbackThreadModel). List of threads associated with
                the entity. Doesn't include deleted entries.
        """
        return cls.get_all().filter(cls.entity_type == entity_type).filter(
            cls.entity_id == entity_id).order(-cls.last_updated).fetch(limit)
Пример #30
0
class StoryPost(ndb.Model):
    title = ndb.StringProperty()
    text = ndb.TextProperty()
    url = ndb.TextProperty()
    short_url = ndb.TextProperty(indexed=False)
    short_hn_url = ndb.TextProperty(indexed=False)
    score = ndb.IntegerProperty(indexed=False)

    created = ndb.DateTimeProperty(auto_now_add=True)

    @classmethod
    def add(cls, story):
        story_id = str(story.get('id'))
        if memcache.get(story_id):
            logging.info('STOP: {} in memcache'.format(story_id))
            return
        if ndb.Key(cls, story_id).get():
            logging.info('STOP: {} in DB'.format(story_id))
            memcache.set(story_id, 1)
            return
        logging.info('SEND: {}'.format(story_id))
        story['title'] = story.get('title').encode('utf-8')

        hn_url = "https://news.ycombinator.com/item?id={}".format(story_id)
        short_hn_url = shorten_url(hn_url)
        buttons = []

        if story.get('url'):
            short_url = shorten_url(story.get('url'))
            buttons.append({'text': 'Read', 'url': story.get('url')})
        else:
            short_url = short_hn_url
            story['url'] = hn_url

        buttons.append({
            'text':
            '{}+ Comments'.format(story.get('descendants', 0)),
            'url':
            hn_url
        })

        # Add title
        message = '<b>{title}</b> (Score: {score}+)\n\n'.format(**story)
        # Add link
        message += '<b>Link:</b> {}\n'.format(short_url)
        # Add text
        text = story.get('text')
        if text:
            text = text.replace('<p>', '\n').replace('&#x27;', "'") \
                       .replace('&#x2F;', '/').encode('utf-8')
            message += "\n{}\n".format(text)

        if development():
            result = send_message('@hacker_news_feed_st', message,
                                  {'inline_keyboard': [buttons]})
        else:
            result = send_message('@hacker_news_feed', message,
                                  {'inline_keyboard': [buttons]})
        if result:
            cls(id=story_id,
                title=story.get('title'),
                url=story.get('url'),
                score=story.get('score'),
                text=story.get('text'),
                short_url=short_url,
                short_hn_url=short_hn_url).put()
            memcache.set(story_id, 1)