commit 3a477f8b0f58503d00ab3cb5890e9b423fc6a622
parent 6ef7c0a082c03f65ebfa7c329c5e845029349625
Author: Fredrik <moi@knutsen.co>
Date:   Mon, 29 Oct 2018 17:33:30 +0000
Merge pull request #6 from Demonstrandum/devel
Update to using MongoDB
Diffstat:
8 files changed, 95 insertions(+), 71 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,41 @@
+# gem
+*.gem
+
+# Shh, web stuff
+tmp/
+log/
+
+## System and release files ##
+# OS files
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+*.swp
+*.ini
+
+# Compiled files
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+
+# Packages
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# Debug logs and databases
+*.log
+*.sql
+*.sqlite
diff --git a/Gemfile b/Gemfile
@@ -5,3 +5,4 @@ gem 'rack', '~> 2.0', '>= 2.0.5'
 gem 'rack-ssl', '~> 1.4'
 gem 'sinatra', '~> 2.0', '>= 2.0.1'
 gem 'json'
+gem 'mongo'
diff --git a/Gemfile.lock b/Gemfile.lock
@@ -1,9 +1,12 @@
 GEM
   remote: https://rubygems.org/
   specs:
+    bson (4.3.0)
     daemons (1.2.6)
     eventmachine (1.2.7)
     json (2.1.0)
+    mongo (2.6.2)
+      bson (>= 4.3.0, < 5.0.0)
     mustermann (1.0.3)
     rack (2.0.5)
     rack-protection (2.0.4)
@@ -15,7 +18,6 @@ GEM
       rack (~> 2.0)
       rack-protection (= 2.0.4)
       tilt (~> 2.0)
-    symbolized (0.0.1)
     thin (1.7.2)
       daemons (~> 1.0, >= 1.0.9)
       eventmachine (~> 1.0, >= 1.0.4)
@@ -27,10 +29,10 @@ PLATFORMS
 
 DEPENDENCIES
   json
+  mongo
   rack (~> 2.0, >= 2.0.5)
   rack-ssl (~> 1.4)
   sinatra (~> 2.0, >= 2.0.1)
-  symbolized
   thin
 
 BUNDLED WITH
diff --git a/now.json b/now.json
@@ -1,5 +1,8 @@
 {
   "name": "Veto",
   "alias": "veto.vote",
-  "type": "docker"
+  "type": "docker",
+  "env": {
+    "MONGO_DB": "@mongo_url_secret"
+  }
 }
diff --git a/public/styles.css b/public/styles.css
@@ -217,6 +217,10 @@ h3 {
   border-bottom: 2px solid;
 }
 
+.issues h3 {
+  color: inherit;
+}
+
 .issues .show {
   max-height: 300px;
   opacity: 1;
@@ -225,7 +229,7 @@ h3 {
 .issues .error {
   background: #ffc8b3;
   border-color: #ff5436;
-  color: #800;
+  color: #800 !important;
 }
 
 .issues .error p {
@@ -236,7 +240,7 @@ h3 {
 .issues .warning {
   background: #ffeab3;
   border-color: #ffc136;
-  color: #885a00;
+  color: #885a00 !important;
 }
 
 .issues .warning p {
diff --git a/server.rb b/server.rb
@@ -1,4 +1,4 @@
-require 'net/http'
+require 'mongo'
 require 'json'
 
 require 'sinatra'
@@ -11,57 +11,24 @@ enable :sessions
 
 before { request.path_info.sub! %r{/$}, "" }
 
-$INDIFFERENT = proc do |h, k|
-  case k
-    when String then sym = k.to_sym; h[sym] if h.key?(sym)
-    when Symbol then str = k.to_s; h[str] if h.key?(str)
-  end
-end
-
-$polls = {
-  :'this-is-a-poll-name' => {
-    :name => 'This is a poll name',
-    :votes => {},
-    :alt => true,
-    :voters => []
-  }
-}  # Example.
-
-$JSON_ID = '1arifg'
-$JSON_BASE = 'https://api.myjson.com'
+# ENV['MONGO_DB'] variable with Now secrets, or just in your shell if local.
+CLIENT = Mongo::Client.new "#{ENV['MONGO_DB']}/Veto"
+POLLS = CLIENT[:polls]
 
-String.class_eval { def to_uri; URI(self); end }
-$polls.default_proc = $INDIFFERENT
-
-def request_json
-  puts "[!!] Requesting JSON, ID: #{$JSON_ID}"
-  response = Net::HTTP.get "#{$JSON_BASE}/bins/#{$JSON_ID}".to_uri
-  $polls = JSON.parse response, {:symbolize_names => true}
-  $polls.default_proc = $INDIFFERENT
-  pp $polls
-end
-
-def save_json
-  puts "[!!] Saving JSON, ID: #{$JSON_ID}"
-  uri = "#{$JSON_BASE}/bins/#{$JSON_ID}".to_uri
-  puts "[!!]\tURI: #{uri}"
-  req = Net::HTTP::Put.new uri
-  req.set_content_type 'application/json'
-  req.body = $polls.to_json
-  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request req }
-  puts "[!!]\tResponse: #{res.inspect}"
+def poll_exist? code
+  POLLS.find({:code => code}).to_a.size > 0
 end
 
-request_json  # Initial JSON retrieval
-
 def make_poll code, name, alt
-  $polls[code] = {
+  alt = alt.to_s == 'true'
+  poll = {
+    :code => code,
     :name => name,
     :votes => {},
     :alt => alt,
     :voters => []
   }
-  save_json
+  POLLS.insert_one poll
 end
 
 $HEAD_TAGS = <<-HTML
@@ -97,7 +64,7 @@ get '/share/:code' do
 end
 
 post '/new' do
-  return nil if $polls.keys.include? params[:code]
+  return nil if poll_exist? params[:code]
 
   make_poll(
     params[:code],
@@ -105,47 +72,45 @@ post '/new' do
     params[:alt])
 
   params[:primary].each do |option|
-    $polls[params[:code]][:votes][option] = {
-      :number => 0,
-      :primary => true
-    }
+    POLLS.update_one({:code => params[:code]}, {
+      :"$set" => {
+        :"votes.#{option}" => {
+          :number => 0,
+          :primary => true
+        }
+      }
+    })
   end
-  save_json
 end
 
 get '/poll/:poll' do
-  unless $polls.keys.map(&:to_s).include? params[:poll]
+  unless poll_exist? params[:poll]
     return "This poll has not been created/does not exist!"
   end
 
   local = {:code => params[:poll], :head_tags => $HEAD_TAGS}
-  local.merge! $polls[params[:poll]]
+  local.merge! Hash.from_bson POLLS.find({:code => params[:poll]}).first.to_bson
   erb :poll, :locals => local
 end
 
 post '/poll/:poll/cast' do
-  return nil if $polls[params[:poll]][:voters].include? request.ip
-  $polls[params[:poll]][:voters].push request.ip
+  return nil if POLLS.find(:"$and" => [{:code => params[:poll]}, {:voters => request.ip}]).to_a.size > 0
+  POLLS.update_one({:code => params[:poll]}, {:"$push" => {:voters => request.ip}})
 
-  if $polls[params[:poll]][:votes].keys.include? params[:vote]
-    $polls[params[:poll]][:votes][params[:vote]][:number] += 1
+  if POLLS.find({ :"votes.#{params[:vote]}" => {"$exists": true} })
+    POLLS.update_one({:code => params[:poll]}, { :"$inc" => { :"votes.#{params[:vote]}.number" => 1 } })
   else
-    $polls[params[:poll]][:votes][params[:vote]] = {
+    POLLS.update_one({:code => params[:poll]}, {:"$set" => {:"vote.#{params[:vote]}" => {
       :number => 1,
       :primary => false
-    }
+    }}})
   end
-  save_json
 end
 
 get '/poll/:poll/votes.json' do
-  $polls[params[:poll]][:votes].to_json
+  (Hash.from_bson POLLS.find({:code => params[:poll]}).to_a.first.to_bson)[:votes].to_json
 end
 
 get '/polls.json' do
-  $polls.keys.map(&:to_s).to_json
-end
-
-get '/exported.json' do
-  $polls.to_json
+  POLLS.find.to_a.map { |doc| doc[:code] }.to_json
 end
diff --git a/server.rb b/server.rb.old
diff --git a/views/index.erb b/views/index.erb
@@ -139,12 +139,20 @@
         }
       });
 
+      $(document).on('keypress', '.editor', key => {
+        if (key.which === 13 || key.which === 10) {
+          key.preventDefault();
+          save();
+          editing = NaN;
+        }
+      });
+
       $("#addition").on('keypress', key => {
         let value = $("#addition").val().trim();
         let values = Array(...$('#options li span').map((i, e) => e.innerHTML));
-        if (key.which === 13) {
-          save();
+        if (key.which === 13 || key.which === 10) {
           key.preventDefault();
+          save();
           if (value.length === 0) {
             return $('#addition').attention();
           }