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()
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)
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()
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'
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()
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)
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()
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
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' }))
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()
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))
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
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, )
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)
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() }))
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()
def get_popular(self): practices = Practice.get_popular_practices() self.write(practices)