Esempio n. 1
0
    def get(self, practice_id):
        id = Practice.get_long_uid(practice_id)
        practice = self.api.get_by_id(id)
        if practice:
            # Increment view counts on the practice
            view_counter.increment(id)

            # Get related practices
            related_practices = Practice.get_related_practices(practice, 3)

            # Get color from associated content
            color = '#51516c'  # default color
            if practice.associated_content:
                associated_content = self.api.get_by_id(
                    practice.associated_content)
                color = associated_content.color

            creator = practice.key.parent().get()
            self.write(
                'practice.html',
                practice=practice,
                creator=creator,
                creator_json=json.dumps(creator.to_client_dict()),
                color=color,
                related_practices=related_practices,
            )
        else:
            # 404 if theme cannot be found
            return self.http_not_found()
Esempio n. 2
0
    def get(self, practice_id, gcs_object):
        # Build the GCS path for this object, which is based on bucket, user,
        # and object.
        user_id = Practice.get_parent_uid(practice_id)
        gs_object_name = '/gs/{}/{}/{}'.format(util.get_upload_bucket(),
                                               user_id, gcs_object)

        # Although this inherits from webapp's "Blobstore" handler, the files
        # actually reside in Google Cloud Storage. That's why we convert from
        # the gcs file name.
        blob_key = blobstore.create_gs_key(gs_object_name)

        # Look up the human-readable file name in the file info data of the
        # practice. See the UploadFiles handlers for details on what else is in
        # the file_info dictionary.
        practice = Practice.get_by_id(practice_id)
        filename = None
        for file_info in practice.json_properties['files']:
            if gs_object_name == file_info['gs_object_name']:
                filename = file_info['filename']
        if filename is None:
            raise Exception("Could not find file in practice: {} {}".format(
                practice_id, gcs_object))

        # Attach headers that make the file 1) immediately download rather than
        # opening in the browser and 2) have a pretty file name.
        self.response.headers['Content-Disposition'] = (
            "attachment; filename=" + str(filename))
        self.send_blob(blob_key)
Esempio n. 3
0
    def get(self, topic_id):
        full_topic_id = Topic.get_long_uid(topic_id)
        topic = self.api.get_by_id(full_topic_id)

        # check all content objects were found
        if topic is not None:

            # Increment view counts on the topic
            view_counter.increment(full_topic_id)

            # find lessons in topic
            lessons = []
            if topic.lessons:
                lessons = self.api.get_by_id(topic.lessons)

            # Get related practices
            related_practices = Practice.get_related_practices(topic, 6)

            self.write(
                'topic.html',
                topic=topic,
                lessons=lessons,
                color=topic.color,
                related_practices=related_practices,
            )

        else:
            # 404 if topic cannot be found
            return self.http_not_found()
Esempio n. 4
0
    def add_practice() -> str:

        #バリデーションクラス
        vld = validation.Validation()

        #JSON形式で値が入っているかチェック
        none_validate = {
            'title': 'No Title',
            'year': 'No Year',
            'month': 'No Month',
            'date': 'No Date',
            'hour': 'No Hour',
            'minute': 'No Minute',
            'length': 'No Length',
            'deaddate': 'No Deaddate',
            'deadtime': 'No Deadtime',
            'membernum': 'No Membernum',
            'membertype': 'No Membertype',
            'courtid': 'No Courtid',
            'courttype': 'No Courttype',
            'courtnum': 'No Courtnum',
            'explain': 'No Explain',
            'other': 'No Other',
        }

        messages = vld.check_json(none_validate, 'null_check')
        if not messages == []:
            return ','.join(messages)

        numeric_validate = {
            'year': 'Year is not numeric',
            'month': 'Month is not numeric',
            'hour': 'Hour is not numeric',
            'date': 'Date is not numeric',
            'length': 'Length is not numeric',
            'deaddate': 'Deaddate is not numeric',
            'deadtime': 'Deadtime is not numeric',
            'membernum': 'Membernum is not numeric',
            'membertype': 'Membertype is not numeric',
            'courttype': 'Courttype is not numeric',
            'courtnum': 'Courtnum is not numeric',
        }

        messages = vld.check_json(numeric_validate, 'numeric_check')
        if not message == []:
            return ','.join(messages)

        title, start_date, start_time, end_date, end_time, dead_date, dead_time, member_num, member_type, court_id, court_type, explain, other = fix_request(
        )

        practice = Practice(title, start_date, start_time, end_date, end_time,
                            dead_date, dead_time, member_num, member_type,
                            court_id, court_num, court_type, explain, other)
        db.session.add(practice)
        db.session.commit()

        return 'Success'
Esempio n. 5
0
    def get(self, theme_id):
        id = Theme.get_long_uid(theme_id)
        theme = self.api.get_by_id(id)
        first_lesson_link = ''
        if theme is not None:
            # fetch topics for theme
            topics = []
            if theme.topics:
                topics = self.api.get_by_id(theme.topics)
                # fetch lessons for each topic
                topic_lesson_ids = [
                    id for topic in topics for id in topic.lessons
                ]
                theme_lessons = self.api.get_by_id(topic_lesson_ids)
                # associate lessons with appropriate topics
                for topic in topics:
                    topic.lessons_list = [
                        l for l in theme_lessons if l.uid in topic.lessons
                    ]

                # get first lesson for CTA
                first_lesson_link = '/{}'.format(theme.short_uid)
                has_first_lesson = topics[0] and topics[
                    0].lessons_list and topics[0].lessons_list[0]
                if has_first_lesson:
                    first_lesson_link = '/{}/{}/{}'.format(
                        first_lesson_link, topics[0].short_uid,
                        topics[0].lessons_list[0].short_uid)

            # Get related practices
            related_practices = Practice.get_related_practices(theme, 6)

            # Get translated text and locale
            if theme.locale in config.available_locales:
                locale = theme.locale
            else:
                locale = default_locale

            self.write(
                'theme.html',
                theme=theme,
                topics=topics,
                first_lesson_link=first_lesson_link,
                audience=theme.target_audience,
                related_practices=related_practices,
                locale=locale,
                translation=locales.translations[locale]["courses"],
            )
        else:
            # Special (temporary) redirect for math kit
            # Consider adding 'aliases' for themes
            if theme_id == 'math':
                self.redirect('/growth-mindset-math', permanent=True)
            # 404 if theme cannot be found
            return self.http_not_found()
Esempio n. 6
0
    def get(self):
        # Fetches votes for currently logged in user
        # Replace lesson_id and practice_id with full versions
        params = self.get_params()
        if 'practice_id' in params:
            params[u'practice_id'] = Practice.get_long_uid(
                params[u'practice_id'])
        if 'lesson_id' in params:
            params[u'lesson_id'] = Lesson.get_long_uid(params[u'lesson_id'])

        votes = self.api.get('Vote', ancestor=self.api.user, **params)
        self.write(votes)
Esempio n. 7
0
    def get(self, practice_id):
        id = Practice.get_long_uid(practice_id)
        practice = self.api.get_by_id(id)
        if practice:
            # Increment view counts on the practice
            view_counter.increment(id)

            # Get related practices
            related_practices = Practice.get_related_practices(practice, 3)

            creator = practice.key.parent().get().to_client_dict()
            self.write(
                'practice.html',
                practice=practice,
                creator=creator,
                creator_json=json.dumps(creator),
                related_practices=related_practices,
            )
        else:
            # 404 if theme cannot be found
            return self.http_not_found()
Esempio n. 8
0
    def _annotate_search_content(self, result_dicts):
        """Add data re: content authors and current user to search results."""

        # Search does a weird thing where the repeated authors field can be
        # stored as a list or as a single string value. Standardize it.
        for d in result_dicts:
            if 'authors' in d:
                if type(d['authors']) is not list:
                    d['authors'] = [d['authors']]

        # Content authors
        author_ids = set()
        for d in result_dicts:
            for aid in d.get('authors', []):
                author_ids.add(aid)
        fetched_authors = User.get_by_id(list(author_ids)) or []
        authors_by_id = {user.uid: user for user in fetched_authors}

        # Votes and comments by the current user (who may not be signed in).

        if self.user:
            users_votes_for = self.get('Vote', ancestor=self.user)
            content_user_voted_for = ([v.lesson_id for v in users_votes_for] +
                                      [v.practice_id for v in users_votes_for])
            users_comments = self.get('Comment', ancestor=self.user)
            content_user_commented = ([c.lesson_id for c in users_comments] +
                                      [c.practice_id for c in users_comments])
        else:
            # The user is not signed in.
            content_user_voted_for = []
            content_user_commented = []

        # Loop through search results and modify.

        for d in result_dicts:
            # Find and add content authors.
            if 'authors' in d:
                d['author_users'] = []
                for aid in d['authors']:
                    user = authors_by_id.get(aid, None)
                    if user:
                        d['author_users'].append(user.to_client_dict())
            # Check if the current user voted for or commented on this.
            if d['uid'] in content_user_voted_for:
                d['user_voted_for'] = True
            if d['uid'] in content_user_commented:
                d['user_commented_on'] = True

            # Add in short_uid if not
            if 'short_uid' not in d:
                d['short_uid'] = Practice.convert_uid(d['uid'])

        return result_dicts
Esempio n. 9
0
 def remove_file(self, id):
     file_key = self.get_params().get('file')
     if id is not None and file_key is not None:
         id = Practice.get_long_uid(id)
         practice = self.api.get_by_id(id)
         practice.remove_file_data(urllib.unquote(file_key))
         practice.put()
         self.write(practice)
     else:
         self.response.write(
             json.dumps({
                 'error': True,
                 'message': 'invalid parameters'
             }))
Esempio n. 10
0
    def delete(self, id):
        if not self.user:
            raise PermissionDenied("Public cannot delete.")

        logging.info(u'Api.delete(id={})'.format(id))

        entity = Model.get_by_id(id)
        if not self.user.is_admin:
            # Then the user must be the creator of the thing, which equates
            # to being the parent entity (in a Datastore sense) of the thing
            # being deleted.
            if entity.key.parent() != self.user.key:
                raise PermissionDenied(
                    "{} does not own {} and may not delete it.".format(
                        self.user, entity))

        entity.deleted = True
        # We're about to take it out of the index, so don't bother updating
        # it with the new value of the deleted property.
        # See model.Model._post_put_hook()
        entity.forbid_post_put_hook = True
        entity.put()

        if isinstance(entity, (Lesson, Practice)):
            logging.info("Removing soft-deleted content from search.")
            search.Index(config.content_index).delete(entity.uid)

        entity_kind = Model.get_kind(entity)

        # If User object, need to remove unique properties from unique model
        if entity_kind is 'User':
            entity.remove_unique_properties(entity)

        # If vote, need to decrement vote on subject object
        if entity_kind is 'Vote':
            if entity.practice_id:
                practice_id = entity.practice_id
                practice = Practice.get_by_id(practice_id)
                if practice is not None:
                    practice.votes_for -= 1
                    practice.put()
            if entity.lesson_id:
                lesson_id = entity.lesson_id
                lesson = Lesson.get_by_id(lesson_id)
                if lesson is not None:
                    lesson.votes_for -= 1
                    lesson.put()
Esempio n. 11
0
    def get_practices(self, id):
        user_key = Model.id_to_key(id)
        query = Practice.query(ancestor=user_key).filter(
            Practice.deleted == False).order(-Practice.created)
        # If no user, or not your profile, don't show unlisted
        if not self.api.user or id != self.api.user.uid:
            query = query.filter(Practice.listed == True)

        # Pagination
        n = 20
        params = self.get_params()
        if 'page' in params:
            offset = int(params['page']) * n
        else:
            offset = 0

        self.write(query.fetch(n, offset=offset))
Esempio n. 12
0
    def _annotate_search_content(self, result_dicts):
        """Add data re: content authors and current user to search results."""

        # Content authors

        content_keys = [Model.id_to_key(d['uid']) for d in result_dicts]
        parent_ids = [k.parent().id() for k in content_keys if k.parent()]
        # A single datastore read for all parents.
        parents = self.get_by_id(parent_ids) or []

        # Votes and comments by the current user (who may not be signed in).

        if self.user:
            users_votes_for = self.get('Vote', ancestor=self.user)
            content_user_voted_for = ([v.lesson_id for v in users_votes_for] +
                                      [v.practice_id for v in users_votes_for])
            users_comments = self.get('Comment', ancestor=self.user)
            content_user_commented = ([c.lesson_id for c in users_comments] +
                                      [c.practice_id for c in users_comments])
        else:
            # The user is not signed in.
            content_user_voted_for = []
            content_user_commented = []

        # Loop through search results and modify.

        for d in result_dicts:
            # Find and add content authors.
            for p in parents:
                # I don't love this way of testing if a user is a parent of a
                # given content entity, b/c it relies on our uid conventions,
                # but it's awfully convenient.
                if p.uid in d['uid']:
                    d['user'] = p.to_client_dict()
            # Check if the current user voted for or commented on this.
            if d['uid'] in content_user_voted_for:
                d['user_voted_for'] = True
            if d['uid'] in content_user_commented:
                d['user_commented_on'] = True

            # Add in short_uid if not
            if 'short_uid' not in d:
                d['short_uid'] = Practice.convert_uid(d['uid'])

        return result_dicts
Esempio n. 13
0
    def get(self, practice_id=None):
        user = self.get_current_user()

        if user is None:
            self.redirect('/search')
            return

        # Check if user is practice creator or admin
        if not user.is_admin and practice_id:
            practice = self.api.get_by_id(Practice.get_long_uid(practice_id))
            creator = practice.key.parent().get()
            if creator is not user:
                self.redirect('/practices/{}'.format(practice_id))

        self.write(
            'practice-upload.html',
            practice_id=practice_id,
        )
Esempio n. 14
0
 def get(self, id=None):
     # convert short_uid to uid if needed
     if id is not None:
         id = Practice.get_long_uid(id)
         response = self.api.get_by_id(id)
     else:
         params = self.get_params()
         practices = self.api.get('Practice', **params)
         user_ids = [p.uid.split('.')[1] for p in practices]
         response = []
         users = self.api.get_by_id(user_ids)
         for p in practices:
             for user in users:
                 if user.uid == p.uid.split('.')[1]:
                     practice_dict = p.to_client_dict()
                     practice_dict['user'] = user.to_client_dict()
                     response.append(practice_dict)
                     break
     self.write(response)
Esempio n. 15
0
    def post(self):
        self.response.headers['Content-Type'] = (
            'application/json; charset=utf-8')

        practice = Practice.get_by_id(self.request.get('practice_id'))

        # list of FileInfo objects
        # https://cloud.google.com/appengine/docs/python/blobstore/fileinfoclass
        file_infos = self.get_file_infos()

        # Interesting properties of each FileInfo are:
        props = [
            'content_type', 'creation', 'filename', 'size', 'md5_hash',
            'gs_object_name'
        ]
        file_dicts = [{k: getattr(f, k) for k in props} for f in file_infos]

        #   Build the file's download link, which will need information on the
        # bucket, user, and GCS object for later retreival of actual content.
        # We'll also need the practice id, which is where we'll store the file
        # name of the object as we want users to receive it (we haven't figured
        # out how to make GCS store human-readable filenames).
        #   But we can leave out some of that. Since the user is part of the
        # practice id, and the bucket is determined by the environment, we
        # really just need practice and object name.
        for f in file_dicts:
            gs_pattern = r'^/gs/(?P<bucket>.+)/(?P<user>.+)/(?P<object>.+)$'
            m = re.match(gs_pattern, f['gs_object_name'])
            f['link'] = ('/api/files/{}/{}/{}'.format(m.group('user'),
                                                      practice.uid,
                                                      m.group('object')))

        # Save the file meta data to the practice object as a JSON field.
        practice.add_file_data(file_dicts)
        practice.put()

        self.response.write(
            json.dumps({
                'error': False,
                'data': practice.to_client_dict()
            }))
Esempio n. 16
0
    def get(self, topic_id, lesson_id):
        full_lesson_id = Lesson.get_long_uid(lesson_id)
        lesson = self.api.get_by_id(full_lesson_id)

        full_topic_id = Topic.get_long_uid(topic_id)
        topic = self.api.get_by_id(full_topic_id)

        # check all content objects were found
        if not (lesson is None or topic is None):

            # Increment view counts on the lesson
            view_counter.increment(full_lesson_id)
            view_counter.increment('{}:{}'.format(full_topic_id,
                                                  full_lesson_id))

            theme = self.api.get_by_id(topic.themes[0])
            # Determines if current theme is for Teachers or not
            # 'teacher_theme' variable affects the UI
            teacher_theme = (theme.short_uid
                             in ['growth-mindset', 'growth-mindset-teachers'])

            # Get related practices
            related_practices = Practice.get_related_practices(topic, 4)

            # get other lessons in topic for navigating
            lessons = []
            # first check for bad topic--lesson match
            if topic.lessons:
                lessons = self.api.get_by_id(topic.lessons)

                # get lesson index and previous and next lessons
                lesson_index = 0
                if lesson.uid in topic.lessons:
                    lesson_index = topic.lessons.index(lesson.uid)

                next_topic = ''
                related_topics = []

                # get next lesson from current or next topic
                next_lesson = ''
                next_lesson_url = ''
                next_url = ''
                if lesson_index < len(lessons) - 1:
                    next_lesson = lessons[lesson_index + 1]
                    next_lesson_url = '/topics/{}/{}'.format(
                        topic.short_uid, next_lesson.short_uid)
                    next_url = next_lesson_url
                else:
                    # fetch next topic for final lesson
                    topic_index = 0
                    if topic.uid in theme.topics:
                        topic_index = theme.topics.index(topic.uid)
                    if topic_index < len(theme.topics) - 1:
                        next_topic = self.api.get_by_id(
                            theme.topics[topic_index + 1])
                        next_url = '/topics/{}'.format(next_topic.short_uid)

                    # get list of 3 other topics
                    related_topic_ids = []
                    for idx, val in enumerate(theme.topics):
                        if next_topic:
                            if val != topic.uid and val != next_topic.uid:
                                related_topic_ids.append(val)
                        elif val != topic.uid:
                            related_topic_ids.append(val)
                    if related_topic_ids:
                        related_topics = self.api.get_by_id(related_topic_ids)
                        if len(related_topics) >= 3:
                            related_topics = random.sample(related_topics, 3)

            # All topic lessons use default locale
            locale = config.default_locale

            if os.path.isfile('templates/lessons/' + lesson.short_uid +
                              '.html'):
                self.write(
                    '/lessons/{}.html'.format(lesson.short_uid),
                    theme=theme,
                    teacher_theme=teacher_theme,
                    topic=topic,
                    lesson=lesson,
                    lessons=lessons,
                    lesson_index=lesson_index,
                    next_lesson=next_lesson,
                    next_lesson_url=next_lesson_url,
                    next_url=next_url,
                    next_topic=next_topic,
                    color=topic.color,
                    related_topics=related_topics,
                    related_practices=related_practices,
                    locale=locale,
                    translation=locales.translations[locale]["lessons"],
                )
            else:
                # 404 if lesson html cannot be found
                return self.http_not_found()

        else:
            # 404 if lesson cannot be found
            return self.http_not_found()
Esempio n. 17
0
 def get_popular(self):
     practices = Practice.get_popular_practices()
     self.write(practices)