Browse code
working, basically
fiddlerwoaroof authored on 16/02/2015 06:47:25
Showing 7 changed files
Showing 7 changed files
- .gitignore
- sql/def.sql
- src/config.rb.sample
- src/main.rb
- src/views/comment_form.haml
- src/views/index.haml
- src/views/restaurant.haml
0 | 3 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,107 @@ |
1 |
+-- Data model |
|
2 |
+DROP TABLE reviews; |
|
3 |
+DROP TABLE reviewers; |
|
4 |
+DROP TABLE restaurants; |
|
5 |
+CREATE TABLE restaurants ( |
|
6 |
+ id SERIAL UNIQUE NOT NULL, |
|
7 |
+ restaurant_name TEXT NOT NULL, |
|
8 |
+ short_name TEXT NOT NULL UNIQUE, |
|
9 |
+ PRIMARY KEY (id) |
|
10 |
+); |
|
11 |
+ |
|
12 |
+CREATE TABLE reviewers ( |
|
13 |
+ id SERIAL UNIQUE NOT NULL, |
|
14 |
+ reviewer_name TEXT UNIQUE NOT NULL, |
|
15 |
+ created_date TIMESTAMP, |
|
16 |
+ last_seen TIMESTAMP, |
|
17 |
+ PRIMARY KEY (id) |
|
18 |
+); |
|
19 |
+ |
|
20 |
+CREATE TABLE reviews ( |
|
21 |
+ id SERIAL UNIQUE NOT NULL, |
|
22 |
+ reviewer_id INTEGER REFERENCES reviewers (id) NOT NULL, |
|
23 |
+ restaurant_id INTEGER REFERENCES restaurants (id) NOT NULL, |
|
24 |
+ review_posted TIMESTAMP DEFAULT current_timestamp, |
|
25 |
+ review TEXT NOT NULL, |
|
26 |
+ UNIQUE (reviewer_id, restaurant_id), |
|
27 |
+ PRIMARY KEY (id) |
|
28 |
+); |
|
29 |
+ |
|
30 |
+-- Stored Procedures |
|
31 |
+ |
|
32 |
+CREATE OR REPLACE FUNCTION get_reviews(sn text) |
|
33 |
+ RETURNS TABLE(review text, reviewer text) AS $$ |
|
34 |
+BEGIN |
|
35 |
+ RETURN QUERY SELECT reviews.review, reviewers.reviewer_name |
|
36 |
+ FROM reviews |
|
37 |
+ INNER JOIN reviewers ON reviews.reviewer_id=reviewers.id |
|
38 |
+ INNER JOIN restaurants ON reviews.restaurant_id=restaurants.id |
|
39 |
+ WHERE restaurants.short_name=sn |
|
40 |
+ ORDER BY review_posted DESC, |
|
41 |
+ reviewer_name ASC; |
|
42 |
+END; |
|
43 |
+$$ LANGUAGE plpgsql; |
|
44 |
+ |
|
45 |
+CREATE OR REPLACE FUNCTION put_review(sn text, rn text, review text) |
|
46 |
+ RETURNS VOID AS $$ |
|
47 |
+DECLARE |
|
48 |
+ restaurant_id int; |
|
49 |
+ reviewer_id int; |
|
50 |
+ nowstamp timestamp; |
|
51 |
+BEGIN |
|
52 |
+ SELECT restaurants.id INTO restaurant_id FROM restaurants WHERE restaurants.short_name=sn; |
|
53 |
+ SELECT reviewers.id INTO reviewer_id FROM reviewers WHERE reviewers.reviewer_name=rn; |
|
54 |
+ |
|
55 |
+ WITH new_values (rest_id, rev_id, review, tm) as (values (restaurant_id, reviewer_id, review, current_timestamp)), |
|
56 |
+ upsert as |
|
57 |
+ ( |
|
58 |
+ UPDATE reviews m |
|
59 |
+ SET restaurant_id = nv.rest_id, |
|
60 |
+ reviewer_id = nv.rev_id, |
|
61 |
+ review = nv.review, |
|
62 |
+ review_posted = tm |
|
63 |
+ FROM new_values nv |
|
64 |
+ WHERE m.restaurant_id = nv.rest_id AND m.reviewer_id = nv.rev_id |
|
65 |
+ RETURNING m.* |
|
66 |
+ ) |
|
67 |
+ INSERT INTO reviews (restaurant_id, reviewer_id, review) |
|
68 |
+ SELECT rest_id, rev_id, new_values.review |
|
69 |
+ FROM new_values |
|
70 |
+ WHERE NOT EXISTS (SELECT 1 |
|
71 |
+ FROM upsert up |
|
72 |
+ WHERE up.restaurant_id = new_values.rest_id AND up.reviewer_id = new_values.rev_id); |
|
73 |
+END; |
|
74 |
+$$ LANGUAGE plpgsql; |
|
75 |
+ |
|
76 |
+-- Test Data |
|
77 |
+INSERT INTO restaurants (restaurant_name, short_name) VALUES |
|
78 |
+ ('Vigilante Coffee', 'vigilante-coffee'), |
|
79 |
+ ('The Coffee Bar', 'the-coffee-bar'), |
|
80 |
+ ('Peregrine Espresso', 'peregrine-espresso'), |
|
81 |
+ ('Graffiato', 'graffiato'); |
|
82 |
+ |
|
83 |
+INSERT INTO reviewers (reviewer_name) VALUES |
|
84 |
+ ('the_tooth_fairy'), |
|
85 |
+ ('fiddlerwoaroof'), |
|
86 |
+ ('grandma_johnson'); |
|
87 |
+ |
|
88 |
+INSERT INTO reviews (reviewer_id, restaurant_id, review) VALUES |
|
89 |
+ ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='vigilante-coffee'), 'Great Coffee!'), |
|
90 |
+ ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'), (SELECT id FROM restaurants where short_name='vigilante-coffee'), 'My coffee was cold :/'), |
|
91 |
+ ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='vigilante-coffee'), 'Bad Customer service, will actively avoid!'), |
|
92 |
+ ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='peregrine-espresso'), 'The owner looked at me funny, do not return!'), |
|
93 |
+ ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'), (SELECT id FROM restaurants where short_name='peregrine-espresso'), 'Great Coffee!'), |
|
94 |
+ ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='peregrine-espresso'), 'Cockroach in bottom of french press, disgusting!'), |
|
95 |
+ ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='graffiato'), 'Too Italian'), |
|
96 |
+ ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'), (SELECT id FROM restaurants where short_name='graffiato'), 'They dont have a peanut butter pizza!'), |
|
97 |
+ ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='graffiato'), 'Whatever . . . '), |
|
98 |
+ ((SELECT id FROM reviewers where reviewer_name='the_tooth_fairy'), (SELECT id FROM restaurants where short_name='the-coffee-bar'), 'Great Location! Good Coffee!'), |
|
99 |
+ ((SELECT id FROM reviewers where reviewer_name='fiddlerwoaroof'), (SELECT id FROM restaurants where short_name='the-coffee-bar'), 'Great Coffee! Good Location!'), |
|
100 |
+ ((SELECT id FROM reviewers where reviewer_name='grandma_johnson'), (SELECT id FROM restaurants where short_name='the-coffee-bar'), 'This is too far from my knitting needles . . . '); |
|
101 |
+ |
|
102 |
+SELECT * FROM reviews |
|
103 |
+ RIGHT JOIN reviewers ON reviews.reviewer_id=reviewers.id |
|
104 |
+ RIGHT JOIN restaurants ON reviews.restaurant_id=restaurants.id |
|
105 |
+ WHERE short_name='vigilante-coffee'; |
|
106 |
+ |
|
107 |
+INSERT INTO reviewers (reviewer_name) VALUES ('the_great_one'); |
... | ... |
@@ -1,9 +1,82 @@ |
1 | 1 |
# myapp.rb |
2 | 2 |
require 'sinatra' |
3 |
+require 'sinatra/partial' |
|
3 | 4 |
require 'haml' |
5 |
+require 'pg' |
|
6 |
+require './config' |
|
7 |
+ |
|
8 |
+def connect_db |
|
9 |
+ return PG::Connection.open(:dbname=>$appsettings[:dbname], |
|
10 |
+ :host=>$appsettings[:dbhost], |
|
11 |
+ :user=>$appsettings[:dbuser], |
|
12 |
+ :password=>$appsettings[:dbpassword]) |
|
13 |
+end |
|
14 |
+ |
|
15 |
+def check_user(db, user) |
|
16 |
+ result = nil |
|
17 |
+ db.prepare 'check_user', 'SELECT exists(SELECT 1 FROM reviewers WHERE reviewer_name=$1)' |
|
18 |
+ if not user.nil? |
|
19 |
+ v = db.exec_prepared('check_user', [user]) |
|
20 |
+ if v.first()['exists'] == 't' |
|
21 |
+ result = user |
|
22 |
+ end |
|
23 |
+ end |
|
24 |
+ return result |
|
25 |
+end |
|
26 |
+ |
|
27 |
+use Rack::Session::Pool, :expire_after => 2592000 |
|
4 | 28 |
|
5 | 29 |
get '/' do |
6 |
- 'Hello world!' |
|
30 |
+ if params[:cur_user] |
|
31 |
+ session[:cur_user] = params[:cur_user] |
|
32 |
+ end |
|
33 |
+ |
|
34 |
+ short_name = params.find do |x| x[1] == nil end |
|
35 |
+ db = connect_db() |
|
36 |
+ cur_user = check_user(db, session[:cur_user]) |
|
37 |
+ if short_name.nil? |
|
38 |
+ restaurants = db.exec 'SELECT restaurant_name,short_name FROM restaurants ORDER BY restaurant_name ASC' |
|
39 |
+ haml :index, :locals => {:restaurants => restaurants, :cur_user => cur_user} |
|
40 |
+ else |
|
41 |
+ short_name = short_name[0] |
|
42 |
+ db.prepare 'get_restaurant_name', 'SELECT restaurant_name FROM restaurants WHERE short_name=$1' |
|
43 |
+ db.prepare 'get_reviews', 'SELECT * FROM get_reviews($1)' |
|
44 |
+ |
|
45 |
+ name = db.exec_prepared('get_restaurant_name', [short_name]).first['restaurant_name'] |
|
46 |
+ results = db.exec_prepared 'get_reviews', [short_name] |
|
47 |
+ haml :restaurant, :locals => {:reviews => results, |
|
48 |
+ :name => name, |
|
49 |
+ :short_name => short_name, |
|
50 |
+ :cur_user => cur_user} |
|
51 |
+ end |
|
7 | 52 |
end |
8 | 53 |
|
54 |
+def short_name(name) |
|
55 |
+ name.downcase().gsub(/[^a-zA-Z0-9]/, '-') |
|
56 |
+end |
|
57 |
+ |
|
58 |
+post '/add/restaurant' do |
|
59 |
+ db = connect_db() |
|
60 |
+ if check_user(db, session[:cur_user]).nil? |
|
61 |
+ redirect to("/") |
|
62 |
+ else |
|
63 |
+ db.prepare 'add_restaurant', 'INSERT INTO restaurants (restaurant_name, short_name) VALUES ($1,$2)' |
|
64 |
+ name = params[:restaurant_name] |
|
65 |
+ sn = short_name(name) |
|
66 |
+ db.exec_prepared 'add_restaurant', [name, sn] |
|
67 |
+ redirect to("/?#{sn}") |
|
68 |
+ end |
|
69 |
+end |
|
70 |
+ |
|
71 |
+ |
|
72 |
+post '/add/review' do |
|
73 |
+ db = connect_db() |
|
74 |
+ if check_user(db, session[:cur_user]).nil? |
|
75 |
+ redirect to("/?#{params[:short_name]}") |
|
76 |
+ else |
|
77 |
+ db.prepare 'put_review', 'SELECT * FROM put_review($1, $2, $3)' |
|
78 |
+ db.exec_prepared 'put_review', [ params[:short_name], session[:cur_user], params[:review] ] |
|
79 |
+ redirect to("/?#{params[:short_name]}") |
|
80 |
+ end |
|
81 |
+end |
|
9 | 82 |
|
10 | 83 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,9 @@ |
1 |
+%form{:action => "/add/review", :method => "post"} |
|
2 |
+ %textarea{:name => "review"} |
|
3 |
+ - if defined? review |
|
4 |
+ = review['review'] |
|
5 |
+ %input{:type => "hidden", :value => short_name, :name => "short_name"} |
|
6 |
+ %input{:type => "hidden", :value => cur_user, :name => "reviewer"} |
|
7 |
+ %input{:type => "submit"} |
|
8 |
+ |
|
9 |
+ |
... | ... |
@@ -1 +1,11 @@ |
1 |
-Hello World |
|
1 |
+%article |
|
2 |
+ %h1 How is |
|
3 |
+ %ul.restaurants |
|
4 |
+ - restaurants.each do |restaurant| |
|
5 |
+ %a{:href => "/?#{restaurant['short_name']}"} |
|
6 |
+ %li= "#{restaurant['restaurant_name']}?" |
|
7 |
+ - if not cur_user.nil? |
|
8 |
+ %li |
|
9 |
+ %form{:action => "/add/restaurant", :method => "post"} |
|
10 |
+ %input{:type => "text", :name => "restaurant_name"} |
|
11 |
+ %input{:type => "submit"} |
2 | 12 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,17 @@ |
1 |
+- comment_form_shown = false |
|
2 |
+%article |
|
3 |
+ %h1= name |
|
4 |
+ %a{:href => "/"} Go Back> |
|
5 |
+ %section#reviews |
|
6 |
+ %h2 how it is: |
|
7 |
+ %ul.reviews |
|
8 |
+ - reviews.each do |review| |
|
9 |
+ - if review['reviewer'] != cur_user |
|
10 |
+ %li= "#{review['review']} —#{review['reviewer']}" |
|
11 |
+ - else |
|
12 |
+ %li= partial :comment_form, |
|
13 |
+ :locals => {:review => review, :cur_user => cur_user, :short_name => short_name} |
|
14 |
+ - comment_form_shown = true |
|
15 |
+ - if not comment_form_shown and not cur_user.nil? |
|
16 |
+ %li= partial :comment_form, |
|
17 |
+ :locals => {:cur_user => cur_user, :short_name => short_name} |