Forum Poster

So after playing around with posting to a discussion for the Spam Checker I decided to make this:

It is a simple application that loads the discussions and lets you select one and post a message to it. I’m not sure that it has any value considering the forums work much better but it was fun to make. Enjoy!

--# Main
--The name of the project must match your Codea project name if dependencies are used. 
--Project: Forum Poster
--Version: Alpha 1.1
--Comments:

-- Forum Poster

-- Use this function to perform your initial setup
function setup()
    mainUrl = "http://www.twolivesleft.com"
    forumUrl = "/Codea/Talk/"
    discussionsUrl = "/Codea/Talk/discussions/p"
    discussionUrl = "/Codea/Talk/discussion/"
    signinUrl = "/Codea/Talk/entry/signin"
    
    page = 1
    
    discussions = {}
    
    discussionViewer = DiscussionViewer()
    
    getDiscussions()
end

function getDiscussions()
    http.request(mainUrl..discussionsUrl..page, gotDiscussions, failed)
end

function gotDiscussions(data, status, headers)
    sound(SOUND_PICKUP, 36339) 
    --saveProjectTab("Data2", "--[[\
"..data.."\
--]]")
    parseDataForDiscussions(data)
end

function parseDataForDiscussions(d)
    for u in d:gmatch('<a href="/Codea/Talk/discussion/(.-)"') do
        local l = string.sub(u, u:len()-10)
        local c = l..'" class="Title">(.-)</a>'   
        local t = d:match(c) or ""
        
        print("Url: "..u.."\
Title: ", t)
        table.insert(discussions, {url = u, title = t})
    end
    
    local s = d:match('<input type="hidden" id="SignedIn" value="(.-)" />')
    
    parsedDiscussions(s)
end

function parsedDiscussions(signedIn)
    output.clear()
    parameter.clear()
    if signedIn == "1" then
        local l = loadedDiscussion or 1
        parameter.integer("loadedDiscussion", 1, #discussions, l, updateViewer)
        parameter.watch("discussions[loadedDiscussion].title")
        parameter.text("textToPost", "")
        parameter.action("Post It", getPostData)
        parameter.action("Open It", openDiscussion)
        parameter.action("Load Next Page Of Discussions", loadNextPage)
    else
        print("You Must Be Signed Into the Forums to Use The Forum Poster!")
        parameter.text("username", "")
        parameter.text("password", "")
        parameter.action("Sign In", getSignInData)
    end
end

function getSignInData()
    local url = mainUrl..signinUrl
    local u, p = username, password
    http.request(url, function(d,s,h) gotSignInData(d,u,p,s,h) end, signInFailure)
end

function gotSignInData(data, user, pass, status, headers)
    local transientKey
    for i in data:gmatch('name="Form/TransientKey" value="(.-)"') do
        print("Key:",i)
        transientKey = i
    end
    
    signIn(user, pass, transientKey)
end

function signIn(user, pass, key)
    local URL = mainUrl..signinUrl
    
    local headers = { }
    headers["Accept"] = "text/plain"
    headers["Content-Type"] = "application/x-www-form-urlencoded"
    headers["Accept-Charset"] = "utf-8"
    
    local data = "Form%2FTransientKey="..key.."&Form%2Fhpt=&Form%2FTarget=%2F&Form%2FClientHour=2013-10-26+12%3A8&Form%2FEmail="..user.."&Form%2FPassword="..pass.."&Form%2FSign_In=Sign+In&Form%2FRememberMe=1&Checkboxes%5B%5D=RememberMe&DeliveryType=VIEW&DeliveryMethod=JSON"
    
    print("Signing in as:", user)
    
    http.request(URL, signInSuccess, signInFailure, {method="POST", headers=headers,data=data})
end

function signInSuccess()
    print("Succesfully Signed In!")
    print("Loading discussions...")
    getDiscussions()
end

function signInFailure(err)
    print("Failed to sign in. Error:", err)
end

function updateViewer()
    discussionViewer:loadDiscussionData(discussions[loadedDiscussion].url)
end

function loadNextPage()
    page = page + 1
    getDiscussions()
end

function getPostData()
    local url = mainUrl..discussionUrl..discussions[loadedDiscussion].url
    local msg = string.gsub(textToPost, "@", "@")
    http.request(url, function(d,s,h) gotPostData(d,msg,s,h) end, postFailure)
end

function gotPostData(data, msg, status, headers)
    local lastCommentNum = nil
    for i in data:gmatch('"Comment_(.-)"') do
        if lastCommentNum == nil or (tonumber(i) ~= nil and tonumber(i) > lastCommentNum) then
            lastCommentNum = tonumber(i)
        end
    end
    
    local commentKey
    for i in data:gmatch('TransientKey=(.-)"') do
        print("Key:",i)
        commentKey = i
    end
    
    local lcn = lastCommentNum or 1
    postText(msg, lcn, commentKey)
end

function postText(m, num, key)
    local id = string.match(discussions[loadedDiscussion].url, "(.-)/")
    local URL = "http://twolivesleft.com/Codea/Talk/vanilla/post/comment/"..id.."/"
    
    local headers = { }
    headers["Accept"] = "text/plain"
    headers["Content-Type"] = "application/x-www-form-urlencoded"
    headers["Accept-Charset"] = "utf-8"
    
    local message = m or ""
    
    local data = "Comment%2FTransientKey="..key.."&Comment%2Fhpt=&Comment%2FDiscussionID="..id.."&Comment%2FCommentID=&Comment%2FDraftID=&Comment%2FBody="..message.."&DeliveryType=VIEW&DeliveryMethodJSON&Type=Post&Comment%2FLastCommentID="..num
    
    print("Posting: '"..message.."'", "\
To: "..discussions[loadedDiscussion].title)
    
    http.request(URL, postSuccess, postFailure, {method="POST", headers=headers,data=data})
end

function postSuccess()
    print("Posting Was Successful")
end

function postFailure(err)
    print("Posting Failed. Error:", err)
end

function failed(err)
    print("An Error Occured:", err)
end

function openDiscussion()
    openURL(mainUrl..discussionUrl..discussions[loadedDiscussion].url, true)
end

function failed()
    print("Failed")
end

-- This function gets called once every frame
function draw()
    background(40, 40, 50)
    
    font("HelveticaNeue-Light")
    fill(255, 255, 255, 255)
    
    if discussions ~= nil and loadedDiscussion ~= nil then
        discussionViewer:draw(discussions[loadedDiscussion])
    end
end


--# DiscussionViewer
DiscussionViewer = class()

function DiscussionViewer:init()
    
end

function DiscussionViewer:loadDiscussionData(url)
    local fullUrl = mainUrl..discussionUrl..url
    http.request(fullUrl, function(d,s,h) self:gotDiscussionData(d,s,h) end, failed)
end

function DiscussionViewer:gotDiscussionData(data, status, headers)
    --saveProjectTab("Data", "--[[\
"..data.."\
--]]")
end

function DiscussionViewer:draw(d)
    local discussion = d or {url = "", title = ""}
    fontSize(50)
    textMode(CENTER)
    text("Selected Discussion:", WIDTH / 2, HEIGHT * 3/4)
    fontSize(25)
    textMode(CORNER) textWrapWidth(WIDTH)
    text("URL: "..discussion.url, 20, HEIGHT/2)
    text("Title: "..discussion.title, 20, HEIGHT/4)
end

function DiscussionViewer:touched(touch)
    -- Codea does not automatically call this method
end

On another note, @Simeon the way it is right now it would be incredibly easy to write a program just like this to spam the forums

New version: Since you must be signed in to post, this new version checks if you are signed in or not. If not, then it asks you to sign in before proceeding.

http://codea.housercompany.com/alpha/index.php?v=788

wrong request :frowning:

i will take a look from CC in my ipad