0

I am noobie to app engine, and am working on adding a simple chat feature to a boilerplate (https://github.com/coto/gae-boilerplate). The chat application works fine on its own but when I try to add it to the boilerplate, I am receiving a 405 POST method error when I try to post a chat message to the ChatHandler. The chatscreen.html does initially render from ChatHander with no problem, just when I try to post a chat do I get the error. Thanks for any advice you can give-

Here is the python chat code:

import httpagentparser
from boilerplate import models
from boilerplate.lib.basehandler import BaseHandler
from boilerplate.lib.basehandler import user_required

import cgi
import urllib
import os
import logging
import webapp2
import jinja2

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.api import memcache

class ChatMessage(db.Model):
    user = db.StringProperty()
    text = db.StringProperty()
    created = db.DateTimeProperty(auto_now=True)

class User(db.Model):
    account = db.StringProperty()
    user = db.StringProperty()



class ChatHandler(BaseHandler):
    def get(self, **kwargs):
        params = {
        }
        return self.render_template('chatscreen.html', **params)

    def post(self, **kwargs):
        user = self.request.get('user')
        self.session['user'] = user

        if not 'user' in self.session:
            params = {
            'error' : 'Must be logged in'
            }
            return self.render_template('chatscreen.html', **params) 
            return

        msg = self.request.get('message')
        if msg == '':
           params = {
           'error' : 'Blank message ignored'
           }
           return self.render_template('chatscreen.html', **params)           
           return

        newchat = ChatMessage(user = "temp_user3", text=msg)
        newchat.put(); 
        if newchat.put():
            chat_list = ChatMessage.all().order('-created').fetch(100)  #pulling chat messages to include new ones not yet in memcache 
            memcache.set('chat_list_key', chat_list, time=2000000)       
            logging.info('entry added by user -- memcache & datastore updated with new list')       

        params = {
        }
        return self.render_template('chatscreen.html', **params)    

class MessagesHandler(BaseHandler):            
    def get(self, **kwargs):
        chat_list = memcache.get('chat_list_key')   #checking cache for chat_list    

        # if no chat_list then pull a list from datastore and populate memcache 
        if chat_list is None:
            chat_list = ChatMessage.all().order('-created').fetch(100) 
            memcache.set('chat_list_key', chat_list, time=2000000)
            logging.info('Saving chat_list to memcache *** no messages found')
            params = {
            'chat_list': chat_list
            }
            return self.render_template('messagelist.html', **params) 

        #if chat_list exist then pull data from memcache
        else: 
            params = {
            'chat_list': chat_list
            }
            return self.render_template('messagelist.html', **params)
            logging.info('Got chat_list from cache')    

class MainHandler(BaseHandler):
    def get(self):
        user = self.session.get('user')
        params = {
        'user': user
        }
        return self.render_template('index.html', **params) 

Here is the routing:

from webapp2_extras.routes import RedirectRoute
from web import handlers
secure_scheme = 'https'

_routes = [
    RedirectRoute('/chat/', handlers.ChatHandler, name='chat', strict_slash=True),
    RedirectRoute('/messages/', handlers.MessagesHandler, name='messages', strict_slash=True),
    RedirectRoute('/secure/', handlers.SecureRequestHandler, name='secure', strict_slash=True)
]

def get_routes():
    return _routes

def add_routes(app):
    if app.debug:
        secure_scheme = 'http'
    for r in _routes:
        app.router.add(r)

Here is the chatscreen.html:

{% extends "_base.html" %}
{% block bodycontent %}
      <h1>AppEngine Chat</h1>
      <form method="post" action="/chat">
      <p>
      <input type="text" name="message" size="60"/>
      <input type="submit" value="Chat"/> 
      </p>
      </form>
      {% if not error == None %}
       <p>
       {{ error }} 
       </p>
      {% endif %}
      <div id="chatcontent">
          Loading...
          <!-- <img src="/static/spinning.gif" alt="Loading..."/> -->
      </div>
<script> /* <![CDATA[ */

$(document).ready(function(){
$(function() {

    updateMsg();

});

function updateMsg() {

    $('#chatcontent').load('/messages');
    setTimeout(updateMsg, 5000);

}
});//end doc.onready function
/* ]]> */
</script>
{% endblock %}

And here is messagelist.html:

{% for chat in chat_list %}
  <p>
      <strong>{{ chat.user}}</strong>: 
      <br />  {{ chat.text }} 

  </p> 
{% endfor %}
Matt Ellis
  • 119
  • 1
  • 2
  • 15

2 Answers2

0

Have you checked RedirectRoute to see if it does any handling on POST that might return that error?

EDIT: I took a quick look at gae-boilerplate, it's got extra code in its main.py

routes.add_routes(app)
boilerplate_routes.add_routes(app)
admin_routes.add_routes(app)

The last two functions might be screwing up your routes. I'd recommend not using the boilerplate if you don't know what it's doing.

dragonx
  • 14,752
  • 24
  • 41
  • I can't seem to find anywhere that it would cause a problem with POST, but I do think you are on to something with the idea that routing is messing something up with the strict slash thing. When I change the code to only use Route and take off the trailing slashes in the routing, I get an "Access is denied to resource" error when i try to post a chat message. – Matt Ellis Jun 04 '13 at 18:21
  • I also tried using RedirectRoute with the application OUTSIDE of the boilerplate and it worked when I took the trailing "/" off of the chat routing. So I tried this (removed the slash) inside the boilerplate enviroment with the routing using "RedirectRoute" but getting an "Access is denied to resource" error – Matt Ellis Jun 04 '13 at 21:40
0

I think I figured it out...when pasting this code into the boilerplate, I mistakenly cut off a handler that deals with sessions - I believe this is what was throwing the error.

Matt Ellis
  • 119
  • 1
  • 2
  • 15
  • I have similar problem (POST works when not using gae-boilerplate, but don't work when integrating into gae-b). I found another question, http://stackoverflow.com/questions/13020681/gae-boilerplate-documentation, he said: he has to include a csrf_token in all POST requests. I am not familiar to session control in web, do you know what should I add in my post request handler? – 正宗白布鞋 Jun 07 '13 at 16:34
  • Ok, I find the way. In my case, the function dispatch in basehandler in gae-b, blocks the POST if _csrf_token doesn't match... Referrer to other forms examples in gae-b, and after I add one hidden field in my form, , everything works ok now. – 正宗白布鞋 Jun 07 '13 at 17:50