diff --git a/Gemfile b/Gemfile index b1a320395a..44d861af6a 100644 --- a/Gemfile +++ b/Gemfile @@ -11,3 +11,15 @@ end group :development, :test do gem 'rubocop', '1.20' end + +gem "pg", "~> 1.5" + +gem "rack-test", "~> 2.1" + +gem "webrick", "~> 1.8" + +gem 'sinatra', '~> 3.0', '>= 3.0.6' + +gem 'rack', '~> 2.2', '>= 2.2.4' + +gem "sinatra-contrib", "~> 3.0" diff --git a/Gemfile.lock b/Gemfile.lock index 66064703c7..4d2b343587 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,27 +3,36 @@ GEM specs: ansi (1.5.0) ast (2.4.2) - diff-lcs (1.4.4) + diff-lcs (1.5.0) docile (1.4.0) - parallel (1.20.1) - parser (3.0.2.0) + multi_json (1.15.0) + mustermann (3.0.0) + ruby2_keywords (~> 0.0.1) + parallel (1.23.0) + parser (3.2.2.1) ast (~> 2.4.1) - rainbow (3.0.0) - regexp_parser (2.1.1) + pg (1.5.3) + rack (2.2.7) + rack-protection (3.0.6) + rack + rack-test (2.1.0) + rack (>= 1.3) + rainbow (3.1.1) + regexp_parser (2.8.0) rexml (3.2.5) - rspec (3.10.0) - rspec-core (~> 3.10.0) - rspec-expectations (~> 3.10.0) - rspec-mocks (~> 3.10.0) - rspec-core (3.10.1) - rspec-support (~> 3.10.0) - rspec-expectations (3.10.1) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-mocks (3.10.2) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.5) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.10.0) - rspec-support (3.10.2) + rspec-support (~> 3.12.0) + rspec-support (3.12.0) rubocop (1.20.0) parallel (~> 1.10) parser (>= 3.0.0.0) @@ -33,10 +42,11 @@ GEM rubocop-ast (>= 1.9.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.11.0) - parser (>= 3.0.1.1) - ruby-progressbar (1.11.0) - simplecov (0.21.2) + rubocop-ast (1.28.1) + parser (>= 3.2.1.0) + ruby-progressbar (1.13.0) + ruby2_keywords (0.0.5) + simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) @@ -45,19 +55,38 @@ GEM simplecov terminal-table simplecov-html (0.12.3) - simplecov_json_formatter (0.1.3) - terminal-table (3.0.1) + simplecov_json_formatter (0.1.4) + sinatra (3.0.6) + mustermann (~> 3.0) + rack (~> 2.2, >= 2.2.4) + rack-protection (= 3.0.6) + tilt (~> 2.0) + sinatra-contrib (3.0.6) + multi_json + mustermann (~> 3.0) + rack-protection (= 3.0.6) + sinatra (= 3.0.6) + tilt (~> 2.0) + terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - unicode-display_width (2.0.0) + tilt (2.1.0) + unicode-display_width (2.4.2) + webrick (1.8.1) PLATFORMS ruby DEPENDENCIES + pg (~> 1.5) + rack (~> 2.2, >= 2.2.4) + rack-test (~> 2.1) rspec rubocop (= 1.20) simplecov simplecov-console + sinatra (~> 3.0, >= 3.0.6) + sinatra-contrib (~> 3.0) + webrick (~> 1.8) RUBY VERSION ruby 3.0.2p107 diff --git a/app.rb b/app.rb new file mode 100644 index 0000000000..0c01bf1e5a --- /dev/null +++ b/app.rb @@ -0,0 +1,78 @@ +require 'date' +require 'sinatra' +require "sinatra/reloader" +require_relative 'lib/database_connection' +require_relative 'lib/peep_repo' +require_relative 'lib/user_repo' + +DatabaseConnection.connect + +class Application < Sinatra::Base + + enable :sessions + + configure :development do + register Sinatra::Reloader + end + + get '/' do + peeps + end + + post '/' do + return erb(:login) if session[:user_id].nil? + repo = PeepRepo.new + peep = Peep.new + peep.message = params['peep'] + peep.time = DateTime.now + peep.user_account_id = 1 + repo.create(peep) + peeps + end + + get '/signup' do + return erb(:signup) + end + + post '/signup' do + repo = UserRepo.new + new_user = User.new + new_user.username = params[:username] + new_user.password = params[:password] + new_user.email_address = params[:email] + new_user.name = params[:name] + ult = repo.create(new_user) + return erb(:login) if ult == false + return erb(:signup) + end + + get '/login' do + return erb(:login) + end + + post '/login' do + username = params[:username] + password = params[:password] + user = UserRepo.new.find_by_username(username) + return erb(:login) unless user.password == password + session[:user_id] = user.id + peeps + end + + get '/logout' do + session[:user_id] = nil + peeps + end + + private + + def peeps + @session = session[:user_id] + @peeps = PeepRepo.new.all.reverse + return erb(:index) + end + + def new_user + + end +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000000..af14ef717e --- /dev/null +++ b/config.ru @@ -0,0 +1,2 @@ +require './app' +run Application diff --git a/lib/database_connection.rb b/lib/database_connection.rb new file mode 100644 index 0000000000..9d43719114 --- /dev/null +++ b/lib/database_connection.rb @@ -0,0 +1,39 @@ + +require 'pg' + +# This class is a thin "wrapper" around the +# PG library. We'll use it in our project to interact +# with the database using SQL. + +class DatabaseConnection + # This method connects to PostgreSQL using the + # PG gem. We connect to 127.0.0.1, and select + # the database name given in argument. + def self.connect + # If the environment variable (set by Render) + # is present, use this to open the connection. + if ENV['DATABASE_URL'] != nil + @connection = PG.connect(ENV['DATABASE_URL']) + return + end + + if ENV['ENV'] == 'test' + database_name = 'test_chitter' + else + database_name = 'chitter' + end + @connection = PG.connect({ host: '127.0.0.1', dbname: database_name }) + end + + # This method executes an SQL query + # on the database, providing some optional parameters + # (you will learn a bit later about when to provide these parameters). + def self.exec_params(query, params) + if @connection.nil? + raise 'DatabaseConnection.exec_params: Cannot run a SQL query as the connection to'\ + 'the database was never opened. Did you make sure to call first the method '\ + '`DatabaseConnection.connect` in your app.rb file (or in your tests spec_helper.rb)?' + end + @connection.exec_params(query, params) + end +end diff --git a/lib/peep.rb b/lib/peep.rb new file mode 100644 index 0000000000..d9253ceb26 --- /dev/null +++ b/lib/peep.rb @@ -0,0 +1,3 @@ +class Peep + attr_accessor :id, :message, :time, :user_account_id, :username, :name +end diff --git a/lib/peep_repo.rb b/lib/peep_repo.rb new file mode 100644 index 0000000000..1174566792 --- /dev/null +++ b/lib/peep_repo.rb @@ -0,0 +1,52 @@ +require_relative 'peep' +require_relative 'database_connection' + +class PeepRepo + def initialize + @peeps = [] + end + + def all + sql = 'SELECT posts.*, user_accounts.username, user_accounts.name + FROM posts + INNER JOIN user_accounts + ON posts.user_account_id = user_accounts.id;' + result = DatabaseConnection.exec_params(sql, []) + result.each do |record| + @peeps << new_peep(record) + end + @peeps + end + + def find(id) + sql = 'SELECT * FROM posts WHERE id = $1;' + params = [id] + result = DatabaseConnection.exec_params(sql, params) + record = result[0] + peep = Peep.new + peep.id = record['id'] + peep.message = record['message'] + peep.time = record['time'] + peep.user_account_id = record['user_account_id'] + peep + end + + def create(peep) + sql = 'INSERT INTO posts (message, time, user_account_id) VALUES ($1, $2, $3);' + params = [peep.message, peep.time, peep.user_account_id] + DatabaseConnection.exec_params(sql, params) + end + + private + + def new_peep(record) + peep = Peep.new + peep.id = record['id'] + peep.message = record['message'] + peep.time = record['time'] + peep.user_account_id = record['user_account_id'] + peep.username = record['username'] + peep.name = record['name'] + peep + end +end diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 0000000000..2fb32556a8 --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,3 @@ +class User + attr_accessor :id, :email_address, :username, :name, :password +end diff --git a/lib/user_repo.rb b/lib/user_repo.rb new file mode 100644 index 0000000000..95103cfee4 --- /dev/null +++ b/lib/user_repo.rb @@ -0,0 +1,55 @@ +require_relative 'user' +require_relative 'database_connection' + +class UserRepo + def initialize + @users = [] + end + + def all + sql = 'SELECT * + FROM user_accounts;' + result = DatabaseConnection.exec_params(sql, []) + result.each do |record| + @users << new_user(record) + end + @users + end + + def create(user) + return true if check_unique(user.email_address, user.username) + sql = 'INSERT INTO user_accounts (email_address, username, name, password) + VALUES ($1, $2, $3, $4);' + params = [user.email_address, user.username, user.name, user.password] + DatabaseConnection.exec_params(sql, params) + return false + end + + def check_unique(email_address, username) + sql = 'SELECT email_address, username + FROM user_accounts + WHERE email_address = $1 OR username = $2;' + params = [email_address, username] + result = DatabaseConnection.exec_params(sql, params) + return !result.first.nil? + end + + def find_by_username(username) + sql = 'SELECT * FROM user_accounts WHERE username = $1;' + params = [username] + result = DatabaseConnection.exec_params(sql, params) + return new_user(result[0]) + end + + private + + def new_user(record) + user = User.new + user.id = record['id'] + user.email_address = record['email_address'] + user.username = record['username'] + user.name = record['name'] + user.password = record['password'] + user + end +end diff --git a/spec/integration/app_sinatra_spec.rb b/spec/integration/app_sinatra_spec.rb new file mode 100644 index 0000000000..2b08008faf --- /dev/null +++ b/spec/integration/app_sinatra_spec.rb @@ -0,0 +1,83 @@ +require "spec_helper" +require "rack/test" +require_relative '../../app' + +describe Application do + include Rack::Test::Methods + + let(:app) { Application.new } + + before(:each) do + reset_tables + end + + context 'GET /' do + it 'shows peeps already made' do + response = get('/') + expect(response.status).to eq 200 + expect(response.body).to include('
Shrek @fionalover420            2008-11-11 13:23:44
') + end + end + + context 'POST /' do + it 'redirects you to login page if you try to post' do + response = post('/', peep: 'peep test') + expect(response.status).to eq 200 + expect(response.body).to include("Username:") + end + + it 'posts a peep when logged in' do + response = post('/login', username: 'fionalover420', password: 'I_Love_Fiona_69') + response = post('/', peep: 'peep test') + expect(response.status).to eq 200 + expect(response.body).to include('peep test') + expect(response.body).to include(' +<% else %> + +<% end %> + +<%= peep.name %> @<%= peep.username %>            <%= peep.time %>
+<%= peep.message %>
+