# -*- coding: utf-8 -*- ''' Created on 2011. 9. 14. @author: Taejun Park ''' from datetime import datetime, timedelta import os import logging from google.appengine.api import memcache from google.appengine.api import users from google.appengine.ext import webapp from google.appengine.ext import db from google.appengine.ext.webapp import template from google.appengine.ext.webapp.util import run_wsgi_app from google.appengine.ext.db import djangoforms #I made import model import getPrograms #not yet attached from django.utils import simplejson as json def userLogging(self): """ Args: self: page handler Returns: Logout(in) URL as a string, 'Login(out)' """ if users.get_current_user(): return users.create_logout_url(self.request.uri), 'Logout' else: return users.create_login_url(self.request.uri), 'Login' def dateChanged(now): """ Args: now : Datetime class Returns: True if changed, False if not it checks wheather correct date was saved in the memcache/Parameter after it works, can use correct date guide """ today = now.date() programGuideDate = memcache.get("programGuideDate") #if memcache is empty if programGuideDate is None: parameter = model.Parameter.get_by_key_name(key_names='day') if parameter is None: #if it is the first run model.Parameter(key_name='day', date=today ).put() if not memcache.add("programGuideDate", today): #save into memcache logging.error("Memcache set failed") return True programGuideDate = parameter.date if not memcache.add("programGuideDate", programGuideDate): logging.error("Memcache set failed") if today > programGuideDate: #if date changed #if now is after 4AM or more than 2days after if now.hour > 4 or today-programGuideDate > timedelta(1): model.Parameter(key_name='day', date=today).put() if not memcache.add("programGuideDate", today): logging.error("Memcache set failed") return True #if not new day or tomorrow before 4am return False def getBroadcastingProgramNow(broadcastingChannel): """ Arg: broadcastingChannel : only KBS1 or KBS2 is supported now Return: ProgramGuide instance in this method, programLists: [program title+datetime] lists program = title+datetime+channel """ now = datetime.now() if dateChanged(now): #if date changed, delete yesterday's program guide db with the same channel db.delete(model.ProgramGuide.gql("WHERE channel = :1", broadcastingChannel)) #getPrograms returns [programtitle,datetime] as a list programLists = getPrograms.getPrograms(broadcastingChannel) #programs is list #parse programLists. the program name was got from KBS hompage so the encoding is euckr for program in programLists: model.ProgramGuide(key_name=program[0].decode('euckr', 'ignore'), programTime=program[1], channel=broadcastingChannel).put() #get if from db to match the type the same programs = model.ProgramGuide.gql("WHERE channel = :1 ORDER BY programTime ASC", broadcastingChannel) if not memcache.add(broadcastingChannel, programs): logging.error("Memcache set failed") else: #check if the time pasts programs = memcache.get(broadcastingChannel) if programs is None: #if memcache is empty, get it from db, add it to the memcache programs = model.ProgramGuide.gql("WHERE channel = :1 ORDER BY programTime ASC", broadcastingChannel) if not memcache.add(broadcastingChannel, programs): logging.error("Memcache set failed") #for ordered for clause. for more information, visit: #http://code.google.com/intl/ko-KR/appengine/docs/python/datastore/queries.html#Query_Cursors start_cursor = memcache.get("program_start_cursor") end_cursor = memcache.get("program_end_cursor") if start_cursor: programs.with_cursor(start_cursor = start_cursor) if end_cursor: programs.with_cursor(end_cursor = end_cursor) for program in programs: if program.programTime > now : #if there's no program matches, it means there's no program now so return "화면조정" if not memcache.add("program_start_cursor", start_cursor): logging.error("Memcache set failed") return program return None class RecentCommentsPage(webapp.RequestHandler): """this class get 30 comments from db and match it for comments.html """ def get(self): url, url_linktext = userLogging(self) comments = model.Comment.all().order('-written_datetime').fetch(30) username = users.get_current_user() template_values={ 'username':username, 'url':url, 'url_linktext':url_linktext, 'comments':comments, } path=os.path.join(os.path.dirname(__file__), 'comments.html') self.response.out.write(template.render(path, template_values)) class MainPage(webapp.RequestHandler): """get which channel user want. then get what program is running now. get comments for the program send them to index.html """ def get(self): #because there are not enough webpages, this program can only run over the KBSs. if self.request.path == '/2tv': channel = 'KBS2' else: channel = 'KBS1' #get what program is running. probramNow programGuide Instance programNow=getBroadcastingProgramNow(channel) if programNow is not None: programInstance = model.Program.get_or_insert(key_name=programNow.key().name(), channel=channel) comments = model.Comment.gql("WHERE program = :program ORDER BY written_datetime DESC", program=programInstance).fetch(5) program = programNow.key().name() else: comments = None program = None #make user signing up url url, url_linktext = userLogging(self) #HTML forms for POST form = ApplyingForm() username = users.get_current_user() template_values={ 'channel':channel, 'head_title': '프로그램 목록', 'page_title': 'TV 프로그램 댓글', 'program': program, 'username': username, 'url':url, 'url_linktext':url_linktext, 'form': form, 'comments': comments } path=os.path.join(os.path.dirname(__file__), 'index.html') self.response.out.write(template.render(path, template_values)) #see http://code.google.com/intl/ko-KR/appengine/articles/djangoforms.html def post(self): #get POST requests data = ApplyingForm(data=self.request.POST) if data.is_valid(): entity=data.save(commit=False) #get commenter: now this program saves email address of current user entity.commenter = users.get_current_user().email() entity.written_datetime =datetime.now() entity.written_via = 'replyingTV' #later would be another platform #get program name from the web page, and get the model reference matches #first from the memcache, sencond from the db programNow = self.request.get('program') programInstance = memcache.get(programNow) if not programInstance: programInstance = model.Program.get_by_key_name(programNow) entity.program = programInstance try: entity.put() #save except : print "don't type that long, plz less than 500 bytes" finally: #redirect it to 2tv if it was from 2tv if self.request.get('channel') == 'KBS2': self.redirect('/2tv', permenent=True) self.redirect('') else: #redirect it to 2tv if it was from 2tv if self.request.get('channel') == 'KBS2': self.redirect('/2tv', permenent=True) self.redirect('') class ApplyingForm(djangoforms.ModelForm): """this class makes form for the Comment model see http://code.google.com/intl/ko-KR/appengine/articles/djangoforms.html """ class Meta: model = model.Comment exclude=['commenter', 'written_datetime', 'program', 'written_via'] class TextPage(webapp.RequestHandler): """link to the replyingtv-program guide page """ def get(self): self.redirect("http://tj850413.blogspot.com/", permanent=True) def main(): application = webapp.WSGIApplication([ ('/about', TextPage), ('/2tv', MainPage), ('/comment', RecentCommentsPage), ('/.*', MainPage), ], debug=True) run_wsgi_app(application) if __name__ == '__main__': main()
시간에 쫓겨 만들다보니 생각하던 것 보단 지저분한 코드가 나왔는데요, 하나하나 살펴보겠습니다.
def userLogging(self) - 앱엔진에서 제공하는 구글 id 로그인 모듈입니다. self클래스를 받아 로그인url과 문자열 login/logout을 리턴합니다. url은 나중에 index.html에서 로그인 url로써 쓰이고, 문자열login/logout은 역시 index.html에서 링크를 나타낼 때 쓰일 문자열입니다.
def dateChanged(now) - datetime인 now를 입력받아 편성표의 날짜가 바뀌었으면 True, 아니면 False를 리턴합니다.
def getBroadcastingProgramNow(broadcastingChannel) - broadCastingChannel을 입력받아 현재 채널의 방송중인 프로그램을 찾아 ProgramGuide 인스턴스를 리턴해줍니다.
class RecentCommentsPage(webapp.RequestHandler) - /comment 페이지의get메시지를 처리해줍니다. 코멘트를 위한 gql query를 보낸 후 최근의 30개만 보여줍니다.
class MainPage(webapp.RequestHandler) - 루트 페이지로 들어오는 get 및 post를 처리해줍니다. get 함수에선 Program 인스턴스를 등록해줍니다. post함수에선 html을 통해 들어온 새로운 comment를 등록해줍니다.
class ApplyingForm(djangoforms.ModelForm) - 장고의 모델폼을 상속하여, 폼을 등록하는데 사용하는 클래스입니다.
class TextPage(webapp.RequestHandler) - 이 블로그로 redirect해주는 클래스입니다.
def main() - WSGIApplication으로 각각의 페이지들을 유도해줍니다.




