Compare commits
No commits in common. "master" and "v1.2" have entirely different histories.
167
server.rb
167
server.rb
|
@ -7,6 +7,8 @@ require "sinatra"
|
||||||
require "json"
|
require "json"
|
||||||
require_relative "sql"
|
require_relative "sql"
|
||||||
|
|
||||||
|
set :bind, '0.0.0.0'
|
||||||
|
|
||||||
class String
|
class String
|
||||||
def escape
|
def escape
|
||||||
self.gsub("&", "&").gsub("<", "<").gsub("\"", """)
|
self.gsub("&", "&").gsub("<", "<").gsub("\"", """)
|
||||||
|
@ -16,7 +18,34 @@ end
|
||||||
get "/" do
|
get "/" do
|
||||||
@title = PROJECT_DISPLAYNAME
|
@title = PROJECT_DISPLAYNAME
|
||||||
@description = "Ask questions, copy link, get answers. Powered by Ruby, Sinatra and SQLite."
|
@description = "Ask questions, copy link, get answers. Powered by Ruby, Sinatra and SQLite."
|
||||||
erb :home
|
erb <<~BODY
|
||||||
|
<form id="f_question" action="/q" method="post"><div class="formdiv">
|
||||||
|
<input type="text" name="q_text" style="width: 100%; margin-bottom: 1em;" placeholder="Question"/>
|
||||||
|
<textarea name="q_options" style="width: 100%; height: 200px;" placeholder="Add answers here, one per line"></textarea>
|
||||||
|
<input type="submit" class="submit-main" value="Submit"/>
|
||||||
|
</div></form>
|
||||||
|
<h1>simplePoll</h1>
|
||||||
|
<p>simplePoll is a simple poll service powered by Ruby, Sinatra and SQLite. Static files are loaded into memory to improve performance. Using advanced IP address technology, users can only submit one answer for polls.</p>
|
||||||
|
<p>simplePoll also offers a simple API for poll information in JSON format:</p>
|
||||||
|
<pre>
|
||||||
|
/api/<question_id> => {
|
||||||
|
"id": question_id,
|
||||||
|
"text": "Question text",
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"id": answer_id,
|
||||||
|
"text": "Answer 1",
|
||||||
|
"count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": answer_id,
|
||||||
|
"text": "Answer 2"
|
||||||
|
"count": 37547821
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
BODY
|
||||||
end
|
end
|
||||||
|
|
||||||
get "/style.css" do
|
get "/style.css" do
|
||||||
|
@ -24,6 +53,14 @@ get "/style.css" do
|
||||||
erb :style, layout: false
|
erb :style, layout: false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
get "/error" do
|
||||||
|
raise Exception.new("OH NOES")
|
||||||
|
end
|
||||||
|
|
||||||
|
get "/secret" do
|
||||||
|
403
|
||||||
|
end
|
||||||
|
|
||||||
post "/q" do
|
post "/q" do
|
||||||
text = params[:q_text]
|
text = params[:q_text]
|
||||||
options_raw = params[:q_options]
|
options_raw = params[:q_options]
|
||||||
|
@ -31,15 +68,27 @@ post "/q" do
|
||||||
if not text or not options_raw then
|
if not text or not options_raw then
|
||||||
status 400
|
status 400
|
||||||
@title = "Invalid input"
|
@title = "Invalid input"
|
||||||
erb :question_invalid
|
erb <<~BODY
|
||||||
|
<h1>Invalid input</h1>
|
||||||
|
<p>Missing POST data</p>
|
||||||
|
<a onclick="history.back();" class="button"><< Try again</a>
|
||||||
|
BODY
|
||||||
elsif text.size < 10 then
|
elsif text.size < 10 then
|
||||||
status 400
|
status 400
|
||||||
@title = "Invalid input"
|
@title = "Invalid input"
|
||||||
erb :question_short
|
erb <<~BODY
|
||||||
|
<h1>Invalid input</h1>
|
||||||
|
<p>Question too short</p>
|
||||||
|
<a onclick="history.back();" class="button"><< Try again</a>
|
||||||
|
BODY
|
||||||
elsif options.size < 2 then
|
elsif options.size < 2 then
|
||||||
status 400
|
status 400
|
||||||
@title = "Invalid input"
|
@title = "Invalid input"
|
||||||
erb :question_noanswers
|
erb <<~BODY
|
||||||
|
<h1>Invalid input</h1>
|
||||||
|
<p>At least 2 answers required</p>
|
||||||
|
<a onclick="history.back();" class="button"><< Try again</a>
|
||||||
|
BODY
|
||||||
else
|
else
|
||||||
q = new_question(text, options)
|
q = new_question(text, options)
|
||||||
puts("Question #{q.id} created by #{request.ip.inspect}")
|
puts("Question #{q.id} created by #{request.ip.inspect}")
|
||||||
|
@ -96,19 +145,7 @@ get %r{/q/([0-9]+)/delete} do |id|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get %r{/q/([0-9]+)/answer} do |id|
|
get %r{/q/([0-9]+)$} do |id|
|
||||||
if question_exists? id.to_i then
|
|
||||||
if params["answer"] then
|
|
||||||
puts("Trying to submit answer for #{request.ip.inspect}")
|
|
||||||
Question.new(id.to_i).add_answer(request.ip, params["answer"])
|
|
||||||
end
|
|
||||||
redirect to "/q/#{id}"
|
|
||||||
else
|
|
||||||
404
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
get %r{/q/([0-9]+)} do |id|
|
|
||||||
if question_exists? id.to_i then
|
if question_exists? id.to_i then
|
||||||
@q = Question.new(id.to_i)
|
@q = Question.new(id.to_i)
|
||||||
@qdata = @q.summary
|
@qdata = @q.summary
|
||||||
|
@ -124,7 +161,36 @@ get %r{/q/([0-9]+)} do |id|
|
||||||
else
|
else
|
||||||
@delete_code = ""
|
@delete_code = ""
|
||||||
end
|
end
|
||||||
erb :answer_form
|
erb <<~BODY
|
||||||
|
<form id="f_answer" action="/q/<%=@qdata[:id]%>/answer"><div class="formdiv">
|
||||||
|
<strong><%=@qdata[:text].escape%></strong>
|
||||||
|
<ul id="q_options"><% for opt in @qdata[:options] do %>
|
||||||
|
<li class="q_option">
|
||||||
|
<input type="radio" required id="radio<%= opt[:id] %>" name="answer" value="<%= opt[:id] %>"/><label for="radio<%= opt[:id] %>"><%= opt[:text].escape %></label><span style="float: right;"><%= opt[:count] %></span><br/>
|
||||||
|
<div class="q_answer_bar">
|
||||||
|
<div style="width: <%= @answer_count > 0 ? (opt[:count] / @answer_count.to_f)*100 : 0 %>%;"></div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<% end %></ul>
|
||||||
|
<input type="submit" class="submit-main" value="Submit answer"/>
|
||||||
|
</div></form>
|
||||||
|
<form id="f_delete" action="/q/<%=@qdata[:id]%>/delete"><div class="formdiv">
|
||||||
|
<input type="text" size="32" name="code" placeholder="Code" value="#{@delete_code}"/>
|
||||||
|
<input type="submit" class="submit-delete" value="Delete"/>
|
||||||
|
</div></form>
|
||||||
|
BODY
|
||||||
|
else
|
||||||
|
404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
get %r{/q/([0-9]+)/answer} do |id|
|
||||||
|
if question_exists? id.to_i then
|
||||||
|
if params["answer"] then
|
||||||
|
puts("Trying to submit answer for #{request.ip.inspect}")
|
||||||
|
Question.new(id.to_i).add_answer(request.ip, params["answer"])
|
||||||
|
end
|
||||||
|
redirect to "/q/#{id}"
|
||||||
else
|
else
|
||||||
404
|
404
|
||||||
end
|
end
|
||||||
|
@ -333,7 +399,7 @@ a.button:hover {
|
||||||
|
|
||||||
@@ e403
|
@@ e403
|
||||||
<h1>403 Forbidden</h1>
|
<h1>403 Forbidden</h1>
|
||||||
<p>You do not have access to the requested location.</p>
|
<p>You're doing this to yourself. Stop.</p>
|
||||||
|
|
||||||
@@ notfound
|
@@ notfound
|
||||||
<h1>404 Not Found</h1>
|
<h1>404 Not Found</h1>
|
||||||
|
@ -341,67 +407,6 @@ a.button:hover {
|
||||||
|
|
||||||
@@ e500
|
@@ e500
|
||||||
<h1>500 Internal Server Error</h1>
|
<h1>500 Internal Server Error</h1>
|
||||||
<p>The server has encountered an error while processing your request.</p>
|
<p>This shouldn't've happened.</p>
|
||||||
<p style="font-size: 50%;"><%= env["sinatra.error"].message %></p>
|
<p style="font-size: 50%;"><%= env["sinatra.error"].message %></p>
|
||||||
|
|
||||||
@@ question_invalid
|
|
||||||
<h1>Invalid input</h1>
|
|
||||||
<p>Missing POST data</p>
|
|
||||||
<a onclick="history.back();" class="button"><< Try again</a>
|
|
||||||
|
|
||||||
@@ question_short
|
|
||||||
<h1>Invalid input</h1>
|
|
||||||
<p>Question too short</p>
|
|
||||||
<a onclick="history.back();" class="button"><< Try again</a>
|
|
||||||
|
|
||||||
@@ question_noanswers
|
|
||||||
<h1>Invalid input</h1>
|
|
||||||
<p>At least 2 answers required</p>
|
|
||||||
<a onclick="history.back();" class="button"><< Try again</a>
|
|
||||||
|
|
||||||
@@ home
|
|
||||||
<form id="f_question" action="/q" method="post"><div class="formdiv">
|
|
||||||
<input type="text" name="q_text" style="width: 100%; margin-bottom: 1em;" placeholder="Question"/>
|
|
||||||
<textarea name="q_options" style="width: 100%; height: 200px;" placeholder="Add answers here, one per line"></textarea>
|
|
||||||
<input type="submit" class="submit-main" value="Submit"/>
|
|
||||||
</div></form>
|
|
||||||
<h1>simplePoll</h1>
|
|
||||||
<p>simplePoll is a simple poll service powered by Ruby, Sinatra and SQLite. Static files are loaded into memory to improve performance. Using advanced IP address technology, users can only submit one answer for polls.</p>
|
|
||||||
<p>simplePoll also offers a simple API for poll information in JSON format:</p>
|
|
||||||
<pre>
|
|
||||||
/api/<question_id> => {
|
|
||||||
"success": true,
|
|
||||||
"id": question_id,
|
|
||||||
"text": "Question text",
|
|
||||||
"answers": [
|
|
||||||
{
|
|
||||||
"id": answer_id,
|
|
||||||
"text": "Answer 1",
|
|
||||||
"count": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": answer_id,
|
|
||||||
"text": "Answer 2"
|
|
||||||
"count": 37547821
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
@@ answer_form
|
|
||||||
<form id="f_answer" action="/q/<%=@qdata[:id]%>/answer"><div class="formdiv">
|
|
||||||
<strong><%=@qdata[:text].escape%></strong>
|
|
||||||
<ul id="q_options"><% for opt in @qdata[:options] do %>
|
|
||||||
<li class="q_option">
|
|
||||||
<input type="radio" required id="radio<%= opt[:id] %>" name="answer" value="<%= opt[:id] %>"/><label for="radio<%= opt[:id] %>"><%= opt[:text].escape %></label><span style="float: right;"><%= opt[:count] %></span><br/>
|
|
||||||
<div class="q_answer_bar">
|
|
||||||
<div style="width: <%= @answer_count > 0 ? (opt[:count] / @answer_count.to_f)*100 : 0 %>%;"></div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<% end %></ul>
|
|
||||||
<input type="submit" class="submit-main" value="Submit answer"/>
|
|
||||||
</div></form>
|
|
||||||
<form id="f_delete" action="/q/<%=@qdata[:id]%>/delete"><div class="formdiv">
|
|
||||||
<input type="text" size="32" name="code" placeholder="Code" value="<%= @delete_code %>"/>
|
|
||||||
<input type="submit" class="submit-delete" value="Delete"/>
|
|
||||||
</div></form>
|
|
||||||
|
|
2
sql.rb
2
sql.rb
|
@ -101,7 +101,7 @@ end
|
||||||
|
|
||||||
def delete_question(id)
|
def delete_question(id)
|
||||||
sql(<<~SQL, [id])
|
sql(<<~SQL, [id])
|
||||||
DELETE FROM q_answers WHERE q_answers.id IN (
|
DELETE FROM q_answers WHERE q_answers.o_id IN (
|
||||||
SELECT q_answers.id FROM q_options WHERE q_answers.o_id = q_options.id AND q_options.q_id = ?1
|
SELECT q_answers.id FROM q_options WHERE q_answers.o_id = q_options.id AND q_options.q_id = ?1
|
||||||
);
|
);
|
||||||
SQL
|
SQL
|
||||||
|
|
Loading…
Reference in New Issue