From 3cf4eaa80f726ca83ca7ba371c8a3562b59e8463 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 15:23:41 +0100 Subject: [PATCH 01/56] Set up rspec folder structure and sinatra config --- Gemfile | 5 +++++ Gemfile.lock | 26 ++++++++++++++++++++++++++ app.rb | 8 ++++++++ config.ru | 2 ++ spec/integration/app_spec.rb | 0 5 files changed, 41 insertions(+) create mode 100644 app.rb create mode 100644 config.ru create mode 100644 spec/integration/app_spec.rb diff --git a/Gemfile b/Gemfile index b1a320395a..866f834e6c 100644 --- a/Gemfile +++ b/Gemfile @@ -11,3 +11,8 @@ end group :development, :test do gem 'rubocop', '1.20' end + +gem "sinatra", "~> 3.0" +gem "sinatra-contrib", "~> 3.0" +gem "webrick", "~> 1.8" +gem "rack-test", "~> 2.1" diff --git a/Gemfile.lock b/Gemfile.lock index 66064703c7..58a913dabc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,9 +5,17 @@ GEM ast (2.4.2) diff-lcs (1.4.4) docile (1.4.0) + multi_json (1.15.0) + mustermann (3.0.0) + ruby2_keywords (~> 0.0.1) parallel (1.20.1) parser (3.0.2.0) ast (~> 2.4.1) + rack (2.2.7) + rack-protection (3.0.6) + rack + rack-test (2.1.0) + rack (>= 1.3) rainbow (3.0.0) regexp_parser (2.1.1) rexml (3.2.5) @@ -36,6 +44,7 @@ GEM rubocop-ast (1.11.0) parser (>= 3.0.1.1) ruby-progressbar (1.11.0) + ruby2_keywords (0.0.5) simplecov (0.21.2) docile (~> 1.1) simplecov-html (~> 0.11) @@ -46,18 +55,35 @@ GEM terminal-table simplecov-html (0.12.3) simplecov_json_formatter (0.1.3) + 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.1) unicode-display_width (>= 1.1.1, < 3) + tilt (2.1.0) unicode-display_width (2.0.0) + webrick (1.8.1) PLATFORMS ruby DEPENDENCIES + rack-test (~> 2.1) rspec rubocop (= 1.20) simplecov simplecov-console + sinatra (~> 3.0) + 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..1dcd37d299 --- /dev/null +++ b/app.rb @@ -0,0 +1,8 @@ +require 'sinatra/base' +require 'sinatra/reloader' + +class Application < Sinatra::Base + configure :development do + register Sinatra::Reloader + end +end \ No newline at end of file diff --git a/config.ru b/config.ru new file mode 100644 index 0000000000..30570ef105 --- /dev/null +++ b/config.ru @@ -0,0 +1,2 @@ +require './app' +run Application \ No newline at end of file diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb new file mode 100644 index 0000000000..e69de29bb2 From 686a27c9fab0188129c05518af727c95eadd644a Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 16:02:19 +0100 Subject: [PATCH 02/56] Write sql seeds files --- chitter.sql | 19 +++++++++++++++++++ spec/seeds_peeps.sql | 13 +++++++++++++ spec/seeds_users.sql | 10 ++++++++++ 3 files changed, 42 insertions(+) create mode 100644 chitter.sql create mode 100644 spec/seeds_peeps.sql create mode 100644 spec/seeds_users.sql diff --git a/chitter.sql b/chitter.sql new file mode 100644 index 0000000000..77b9dce286 --- /dev/null +++ b/chitter.sql @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS users, peeps; + +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + email text, + password text, + name text, + username text +); + +CREATE TABLE peeps ( + id SERIAL PRIMARY KEY, + content text, + time_posted timestamp, + user_id integer, + constraint fk_user foreign key(user_id) + references users(id) + on delete cascade +); \ No newline at end of file diff --git a/spec/seeds_peeps.sql b/spec/seeds_peeps.sql new file mode 100644 index 0000000000..f4ef188aa5 --- /dev/null +++ b/spec/seeds_peeps.sql @@ -0,0 +1,13 @@ +TRUNCATE TABLE peeps RESTART IDENTITY; + +INSERT INTO peeps + (content, time_posted, user_id) + VALUES + ('content_1', '2023-05-01 17:15:32', 1), + ('content_2', '2022-04-21 04:03:02', 2), + ('content_3', '2022-06-21 00:01:02', 3), + ('content_4', '2022-06-21 22:01:02', 4), + ('content_5', '1999-04-19 16:59:59', 1), + ('content_6', '2005-12-27 03:45:06', 1), + ('content_7', '2007-08-13 17:17:17', 4) +; \ No newline at end of file diff --git a/spec/seeds_users.sql b/spec/seeds_users.sql new file mode 100644 index 0000000000..89f07366aa --- /dev/null +++ b/spec/seeds_users.sql @@ -0,0 +1,10 @@ +TRUNCATE TABLE users RESTART IDENTITY CASCADE; + +INSERT INTO users + (email, password, name, username) + VALUES + ('email_1', 'password_1', 'name_1', 'username_1'), + ('email_2', 'password_2', 'name_2', 'username_2'), + ('email_3', 'password_3', 'name_3', 'username_3'), + ('email_4', 'password_4', 'name_4', 'username_4') +; \ No newline at end of file From 7ae5ca5723f7f6d8bead7156f4566089491d9f09 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 16:49:05 +0100 Subject: [PATCH 03/56] Set up empty database files --- Gemfile | 2 ++ Gemfile.lock | 2 ++ lib/database_connection.rb | 26 ++++++++++++++++++++++++++ lib/peep.rb | 0 lib/peep_repository.rb | 0 lib/user.rb | 0 lib/user_repository.rb | 0 spec/peep_repository_spec.rb | 0 spec/user_repository_spec.rb | 0 9 files changed, 30 insertions(+) create mode 100644 lib/database_connection.rb create mode 100644 lib/peep.rb create mode 100644 lib/peep_repository.rb create mode 100644 lib/user.rb create mode 100644 lib/user_repository.rb create mode 100644 spec/peep_repository_spec.rb create mode 100644 spec/user_repository_spec.rb diff --git a/Gemfile b/Gemfile index 866f834e6c..e036fbc07c 100644 --- a/Gemfile +++ b/Gemfile @@ -16,3 +16,5 @@ gem "sinatra", "~> 3.0" gem "sinatra-contrib", "~> 3.0" gem "webrick", "~> 1.8" gem "rack-test", "~> 2.1" + +gem "pg", "~> 1.5" diff --git a/Gemfile.lock b/Gemfile.lock index 58a913dabc..d7ce111533 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,6 +11,7 @@ GEM parallel (1.20.1) parser (3.0.2.0) ast (~> 2.4.1) + pg (1.5.3) rack (2.2.7) rack-protection (3.0.6) rack @@ -76,6 +77,7 @@ PLATFORMS ruby DEPENDENCIES + pg (~> 1.5) rack-test (~> 2.1) rspec rubocop (= 1.20) diff --git a/lib/database_connection.rb b/lib/database_connection.rb new file mode 100644 index 0000000000..ac9ec32a31 --- /dev/null +++ b/lib/database_connection.rb @@ -0,0 +1,26 @@ +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(database_name) + @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 \ No newline at end of file diff --git a/lib/peep.rb b/lib/peep.rb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/peep_repository.rb b/lib/peep_repository.rb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/user_repository.rb b/lib/user_repository.rb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spec/peep_repository_spec.rb b/spec/peep_repository_spec.rb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spec/user_repository_spec.rb b/spec/user_repository_spec.rb new file mode 100644 index 0000000000..e69de29bb2 From e04cb8d262d752c706282c06a08da5888b6ba5a8 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 17:14:31 +0100 Subject: [PATCH 04/56] Write UserRepository#find --- app.rb | 2 +- config.ru | 2 +- lib/database_connection.rb | 2 +- lib/user.rb | 3 +++ lib/user_repository.rb | 21 +++++++++++++++++++++ spec/spec_helper.rb | 3 +++ spec/user_repository_spec.rb | 35 +++++++++++++++++++++++++++++++++++ 7 files changed, 65 insertions(+), 3 deletions(-) diff --git a/app.rb b/app.rb index 1dcd37d299..7d8060cbd8 100644 --- a/app.rb +++ b/app.rb @@ -5,4 +5,4 @@ class Application < Sinatra::Base configure :development do register Sinatra::Reloader end -end \ No newline at end of file +end diff --git a/config.ru b/config.ru index 30570ef105..af14ef717e 100644 --- a/config.ru +++ b/config.ru @@ -1,2 +1,2 @@ require './app' -run Application \ No newline at end of file +run Application diff --git a/lib/database_connection.rb b/lib/database_connection.rb index ac9ec32a31..470de97998 100644 --- a/lib/database_connection.rb +++ b/lib/database_connection.rb @@ -23,4 +23,4 @@ def self.exec_params(query, params) end @connection.exec_params(query, params) end -end \ No newline at end of file +end diff --git a/lib/user.rb b/lib/user.rb index e69de29bb2..1f12d2cc2e 100644 --- a/lib/user.rb +++ b/lib/user.rb @@ -0,0 +1,3 @@ +class User + attr_accessor :id, :email, :password, :name, :username +end diff --git a/lib/user_repository.rb b/lib/user_repository.rb index e69de29bb2..27c85ce58a 100644 --- a/lib/user_repository.rb +++ b/lib/user_repository.rb @@ -0,0 +1,21 @@ +require_relative './user' + +class UserRepository + def find(id) + sql = 'SELECT * FROM users WHERE id = $1' + records = DatabaseConnection.exec_params(sql, [id]) + return create_user_from_record(records.first) + end + + private + + def create_user_from_record(record) + user = User.new + user.id = record['id'].to_i + user.email = record['email'] + user.password = record['password'] + user.name = record['name'] + user.username = record['username'] + return user + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 252747d899..e3e1e20c2b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,6 @@ require 'simplecov' require 'simplecov-console' +require 'database_connection' SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ SimpleCov::Formatter::Console, @@ -15,3 +16,5 @@ puts "\e[33mTry it now! Just run: rubocop\e[0m" end end + +DatabaseConnection.connect('chitter_test') diff --git a/spec/user_repository_spec.rb b/spec/user_repository_spec.rb index e69de29bb2..b48d406259 100644 --- a/spec/user_repository_spec.rb +++ b/spec/user_repository_spec.rb @@ -0,0 +1,35 @@ +require 'user_repository' + +def reset_user_table + sql_seeds = File.read("spec/seeds_users.sql") + connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_test' }) + connection.exec sql_seeds +end + +describe UserRepository do + before(:each) do + reset_user_table + end + + describe '#find' do + it 'returns a user by id' do + repo = UserRepository.new + user = repo.find(1) + expect(user.id).to eq 1 + expect(user.email).to eq 'email_1' + expect(user.password).to eq 'password_1' + expect(user.name).to eq 'name_1' + expect(user.username).to eq 'username_1' + end + + it 'returns another user by id' do + repo = UserRepository.new + user = repo.find(3) + expect(user.id).to eq 3 + expect(user.email).to eq 'email_3' + expect(user.password).to eq 'password_3' + expect(user.name).to eq 'name_3' + expect(user.username).to eq 'username_3' + end + end +end From b41415df90a119b000d99fee45a57daf3fb02986 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 17:28:11 +0100 Subject: [PATCH 05/56] Write UserRepository#all and UserRepository#create --- lib/user_repository.rb | 13 +++++++++ spec/user_repository_spec.rb | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/lib/user_repository.rb b/lib/user_repository.rb index 27c85ce58a..cb15792c2e 100644 --- a/lib/user_repository.rb +++ b/lib/user_repository.rb @@ -1,12 +1,25 @@ require_relative './user' class UserRepository + def all + sql = 'SELECT * FROM users;' + records = DatabaseConnection.exec_params(sql, []) + records.map { |record| create_user_from_record(record) } + end + def find(id) sql = 'SELECT * FROM users WHERE id = $1' records = DatabaseConnection.exec_params(sql, [id]) return create_user_from_record(records.first) end + def create(user) + sql = 'INSERT INTO users (email, password, name, username) + VALUES ($1, $2, $3, $4)' + params = [user.email, user.password, user.name, user.username] + DatabaseConnection.exec_params(sql, params) + end + private def create_user_from_record(record) diff --git a/spec/user_repository_spec.rb b/spec/user_repository_spec.rb index b48d406259..ab24626c77 100644 --- a/spec/user_repository_spec.rb +++ b/spec/user_repository_spec.rb @@ -11,6 +11,35 @@ def reset_user_table reset_user_table end + describe '#all' do + it 'returns a list of all users' do + repo = UserRepository.new + users = repo.all + + expect(users.length).to eq 4 + + expect(users).to include( + have_attributes( + id: 1, + email: 'email_1', + password: 'password_1', + name: 'name_1', + username: 'username_1' + ) + ) + + expect(users).to include( + have_attributes( + id: 3, + email: 'email_3', + password: 'password_3', + name: 'name_3', + username: 'username_3' + ) + ) + end + end + describe '#find' do it 'returns a user by id' do repo = UserRepository.new @@ -32,4 +61,27 @@ def reset_user_table expect(user.username).to eq 'username_3' end end + + describe '#create' do + it "creates a new user in the database" do + user = User.new + user.email = 'new_email' + user.password = 'new_password' + user.name = 'new_name' + user.username = 'new_username' + + repo = UserRepository.new + repo.create(user) + + expect(repo.all).to include( + have_attributes( + id: 5, + email: 'new_email', + password: 'new_password', + name: 'new_name', + username: 'new_username' + ) + ) + end + end end From 2a3a279c66524fd45618e7f813174fe1d1f032eb Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 17:47:23 +0100 Subject: [PATCH 06/56] Write PeepRepository#all --- lib/peep.rb | 3 +++ lib/peep_repository.rb | 26 +++++++++++++++++++++++ spec/peep_repository_spec.rb | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/lib/peep.rb b/lib/peep.rb index e69de29bb2..5fc9e57fcf 100644 --- a/lib/peep.rb +++ b/lib/peep.rb @@ -0,0 +1,3 @@ +class Peep + attr_accessor :id, :content, :time_posted, :user_id +end diff --git a/lib/peep_repository.rb b/lib/peep_repository.rb index e69de29bb2..1f7a9383c9 100644 --- a/lib/peep_repository.rb +++ b/lib/peep_repository.rb @@ -0,0 +1,26 @@ +require_relative './peep' + +class PeepRepository + def all + sql = 'SELECT * FROM peeps;' + records = DatabaseConnection.exec_params(sql, []) + records.map { |record| create_peep_from_record(record) } + end + + def find(id) + end + + def create(peep) + end + + private + + def create_peep_from_record(record) + peep = Peep.new + peep.id = record['id'].to_i + peep.content = record['content'] + peep.time_posted = Time.new(record['time_posted']) + peep.user_id = record['user_id'].to_i + return peep + end +end diff --git a/spec/peep_repository_spec.rb b/spec/peep_repository_spec.rb index e69de29bb2..0b7d607762 100644 --- a/spec/peep_repository_spec.rb +++ b/spec/peep_repository_spec.rb @@ -0,0 +1,40 @@ +require 'peep_repository' + +def reset_peeps_table + sql_seeds = File.read('spec/seeds_peeps.sql') + connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_test' }) + connection.exec(sql_seeds) +end + +describe PeepRepository do + before(:each) do + reset_peeps_table + end + + describe '#all' do + it "returns a list of all peeps" do + repo = PeepRepository.new + peeps = repo.all + + expect(peeps.length).to eq 7 + + expect(peeps).to include( + have_attributes( + id: 1, + content: 'content_1', + time_posted: Time.new('2023-05-01 17:15:32'), + user_id: 1 + ) + ) + + expect(peeps).to include( + have_attributes( + id: 5, + content: 'content_5', + time_posted: Time.new('1999-04-19 16:59:59'), + user_id: 1 + ) + ) + end + end +end \ No newline at end of file From 880717be0b272a46ff614700c43c6769adfd7c71 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 18:04:19 +0100 Subject: [PATCH 07/56] Write PeepRepository#find and PeepRepository#create --- lib/peep_repository.rb | 7 ++++++ spec/peep_repository_spec.rb | 47 ++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/peep_repository.rb b/lib/peep_repository.rb index 1f7a9383c9..d004a65f0c 100644 --- a/lib/peep_repository.rb +++ b/lib/peep_repository.rb @@ -8,9 +8,16 @@ def all end def find(id) + sql = 'SELECT * FROM peeps WHERE id = $1;' + records = DatabaseConnection.exec_params(sql, [id]) + return create_peep_from_record(records.first) end def create(peep) + sql = 'INSERT INTO peeps (content, time_posted, user_id) + VALUES ($1, $2, $3)' + params = [peep.content, peep.time_posted, peep.user_id] + DatabaseConnection.exec_params(sql, params) end private diff --git a/spec/peep_repository_spec.rb b/spec/peep_repository_spec.rb index 0b7d607762..22a4888169 100644 --- a/spec/peep_repository_spec.rb +++ b/spec/peep_repository_spec.rb @@ -12,7 +12,7 @@ def reset_peeps_table end describe '#all' do - it "returns a list of all peeps" do + it 'returns a list of all peeps' do repo = PeepRepository.new peeps = repo.all @@ -36,5 +36,48 @@ def reset_peeps_table ) ) end + + describe '#find' do + it 'returns a peep by id' do + repo = PeepRepository.new + peep = repo.find(1) + + expect(peep.id).to eq 1 + expect(peep.content).to eq 'content_1' + expect(peep.time_posted).to eq Time.new('2023-05-01 17:15:32') + expect(peep.user_id).to eq 1 + end + + it 'returns another peep by id' do + repo = PeepRepository.new + peep = repo.find(4) + + expect(peep.id).to eq 4 + expect(peep.content).to eq 'content_4' + expect(peep.time_posted).to eq Time.new('2022-06-21 22:01:02') + expect(peep.user_id).to eq 4 + end + end + + describe '#create' do + it 'adds a new peep to the database' do + peep = Peep.new + peep.content = 'new_content' + peep.time_posted = Time.new('2023-05-05 17:53:00') + peep.user_id = 3 + + repo = PeepRepository.new + repo.create(peep) + + expect(repo.all).to include( + have_attributes( + id: 8, + content: 'new_content', + time_posted: Time.new('2023-05-05 17:53:00'), + user_id: 3 + ) + ) + end + end end -end \ No newline at end of file +end From 29888d668b17b955312b6283af2bd54395f9c9cd Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 18:20:09 +0100 Subject: [PATCH 08/56] Rewrite DatabaseConnection to allow for deployment with repote database --- lib/database_connection.rb | 18 +++++++----------- spec/spec_helper.rb | 3 ++- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/database_connection.rb b/lib/database_connection.rb index 470de97998..34b41dff47 100644 --- a/lib/database_connection.rb +++ b/lib/database_connection.rb @@ -1,20 +1,16 @@ 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(database_name) + def self.connect + if ENV['DATABASE_URL'] != nil + @connection = PG.connect(ENV['DATABASE_URL']) + return + end + + database_name = ENV['ENV'] == 'test' ? 'chitter_test' : 'chitter' @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'\ diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e3e1e20c2b..c3b92ee18b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -17,4 +17,5 @@ end end -DatabaseConnection.connect('chitter_test') +ENV['ENV'] = 'test' +DatabaseConnection.connect From 38ba99ba9bb4b2f4aa633c58ca5955b7a3b46b03 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 18:29:38 +0100 Subject: [PATCH 09/56] Set up app.rb and move reset tables methods into spec_helper --- app.rb | 2 ++ spec/integration/app_spec.rb | 14 ++++++++++++++ spec/peep_repository_spec.rb | 6 ------ spec/spec_helper.rb | 12 ++++++++++++ spec/user_repository_spec.rb | 8 +------- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/app.rb b/app.rb index 7d8060cbd8..1c4174713f 100644 --- a/app.rb +++ b/app.rb @@ -4,5 +4,7 @@ class Application < Sinatra::Base configure :development do register Sinatra::Reloader + also_reload 'lib/user_repository' + also_reload 'lib/peep_repository' end end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index e69de29bb2..291c5f7680 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' +require 'rack/test' +require_relative '../../app' + +describe Application do + include Rack::Test::Methods + + let(:app) { Application.new } + + before(:each) do + reset_user_table + reset_peeps_table + end +end diff --git a/spec/peep_repository_spec.rb b/spec/peep_repository_spec.rb index 22a4888169..3da3a395da 100644 --- a/spec/peep_repository_spec.rb +++ b/spec/peep_repository_spec.rb @@ -1,11 +1,5 @@ require 'peep_repository' -def reset_peeps_table - sql_seeds = File.read('spec/seeds_peeps.sql') - connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_test' }) - connection.exec(sql_seeds) -end - describe PeepRepository do before(:each) do reset_peeps_table diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c3b92ee18b..d22d532734 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,3 +19,15 @@ ENV['ENV'] = 'test' DatabaseConnection.connect + +def reset_peeps_table + sql_seeds = File.read('spec/seeds_peeps.sql') + connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_test' }) + connection.exec(sql_seeds) +end + +def reset_users_table + sql_seeds = File.read("spec/seeds_users.sql") + connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_test' }) + connection.exec sql_seeds +end diff --git a/spec/user_repository_spec.rb b/spec/user_repository_spec.rb index ab24626c77..90f7fb0ec0 100644 --- a/spec/user_repository_spec.rb +++ b/spec/user_repository_spec.rb @@ -1,14 +1,8 @@ require 'user_repository' -def reset_user_table - sql_seeds = File.read("spec/seeds_users.sql") - connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_test' }) - connection.exec sql_seeds -end - describe UserRepository do before(:each) do - reset_user_table + reset_users_table end describe '#all' do From d00069ce889adda9ce0b0571a7331aa3a670482b Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 18:49:33 +0100 Subject: [PATCH 10/56] Write the skeleton for http route tests --- spec/integration/app_spec.rb | 84 ++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 291c5f7680..d07b117ba5 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -11,4 +11,88 @@ reset_user_table reset_peeps_table end + + describe 'GET /' do + xit 'returns 200 OK' do + end + + xit 'returns returns html with all peeps' do + end + + xit 'returns html with link to sign up' do + end + + xit 'returns html with link to post a new peep' do + end + end + + describe 'GET /sign-up' do + xit 'returns 200 OK' do + end + + xit 'returns html with sign up form using POST /sign-up route' do + end + + xit 'returns html with link back to homepage' do + end + end + + describe 'GET /new-peep' do + xit 'returns 200 OK' do + end + + xit 'returns html with new peep form using POST /new-peep route' do + end + + xit 'returns html with link back to the homepage' do + end + end + + describe 'POST /sign-up' do + context 'when used with valid params' do + xit 'returns 200 OK' do + end + + xit 'returns html with success message' do + end + + xit 'returns html with link back to the homepage' do + end + + xit 'adds a new user to the database' do + end + end + + context 'when used with invalid params' do + xit 'returns 400 Bad Request' do + end + # TODO - Consider invalid params + end + + end + + describe 'POST /new-peep' do + context 'when used with valid params' do + xit 'returns 200 OK' do + end + + xit 'returns html with success message' do + end + + xit 'returns html with link back to the homepage' do + end + + xit 'returns html with option to create another new peep' do + end + + xit 'adds a new peep to the database' do + end + end + + context 'when used with invalid params' do + xit 'returns 400 Bad Request' do + end + # TODO - Consider invalid params + end + end end From e987bf8b8d59ff645b382f729eee2c5e9295d93e Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 19:47:17 +0100 Subject: [PATCH 11/56] Fix bug with getting timestamp from the database --- lib/peep_repository.rb | 12 ++++++++++-- spec/peep_repository_spec.rb | 9 ++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/peep_repository.rb b/lib/peep_repository.rb index d004a65f0c..8554f9353c 100644 --- a/lib/peep_repository.rb +++ b/lib/peep_repository.rb @@ -4,7 +4,8 @@ class PeepRepository def all sql = 'SELECT * FROM peeps;' records = DatabaseConnection.exec_params(sql, []) - records.map { |record| create_peep_from_record(record) } + x = records.map { |record| create_peep_from_record(record) } + x end def find(id) @@ -26,8 +27,15 @@ def create_peep_from_record(record) peep = Peep.new peep.id = record['id'].to_i peep.content = record['content'] - peep.time_posted = Time.new(record['time_posted']) + peep.time_posted = timestamp_to_time_object(record['time_posted']) peep.user_id = record['user_id'].to_i return peep end + + def timestamp_to_time_object(timestamp) + date, time = timestamp.split(" ") + year, month, day = date.split("-") + hour, minute, second = time.split(":") + return Time.new(year, month, day, hour, minute, second) + end end diff --git a/spec/peep_repository_spec.rb b/spec/peep_repository_spec.rb index 3da3a395da..9df5141e38 100644 --- a/spec/peep_repository_spec.rb +++ b/spec/peep_repository_spec.rb @@ -9,14 +9,13 @@ it 'returns a list of all peeps' do repo = PeepRepository.new peeps = repo.all - expect(peeps.length).to eq 7 expect(peeps).to include( have_attributes( id: 1, content: 'content_1', - time_posted: Time.new('2023-05-01 17:15:32'), + time_posted: Time.new(2023, 05, 01, 17, 15, 32), user_id: 1 ) ) @@ -25,7 +24,7 @@ have_attributes( id: 5, content: 'content_5', - time_posted: Time.new('1999-04-19 16:59:59'), + time_posted: Time.new(1999, 04, 19, 16, 59, 59), user_id: 1 ) ) @@ -38,7 +37,7 @@ expect(peep.id).to eq 1 expect(peep.content).to eq 'content_1' - expect(peep.time_posted).to eq Time.new('2023-05-01 17:15:32') + expect(peep.time_posted).to eq Time.new(2023, 05, 01, 17, 15, 32) expect(peep.user_id).to eq 1 end @@ -48,7 +47,7 @@ expect(peep.id).to eq 4 expect(peep.content).to eq 'content_4' - expect(peep.time_posted).to eq Time.new('2022-06-21 22:01:02') + expect(peep.time_posted).to eq Time.new(2022, 06, 21, 22, 01, 02) expect(peep.user_id).to eq 4 end end From 469293e31f342c7e7aa8d171801450e61bd3a6a0 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 20:40:59 +0100 Subject: [PATCH 12/56] Write GET / route and initial homepage html --- app.rb | 17 +++++++++++++++++ lib/peep.rb | 2 +- spec/integration/app_spec.rb | 33 +++++++++++++++++++++++++++------ views/index.erb | 13 +++++++++++++ 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 views/index.erb diff --git a/app.rb b/app.rb index 1c4174713f..47c5a0f989 100644 --- a/app.rb +++ b/app.rb @@ -1,5 +1,10 @@ require 'sinatra/base' require 'sinatra/reloader' +require_relative 'lib/peep_repository' +require_relative 'lib/user_repository' +require_relative 'lib/database_connection' + +DatabaseConnection.connect class Application < Sinatra::Base configure :development do @@ -7,4 +12,16 @@ class Application < Sinatra::Base also_reload 'lib/user_repository' also_reload 'lib/peep_repository' end + + get '/' do + peep_repo = PeepRepository.new + user_repo = UserRepository.new + @peeps = peep_repo.all + @peeps.each do |peep| + peep.user = user_repo.find(peep.user_id) + end + + + erb(:index) + end end diff --git a/lib/peep.rb b/lib/peep.rb index 5fc9e57fcf..e772c88214 100644 --- a/lib/peep.rb +++ b/lib/peep.rb @@ -1,3 +1,3 @@ class Peep - attr_accessor :id, :content, :time_posted, :user_id + attr_accessor :id, :content, :time_posted, :user_id, :user end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index d07b117ba5..4222b167d3 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -8,21 +8,42 @@ let(:app) { Application.new } before(:each) do - reset_user_table + reset_users_table reset_peeps_table end describe 'GET /' do - xit 'returns 200 OK' do + it 'returns 200 OK' do + response = get('/') + expect(response.status).to eq 200 end - xit 'returns returns html with all peeps' do - end + it 'returns returns html with all peeps' do + response = get('/') + + expect(response.body).to include '

All Peeps

' + + expect(response.body).to include 'content_1' + expect(response.body).to include '2023-05-01 17:15:32' + expect(response.body).to include 'username_1' - xit 'returns html with link to sign up' do + expect(response.body).to include 'content_3' + expect(response.body).to include '2022-06-21 00:01:02' + expect(response.body).to include 'username_3' + + expect(response.body).to include 'content_4' + expect(response.body).to include '2022-06-21 22:01:02' + expect(response.body).to include 'username_4' end - xit 'returns html with link to post a new peep' do + it 'returns html with link to sign up' do + response = get('/') + expect(response.body).to include 'Sign Up' + end + + it 'returns html with link to post a new peep' do + response = get('/') + expect(response.body).to include 'Add new peep' end end diff --git a/views/index.erb b/views/index.erb new file mode 100644 index 0000000000..bdd6865d24 --- /dev/null +++ b/views/index.erb @@ -0,0 +1,13 @@ + + + +

Sign Up

+

Add new peep

+

All Peeps

+ <% @peeps.each do |peep| %> +

<%=peep.content %>

+

<%=peep.time_posted %>

+

<%=peep.user.username %>

+ <% end %> + + \ No newline at end of file From e3ae33e16de208ef58d36a78b028b5991b5dfb8b Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 20:54:02 +0100 Subject: [PATCH 13/56] Write GET /sign-up route and sign up page html --- app.rb | 10 ++++++---- spec/integration/app_spec.rb | 23 +++++++++++++++++------ views/sign_up.erb | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 views/sign_up.erb diff --git a/app.rb b/app.rb index 47c5a0f989..f6227ce325 100644 --- a/app.rb +++ b/app.rb @@ -15,13 +15,15 @@ class Application < Sinatra::Base get '/' do peep_repo = PeepRepository.new - user_repo = UserRepository.new @peeps = peep_repo.all - @peeps.each do |peep| - peep.user = user_repo.find(peep.user_id) - end + user_repo = UserRepository.new + @peeps.each { |peep| peep.user = user_repo.find(peep.user_id) } erb(:index) end + + get '/sign-up' do + erb(:sign_up) + end end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 4222b167d3..a4c217c5b7 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -46,15 +46,26 @@ expect(response.body).to include 'Add new peep' end end - + describe 'GET /sign-up' do - xit 'returns 200 OK' do + it 'returns 200 OK' do + response = get('/sign-up') + expect(response.status).to eq 200 end - - xit 'returns html with sign up form using POST /sign-up route' do + + it 'returns html with sign up form using POST /sign-up route' do + response = get('sign-up') + expect(response.body).to include '
' + expect(response.body).to include '' + expect(response.body).to include '' + expect(response.body).to include '' + expect(response.body).to include '' + expect(response.body).to include '' end - - xit 'returns html with link back to homepage' do + + it 'returns html with link back to homepage' do + response = get('sign-up') + expect(response.body).to include 'Back to homepage' end end diff --git a/views/sign_up.erb b/views/sign_up.erb new file mode 100644 index 0000000000..ecbe91d047 --- /dev/null +++ b/views/sign_up.erb @@ -0,0 +1,17 @@ + + + +

Back to homepage

+ + + + + + + + + + +
+ + \ No newline at end of file From ae84c4d427d31e2969189cc1944e5ccefc736dff Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 21:04:08 +0100 Subject: [PATCH 14/56] Write GET /new-peep route and html form: --- app.rb | 4 ++++ spec/integration/app_spec.rb | 26 ++++++++++++++++++-------- views/new_peep.erb | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 views/new_peep.erb diff --git a/app.rb b/app.rb index f6227ce325..eccb98ddbf 100644 --- a/app.rb +++ b/app.rb @@ -26,4 +26,8 @@ class Application < Sinatra::Base get '/sign-up' do erb(:sign_up) end + + get '/new-peep' do + erb(:new_peep) + end end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index a4c217c5b7..1fe0087d2b 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -54,7 +54,7 @@ end it 'returns html with sign up form using POST /sign-up route' do - response = get('sign-up') + response = get('/sign-up') expect(response.body).to include '
' expect(response.body).to include '' expect(response.body).to include '' @@ -64,19 +64,29 @@ end it 'returns html with link back to homepage' do - response = get('sign-up') + response = get('/sign-up') expect(response.body).to include 'Back to homepage' end end - + describe 'GET /new-peep' do - xit 'returns 200 OK' do + it 'returns 200 OK' do + response = get('/new-peep') + expect(response.status).to eq 200 end - - xit 'returns html with new peep form using POST /new-peep route' do + + it 'returns html with new peep form using POST /new-peep route' do + response = get('/new-peep') + expect(response.body).to include '' + expect(response.body).to include '' + expect(response.body).to include '' + expect(response.body).to include '' + expect(response.body).to include '' end - - xit 'returns html with link back to the homepage' do + + it 'returns html with link back to the homepage' do + response = get('/new-peep') + expect(response.body).to include 'Back to homepage' end end diff --git a/views/new_peep.erb b/views/new_peep.erb new file mode 100644 index 0000000000..e62ae6edb3 --- /dev/null +++ b/views/new_peep.erb @@ -0,0 +1,15 @@ + + + +

Back to homepage

+ + + + + + + + +
+ + \ No newline at end of file From 3065380af4a8d3535d156e1324aa833679f55657 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 21:21:20 +0100 Subject: [PATCH 15/56] Write POST /sign-up route with success and html --- app.rb | 11 ++++++++ spec/integration/app_spec.rb | 52 ++++++++++++++++++++++++++++++------ views/sign_up_success.erb | 8 ++++++ 3 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 views/sign_up_success.erb diff --git a/app.rb b/app.rb index eccb98ddbf..4ddde20780 100644 --- a/app.rb +++ b/app.rb @@ -30,4 +30,15 @@ class Application < Sinatra::Base get '/new-peep' do erb(:new_peep) end + + post '/sign-up' do + user = User.new + user.email = params[:email] + user.password = params[:password] + user.name = params[:name] + user.username = params[:username] + repo = UserRepository.new + repo.create(user) + erb(:sign_up_success) + end end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 1fe0087d2b..7c48aa90d7 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -89,19 +89,55 @@ expect(response.body).to include 'Back to homepage' end end - + describe 'POST /sign-up' do context 'when used with valid params' do - xit 'returns 200 OK' do + it 'returns 200 OK' do + response = post( + '/sign-up', + email: 'new@gmail.com', + password: 'new_password', + name: 'New Name', + username: 'new_username' + ) + expect(response.status).to eq 200 end - - xit 'returns html with success message' do + + it 'returns html with success message' do + response = post( + '/sign-up', + email: 'new@gmail.com', + password: 'new_password', + name: 'New Name', + username: 'new_username' + ) + expect(response.body).to include '

Success!

' + expect(response.body).to include '

Thanks for signing up!

' end - - xit 'returns html with link back to the homepage' do + + it 'returns html with link back to the homepage' do + response = post('/sign-up') + expect(response.body).to include 'Back to homepage' end - - xit 'adds a new user to the database' do + + it 'adds a new user to the database' do + response = post( + '/sign-up', + email: 'new@gmail.com', + password: 'new_password', + name: 'New Name', + username: 'new_username' + ) + + repo = UserRepository.new + expect(repo.all).to include( + have_attributes( + email: 'new@gmail.com', + password: 'new_password', + name: 'New Name', + username: 'new_username' + ) + ) end end diff --git a/views/sign_up_success.erb b/views/sign_up_success.erb new file mode 100644 index 0000000000..c0d9c9b86e --- /dev/null +++ b/views/sign_up_success.erb @@ -0,0 +1,8 @@ + + + +

Back to homepage

+

Success!

+

Thanks for signing up!

+ + \ No newline at end of file From 7bb239cd6d05eda9cc5cc79ad2ba7b029bbc1209 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 21:41:12 +0100 Subject: [PATCH 16/56] Write POST /new-peep route for valid params and html success page --- app.rb | 10 +++++++++ spec/integration/app_spec.rb | 42 ++++++++++++++++++++++++++++-------- views/new_peep_success.erb | 9 ++++++++ 3 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 views/new_peep_success.erb diff --git a/app.rb b/app.rb index 4ddde20780..7e80c73fe0 100644 --- a/app.rb +++ b/app.rb @@ -41,4 +41,14 @@ class Application < Sinatra::Base repo.create(user) erb(:sign_up_success) end + + post '/new-peep' do + peep = Peep.new + peep.content = params[:content] + peep.time_posted = params[:time_posted] || Time.new + peep.user_id = params[:user_id] + repo = PeepRepository.new + repo.create(peep) + erb(:new_peep_success) + end end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 7c48aa90d7..50708b4be3 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -151,19 +151,43 @@ describe 'POST /new-peep' do context 'when used with valid params' do - xit 'returns 200 OK' do + it 'returns 200 OK' do + response = post('/new-peep') + expect(response.status).to eq 200 end - - xit 'returns html with success message' do + + it 'returns html with success message' do + response = post('/new-peep') + expect(response.body).to include '

Success!

' + expect(response.body).to include '

You added a new peep!

' end - - xit 'returns html with link back to the homepage' do + + it 'returns html with link back to the homepage' do + response = post('/new-peep') + expect(response.body).to include 'Back to homepage' end - - xit 'returns html with option to create another new peep' do + + it 'returns html with option to create another new peep' do + response = post('/new-peep') + expect(response.body).to include 'Add another peep' end - - xit 'adds a new peep to the database' do + + it 'adds a new peep to the database' do + response = post( + '/new-peep', + content: 'this is new content', + time_posted: Time.new(2000, 1, 2, 3, 4, 5), + user_id: '3' + ) + repo = PeepRepository.new + expect(repo.all).to include( + have_attributes( + id: 8, + content: 'this is new content', + time_posted: Time.new(2000, 1, 2, 3, 4, 5), + user_id: 3 + ) + ) end end diff --git a/views/new_peep_success.erb b/views/new_peep_success.erb new file mode 100644 index 0000000000..488bcfe5a8 --- /dev/null +++ b/views/new_peep_success.erb @@ -0,0 +1,9 @@ + + + +

Back to homepage

+

Success!

+

You added a new peep!

+

Add another peep

+ + \ No newline at end of file From c97f8a3be5f7de0ac0f7a635aeac8e97220f0f79 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 21:42:51 +0100 Subject: [PATCH 17/56] Remove time added from new peep form due to dynamic generation --- spec/integration/app_spec.rb | 1 - views/new_peep.erb | 2 -- 2 files changed, 3 deletions(-) diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 50708b4be3..39777086c8 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -79,7 +79,6 @@ response = get('/new-peep') expect(response.body).to include '
' expect(response.body).to include '' - expect(response.body).to include '' expect(response.body).to include '' expect(response.body).to include '' end diff --git a/views/new_peep.erb b/views/new_peep.erb index e62ae6edb3..1f7e6739c8 100644 --- a/views/new_peep.erb +++ b/views/new_peep.erb @@ -5,8 +5,6 @@ - - From e022178569cd1f2959ee223e90869d374891a55e Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 21:52:54 +0100 Subject: [PATCH 18/56] Update GET / to return peeps in reverse chronological order --- app.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app.rb b/app.rb index 7e80c73fe0..ecee83df72 100644 --- a/app.rb +++ b/app.rb @@ -15,8 +15,8 @@ class Application < Sinatra::Base get '/' do peep_repo = PeepRepository.new - @peeps = peep_repo.all - + peeps = peep_repo.all + @peeps = peeps.sort_by(&:time_posted).reverse user_repo = UserRepository.new @peeps.each { |peep| peep.user = user_repo.find(peep.user_id) } From 10c14945f2efbdcb601044452841a33638e467a2 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Fri, 5 May 2023 21:53:12 +0100 Subject: [PATCH 19/56] Fix rubocop offenses --- lib/peep_repository.rb | 5 ++--- spec/peep_repository_spec.rb | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/peep_repository.rb b/lib/peep_repository.rb index 8554f9353c..a42b3e99bc 100644 --- a/lib/peep_repository.rb +++ b/lib/peep_repository.rb @@ -4,8 +4,7 @@ class PeepRepository def all sql = 'SELECT * FROM peeps;' records = DatabaseConnection.exec_params(sql, []) - x = records.map { |record| create_peep_from_record(record) } - x + records.map { |record| create_peep_from_record(record) } end def find(id) @@ -33,7 +32,7 @@ def create_peep_from_record(record) end def timestamp_to_time_object(timestamp) - date, time = timestamp.split(" ") + date, time = timestamp.split year, month, day = date.split("-") hour, minute, second = time.split(":") return Time.new(year, month, day, hour, minute, second) diff --git a/spec/peep_repository_spec.rb b/spec/peep_repository_spec.rb index 9df5141e38..6dd3887829 100644 --- a/spec/peep_repository_spec.rb +++ b/spec/peep_repository_spec.rb @@ -15,7 +15,7 @@ have_attributes( id: 1, content: 'content_1', - time_posted: Time.new(2023, 05, 01, 17, 15, 32), + time_posted: Time.new(2023, 5, 1, 17, 15, 32), user_id: 1 ) ) @@ -24,7 +24,7 @@ have_attributes( id: 5, content: 'content_5', - time_posted: Time.new(1999, 04, 19, 16, 59, 59), + time_posted: Time.new(1999, 4, 19, 16, 59, 59), user_id: 1 ) ) @@ -37,7 +37,7 @@ expect(peep.id).to eq 1 expect(peep.content).to eq 'content_1' - expect(peep.time_posted).to eq Time.new(2023, 05, 01, 17, 15, 32) + expect(peep.time_posted).to eq Time.new(2023, 5, 1, 17, 15, 32) expect(peep.user_id).to eq 1 end @@ -47,7 +47,7 @@ expect(peep.id).to eq 4 expect(peep.content).to eq 'content_4' - expect(peep.time_posted).to eq Time.new(2022, 06, 21, 22, 01, 02) + expect(peep.time_posted).to eq Time.new(2022, 6, 21, 22, 1, 2) expect(peep.user_id).to eq 4 end end From d38fe323149f6c7ba89fc848f93a8cb3a16e5de7 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Sat, 6 May 2023 12:33:53 +0100 Subject: [PATCH 20/56] sanitise new-user input to check for empty strings --- app.rb | 5 +++ spec/integration/app_spec.rb | 77 +++++++++++++++++++++++++++++++++--- views/sign_up_failure.erb | 10 +++++ 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 views/sign_up_failure.erb diff --git a/app.rb b/app.rb index ecee83df72..e4106a5b07 100644 --- a/app.rb +++ b/app.rb @@ -32,6 +32,11 @@ class Application < Sinatra::Base end post '/sign-up' do + if params.values.any?('') + status 400 + return erb(:sign_up_failure) + end + user = User.new user.email = params[:email] user.password = params[:password] diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 39777086c8..13274769ca 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -127,7 +127,7 @@ name: 'New Name', username: 'new_username' ) - + repo = UserRepository.new expect(repo.all).to include( have_attributes( @@ -139,13 +139,80 @@ ) end end - + context 'when used with invalid params' do - xit 'returns 400 Bad Request' do + context 'when email is empty' + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: '', + password: 'new_password', + name: 'New Name', + username: 'new_username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' end - # TODO - Consider invalid params - end + context 'when password is empty' + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: '', + name: 'New Name', + username: 'new_username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end + + context 'when name is empty' + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: 'new_password', + name: '', + username: 'new_username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end + + context 'when username is empty' + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: 'new_password', + name: 'New Name', + username: '' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end + end end describe 'POST /new-peep' do diff --git a/views/sign_up_failure.erb b/views/sign_up_failure.erb new file mode 100644 index 0000000000..583da48895 --- /dev/null +++ b/views/sign_up_failure.erb @@ -0,0 +1,10 @@ + + + +

Back to homepage

+

Error!

+

One or more of your inputs was invalid

+

Try again

+ + + \ No newline at end of file From b651d7edea4e650bc7b4e0749a934d7a2ef11245 Mon Sep 17 00:00:00 2001 From: Evan Thomas Date: Sat, 6 May 2023 13:03:22 +0100 Subject: [PATCH 21/56] Sanitise user input for invalid characters --- app.rb | 8 +- spec/integration/app_spec.rb | 208 ++++++++++++++++++++++++----------- 2 files changed, 151 insertions(+), 65 deletions(-) diff --git a/app.rb b/app.rb index e4106a5b07..7e54956f91 100644 --- a/app.rb +++ b/app.rb @@ -32,7 +32,7 @@ class Application < Sinatra::Base end post '/sign-up' do - if params.values.any?('') + unless params.values.all? { |input| is_input_valid?(input) } status 400 return erb(:sign_up_failure) end @@ -56,4 +56,10 @@ class Application < Sinatra::Base repo.create(peep) erb(:new_peep_success) end + + private + + def is_input_valid?(input) + input != '' && !input.match(/[<>]/) + end end diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb index 13274769ca..a3f51c3db0 100644 --- a/spec/integration/app_spec.rb +++ b/spec/integration/app_spec.rb @@ -141,76 +141,156 @@ end context 'when used with invalid params' do - context 'when email is empty' - it 'returns 400 Bad Request and html failure page' do - response = post( - '/sign-up', - email: '', - password: 'new_password', - name: 'New Name', - username: 'new_username' - ) - expect(response.status).to eq 400 - expect(response.body).to include '

Error!

' - expect(response.body).to include ( - '

One or more of your inputs was invalid

' - ) - expect(response.body).to include 'Back to homepage' - expect(response.body).to include 'Try again' + context 'when email is empty' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: '', + password: 'new_password', + name: 'New Name', + username: 'new_username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end end - context 'when password is empty' - it 'returns 400 Bad Request and html failure page' do - response = post( - '/sign-up', - email: 'new_email', - password: '', - name: 'New Name', - username: 'new_username' - ) - expect(response.status).to eq 400 - expect(response.body).to include '

Error!

' - expect(response.body).to include ( - '

One or more of your inputs was invalid

' - ) - expect(response.body).to include 'Back to homepage' - expect(response.body).to include 'Try again' + context 'when password is empty' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: '', + name: 'New Name', + username: 'new_username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end end - context 'when name is empty' - it 'returns 400 Bad Request and html failure page' do - response = post( - '/sign-up', - email: 'new_email', - password: 'new_password', - name: '', - username: 'new_username' - ) - expect(response.status).to eq 400 - expect(response.body).to include '

Error!

' - expect(response.body).to include ( - '

One or more of your inputs was invalid

' - ) - expect(response.body).to include 'Back to homepage' - expect(response.body).to include 'Try again' + context 'when name is empty' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: 'new_password', + name: '', + username: 'new_username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end end - context 'when username is empty' - it 'returns 400 Bad Request and html failure page' do - response = post( - '/sign-up', - email: 'new_email', - password: 'new_password', - name: 'New Name', - username: '' - ) - expect(response.status).to eq 400 - expect(response.body).to include '

Error!

' - expect(response.body).to include ( - '

One or more of your inputs was invalid

' - ) - expect(response.body).to include 'Back to homepage' - expect(response.body).to include 'Try again' + context 'when username is empty' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: 'new_password', + name: 'New Name', + username: '' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end + end + + context 'when email has invalid characters' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email<', + password: 'new_password', + name: 'New Name', + username: 'username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end + end + + context 'when password has invalid characters' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: 'new_password>', + name: 'New Name', + username: 'username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end + end + + context 'when name has invalid characters' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: 'new_password', + name: 'New Name', + username: 'username' + ) + expect(response.status).to eq 400 + expect(response.body).to include '

Error!

' + expect(response.body).to include ( + '

One or more of your inputs was invalid

' + ) + expect(response.body).to include 'Back to homepage' + expect(response.body).to include 'Try again' + end + end + + context 'when username has invalid characters' do + it 'returns 400 Bad Request and html failure page' do + response = post( + '/sign-up', + email: 'new_email', + password: 'new_password', + name: 'New Name', + username: '