<s> """<STR_LIT>""" <EOL> import datetime <EOL> from google . appengine . api import datastore_types <EOL> from google . appengine . api import xmpp <EOL> from google . appengine . ext import ndb <EOL> from google . appengine . ext . webapp import xmpp_handlers <EOL> import webapp2 <EOL> from webapp2_extras import jinja2 <EOL> PONDER_MSG = '<STR_LIT>' <EOL> TELLME_MSG = '<STR_LIT>' <EOL> SOMEONE_ANSWERED_MSG = ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> ANSWER_INTRO_MSG = '<STR_LIT>' <EOL> ANSWER_MSG = '<STR_LIT>' <EOL> WAIT_MSG = ( '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> THANKS_MSG = '<STR_LIT>' <EOL> TELLME_THANKS_MSG = THANKS_MSG + '<STR_LIT>' <EOL> EMPTYQ_MSG = '<STR_LIT>' <EOL> HELP_MSG = ( '<STR_LIT>' <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' ) <EOL> MAX_ANSWER_TIME = <NUM_LIT> <EOL> class IMProperty ( ndb . StringProperty ) : <EOL> """<STR_LIT>""" <EOL> def _validate ( self , value ) : <EOL> """<STR_LIT>""" <EOL> if not isinstance ( value , datastore_types . IM ) : <EOL> raise TypeError ( '<STR_LIT>' . format ( value ) ) <EOL> def _to_base_type ( self , value ) : <EOL> """<STR_LIT>""" <EOL> return str ( value ) <EOL> def _from_base_type ( self , value ) : <EOL> """<STR_LIT>""" <EOL> return datastore_types . IM ( value ) <EOL> class Question ( ndb . Model ) : <EOL> """<STR_LIT>""" <EOL> question = ndb . TextProperty ( required = True ) <EOL> asker = IMProperty ( required = True ) <EOL> asked = ndb . DateTimeProperty ( required = True , auto_now_add = True ) <EOL> suspended = ndb . BooleanProperty ( required = True ) <EOL> assignees = IMProperty ( repeated = True ) <EOL> last_assigned = ndb . DateTimeProperty ( ) <EOL> answer = ndb . TextProperty ( indexed = True ) <EOL> answerer = IMProperty ( ) <EOL> answered = ndb . DateTimeProperty ( ) <EOL> @ staticmethod <EOL> @ ndb . transactional <EOL> def _try_assign ( key , user , expiry ) : <EOL> """<STR_LIT>""" <EOL> question = key . get ( ) <EOL> if not question . last_assigned or question . last_assigned < expiry : <EOL> question . assignees . append ( user ) <EOL> question . last_assigned = datetime . datetime . now ( ) <EOL> question . put ( ) <EOL> return question <EOL> @ classmethod <EOL> def assign_question ( cls , user ) : <EOL> """<STR_LIT>""" <EOL> question = None <EOL> while question is None or user not in question . assignees : <EOL> expiry = ( datetime . datetime . now ( ) <EOL> - datetime . timedelta ( seconds = MAX_ANSWER_TIME ) ) <EOL> query = cls . query ( cls . answerer == None , cls . last_assigned < expiry ) <EOL> query = query . order ( cls . last_assigned , cls . asked ) <EOL> candidates = [ candidate for candidate in query . fetch ( <NUM_LIT:2> ) <EOL> if candidate . asker != user ] <EOL> if not candidates : <EOL> break <EOL> question = cls . _try_assign ( candidates [ <NUM_LIT:0> ] . key , user , expiry ) <EOL> return question <EOL> @ ndb . transactional <EOL> def unassign ( self , user ) : <EOL> """<STR_LIT>""" <EOL> question = self . key . get ( ) <EOL> if user in question . assignees : <EOL> question . assignees . remove ( user ) <EOL> question . put ( ) <EOL> @ classmethod <EOL> def get_asked ( cls , user ) : <EOL> """<STR_LIT>""" <EOL> query = cls . query ( cls . asker == user , cls . answer == None ) <EOL> return query . get ( ) <EOL> @ classmethod <EOL> def get_answering ( cls , user ) : <EOL> """<STR_LIT>""" <EOL> query = cls . query ( cls . assignees == user , cls . answer == None ) <EOL> return query . get ( ) <EOL> def bare_jid ( sender ) : <EOL> """<STR_LIT>""" <EOL> return sender . split ( '<STR_LIT:/>' ) [ <NUM_LIT:0> ] <EOL> class XmppHandler ( xmpp_handlers . CommandHandler ) : <EOL> """<STR_LIT>""" <EOL> def unhandled_command ( self , message = None ) : <EOL> """<STR_LIT>""" <EOL> message . reply ( HELP_MSG . format ( self . request . host_url ) ) <EOL> def askme_command ( self , message = None ) : <EOL> """<STR_LIT>""" <EOL> im_from = datastore_types . IM ( '<STR_LIT>' , bare_jid ( message . sender ) ) <EOL> currently_answering = Question . get_answering ( im_from ) <EOL> question = Question . assign_question ( im_from ) <EOL> if question : <EOL> message . reply ( TELLME_MSG . format ( question . question ) ) <EOL> else : <EOL> message . reply ( EMPTYQ_MSG ) <EOL> if currently_answering : <EOL> currently_answering . unassign ( im_from ) <EOL> def text_message ( self , message = None ) : <EOL> """<STR_LIT>""" <EOL> im_from = datastore_types . IM ( '<STR_LIT>' , bare_jid ( message . sender ) ) <EOL> question = Question . get_answering ( im_from ) <EOL> if question : <EOL> other_assignees = question . assignees <EOL> other_assignees . remove ( im_from ) <EOL> question . answer = message . arg <EOL> question . answerer = im_from <EOL> question . assignees = [ ] <EOL> question . answered = datetime . datetime . now ( ) <EOL> question . put ( ) <EOL> xmpp . send_message ( [ question . asker . address ] , <EOL> ANSWER_INTRO_MSG . format ( question . question ) ) <EOL> xmpp . send_message ( [ question . asker . address ] , <EOL> ANSWER_MSG . format ( message . arg ) ) <EOL> asked_question = Question . get_asked ( im_from ) <EOL> if asked_question : <EOL> message . reply ( TELLME_THANKS_MSG ) <EOL> else : <EOL> message . reply ( THANKS_MSG ) <EOL> if other_assignees : <EOL> xmpp . send_message ( [ user . address for user in other_assignees ] , <EOL> SOMEONE_ANSWERED_MSG ) <EOL> else : <EOL> self . unhandled_command ( message ) <EOL> def tellme_command ( self , message = None ) : <EOL> """<STR_LIT>""" <EOL> im_from = datastore_types . IM ( '<STR_LIT>' , bare_jid ( message . sender ) ) <EOL> asked_question = Question . get_asked ( im_from ) <EOL> if asked_question : <EOL> message . reply ( WAIT_MSG ) <EOL> else : <EOL> asked_question = Question ( question = message . arg , asker = im_from ) <EOL> asked_question . put ( ) <EOL> currently_answering = Question . get_answering ( im_from ) <EOL> if not currently_answering : <EOL> question = Question . assign_question ( im_from ) <EOL> if question : <EOL> message . reply ( TELLME_MSG . format ( question . question ) ) <EOL> return <EOL> message . reply ( PONDER_MSG ) <EOL> class XmppPresenceHandler ( webapp2 . RequestHandler ) : <EOL> """<STR_LIT>""" <EOL> def post ( self , status ) : <EOL> """<STR_LIT>""" <EOL> sender = self . request . get ( '<STR_LIT>' ) <EOL> im_from = datastore_types . IM ( '<STR_LIT>' , bare_jid ( sender ) ) <EOL> suspend = ( status == '<STR_LIT>' ) <EOL> query = Question . query ( Question . asker == im_from , <EOL> Question . answer == None , <EOL> Question . suspended == ( not suspend ) ) <EOL> question = query . get ( ) <EOL> if question : <EOL> question . suspended = suspend <EOL> question . put ( ) <EOL> class LatestHandler ( webapp2 . RequestHandler ) : <EOL> """<STR_LIT>""" <EOL> @ webapp2 . cached_property <EOL> def jinja2 ( self ) : <EOL> """<STR_LIT>""" <EOL> return jinja2 . get_jinja2 ( app = self . app ) <EOL> def render_response ( self , template , ** context ) : <EOL> """<STR_LIT>""" <EOL> rendered_value = self . jinja2 . render_template ( template , ** context ) <EOL> self . response . write ( rendered_value ) <EOL> def get ( self ) : <EOL> """<STR_LIT>""" <EOL> query = Question . query ( Question . answered > None ) . order ( <EOL> - Question . answered ) <EOL> self . render_response ( '<STR_LIT>' , questions = query . fetch ( <NUM_LIT:20> ) ) <EOL> APPLICATION = webapp2 . WSGIApplication ( [ <EOL> ( '<STR_LIT:/>' , LatestHandler ) , <EOL> ( '<STR_LIT>' , XmppHandler ) , <EOL> ( '<STR_LIT>' , XmppPresenceHandler ) , <EOL> ] , debug = True ) </s>
