From 67f3c1dc75590d08130a144c9f9ea228b4e009c6 Mon Sep 17 00:00:00 2001
From: Julian Festing
Date: Sun, 7 May 2023 14:42:57 +0100
Subject: [PATCH 01/17] passed all tests for chitter repository
---
Gemfile | 7 +
Gemfile.lock | 28 ++++
README.md | 12 +-
app.rb | 13 ++
config.ru | 0
docs/chitter_design_recipe.md | 229 ++++++++++++++++++++++++++++++++
docs/chitter_table_recipe.md | 84 ++++++++++++
lib/chitter.rb | 5 +
lib/chitter_repository.rb | 47 +++++++
lib/database_connection.rb | 26 ++++
spec/chitter_repository_spec.rb | 40 ++++++
spec/chitters_table.sql | 5 +
spec/integration/app_spec.rb | 0
spec/seeds.sql | 0
spec/seeds_chitters.sql | 17 +++
spec/spec_helper.rb | 5 +
16 files changed, 510 insertions(+), 8 deletions(-)
create mode 100644 app.rb
create mode 100644 config.ru
create mode 100644 docs/chitter_design_recipe.md
create mode 100644 docs/chitter_table_recipe.md
create mode 100644 lib/chitter.rb
create mode 100644 lib/chitter_repository.rb
create mode 100644 lib/database_connection.rb
create mode 100644 spec/chitter_repository_spec.rb
create mode 100644 spec/chitters_table.sql
create mode 100644 spec/integration/app_spec.rb
create mode 100644 spec/seeds.sql
create mode 100644 spec/seeds_chitters.sql
diff --git a/Gemfile b/Gemfile
index b1a320395a..c205bc57f8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,3 +11,10 @@ end
group :development, :test do
gem 'rubocop', '1.20'
end
+
+gem "pg", "~> 1.5"
+
+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..d7ce111533 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -5,9 +5,18 @@ 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)
+ pg (1.5.3)
+ 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 +45,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 +56,36 @@ 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
+ pg (~> 1.5)
+ 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/README.md b/README.md
index 465eda879b..d38680434b 100644
--- a/README.md
+++ b/README.md
@@ -23,16 +23,12 @@ As a Maker
So that I can let people know what I am doing
I want to post a message (peep) to chitter
-As a maker
-So that I can see what others are saying
-I want to see all peeps in reverse chronological order
-
-As a Maker
-So that I can better appreciate the context of a peep
I want to see the time at which it was made
-As a Maker
-So that I can post messages on Chitter as me
+function
+I want to see all peeps in reverse chronological order
+
+erb stuff
I want to sign up for Chitter
HARDER
diff --git a/app.rb b/app.rb
new file mode 100644
index 0000000000..fcf4aacebb
--- /dev/null
+++ b/app.rb
@@ -0,0 +1,13 @@
+require_relative 'lib/database_connection'
+
+# We need to give the database name to the method `connect`.
+DatabaseConnection.connect('music_library')
+
+# Perform a SQL query on the database and get the result set.
+sql = 'SELECT id, title FROM albums;'
+result = DatabaseConnection.exec_params(sql, [])
+
+# Print out each record from the result set .
+result.each do |record|
+ p record
+end
\ No newline at end of file
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/docs/chitter_design_recipe.md b/docs/chitter_design_recipe.md
new file mode 100644
index 0000000000..462dc3e0f5
--- /dev/null
+++ b/docs/chitter_design_recipe.md
@@ -0,0 +1,229 @@
+# {{TABLE NAME}} Model and Repository Classes Design Recipe
+
+_Copy this recipe template to design and implement Model and Repository classes for a database table._
+
+## 1. Design and create the Table
+
+If the table is already created in the database, you can skip this step.
+
+Otherwise, [follow this recipe to design and create the SQL schema for your table](./single_table_design_recipe_template.md).
+
+*In this template, we'll use an example table `students`*
+
+```
+# EXAMPLE
+
+Table: students
+
+Columns:
+id | peep | peep_time
+```
+
+## 2. Create Test SQL seeds
+
+Your tests will depend on data stored in PostgreSQL to run.
+
+If seed data is provided (or you already created it), you can skip this step.
+
+```sql
+-- EXAMPLE
+-- (file: spec/seeds_chitters.sql)
+
+-- Write your SQL seed here.
+
+-- First, you'd need to truncate the table - this is so our table is emptied between each test run,
+-- so we can start with a fresh state.
+-- (RESTART IDENTITY resets the primary key)
+
+TRUNCATE TABLE chitters RESTART IDENTITY; -- replace with your own table name.
+
+-- Below this line there should only be `INSERT` statements.
+-- Replace these statements with your own seed data.
+
+INSERT INTO chitters (peep, peep_time) VALUES ('flying solo', '16:20');
+INSERT INTO chitters (peep, peep_time) VALUES ('falling', '16:21');
+INSERT INTO chitters (peep, peep_time) VALUES ('dead', '16:22');
+
+```
+
+Run this SQL file on the database to truncate (empty) the table, and insert the seed data. Be mindful of the fact any existing records in the table will be deleted.
+
+```bash
+psql -h 127.0.0.1 chitter_database < seeds_chitters.sql
+```
+
+## 3. Define the class names
+
+Usually, the Model class name will be the capitalised table name (single instead of plural). The same name is then suffixed by `Repository` for the Repository class name.
+
+```ruby
+# EXAMPLE
+# Table name: chitters
+
+# Model class
+# (in lib/chitter.rb)
+class Chitter
+end
+
+# Repository class
+# (in lib/chitter_repository.rb)
+class ChitterRepository
+end
+```
+
+## 4. Implement the Model class
+
+Define the attributes of your Model class. You can usually map the table columns to the attributes of the class, including primary and foreign keys.
+
+```ruby
+# EXAMPLE
+# Table name: chitters
+
+# Model class
+# (in lib/chitter.rb)
+
+class Chitter
+
+ # Replace the attributes by your own columns.
+ attr_accessor :id, :peep, :peep_time
+end
+
+# The keyword attr_accessor is a special Ruby feature
+# which allows us to set and get attributes on an object,
+# here's an example:
+#
+# student = Student.new
+# student.name = 'Jo'
+# student.name
+```
+
+*You may choose to test-drive this class, but unless it contains any more logic than the example above, it is probably not needed.*
+
+## 5. Define the Repository Class interface
+
+Your Repository class will need to implement methods for each "read" or "write" operation you'd like to run against the database.
+
+Using comments, define the method signatures (arguments and return value) and what they do - write up the SQL queries that will be used by each method.
+
+```ruby
+# EXAMPLE
+# Table name: chitters
+
+# Repository class
+# (in lib/chitter_repository.rb)
+
+class ChitterRepository
+
+ # Selecting all records
+ # No arguments
+ def all
+ # Executes the SQL query:
+ # SELECT id, peep, peep_time FROM chitters;
+
+ # Returns an array of Chitter objects.
+ end
+
+ # Gets a single record by its ID
+ # One argument: the id (number)
+ def find(id)
+ # Executes the SQL query:
+ # SELECT id, name, cohort_name FROM students WHERE id = $1;
+
+ # Returns a single Student object.
+ end
+
+ # Add more methods below for each operation you'd like to implement.
+
+ # def create(student)
+ # end
+
+ # def update(student)
+ # end
+
+ # def delete(student)
+ # end
+end
+```
+
+## 6. Write Test Examples
+
+Write Ruby code that defines the expected behaviour of the Repository class, following your design from the table written in step 5.
+
+These examples will later be encoded as RSpec tests.
+
+```ruby
+# EXAMPLES
+
+# 1
+# Gets all chitters
+
+repo = ChitterRepository.new
+
+chitters = repo.all
+
+chitters.length # => 3
+
+chitters[0].id # => 1
+chitters[0].peep # => 'flying solo'
+chitters[0].peep_time # => 16:20:00
+
+chitters[1].id # => 2
+chitters[1].peep # => 'falling'
+chitters[1].peep_time # => 16:21:00
+
+# 2
+# Gets all chitters in reverse order
+
+repo = ChitterRepository.new
+
+chitters = repo.all
+
+ordered = chitters.order
+
+ordered[0].peep_time # => 16:22
+ordered[1].peep_time # => 16:21
+ordered[2].peep_time # => 16:20
+
+```
+
+Encode this example as a test.
+
+## 7. Reload the SQL seeds before each test run
+
+Running the SQL code present in the seed file will empty the table and re-insert the seed data.
+
+This is so you get a fresh table contents every time you run the test suite.
+
+```ruby
+# EXAMPLE
+
+# file: spec/student_repository_spec.rb
+
+def reset_chitters_table
+ seed_sql = File.read('spec/seeds_chitters.sql')
+ connection = PG.connect({ host: '127.0.0.1', dbname: 'chitters_database_test' })
+ connection.exec(seed_sql)
+end
+
+describe StudentRepository do
+ before(:each) do
+ reset_students_table
+ end
+
+ # (your tests will go here).
+end
+```
+
+## 8. Test-drive and implement the Repository class behaviour
+
+_After each test you write, follow the test-driving process of red, green, refactor to implement the behaviour._
+
+
+
+---
+
+**How was this resource?**
+[😫](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😫) [😕](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😕) [😐](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😐) [🙂](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=🙂) [😀](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Frepository_class_recipe_template.md&prefill_Sentiment=😀)
+Click an emoji to tell us.
+
+
\ No newline at end of file
diff --git a/docs/chitter_table_recipe.md b/docs/chitter_table_recipe.md
new file mode 100644
index 0000000000..7b3e3d3695
--- /dev/null
+++ b/docs/chitter_table_recipe.md
@@ -0,0 +1,84 @@
+# Single Table Design Recipe Template
+
+_Copy this recipe template to design and create a database table from a specification._
+
+## 1. Extract nouns from the user stories or specification
+
+```
+As a Maker
+So that I can let people know what I am doing
+I want to post a message (peep) to chitter
+
+As a maker
+So that I can see what others are saying
+I want to see all peeps in reverse chronological order
+
+As a Maker
+So that I can better appreciate the context of a peep
+I want to see the time at which it was made
+```
+
+```
+Nouns:
+
+chiter, peep, peep_time
+```
+
+## 2. Infer the Table Name and Columns
+
+Put the different nouns in this table. Replace the example with your own nouns.
+
+| Record | Properties |
+| --------------------- | ------------------ |
+| chitter | peep, peep_time
+
+Name of the table (always plural): `chitters`
+
+Column names: `peep`, `peep_time`
+
+## 3. Decide the column types.
+
+[Here's a full documentation of PostgreSQL data types](https://www.postgresql.org/docs/current/datatype.html).
+
+Most of the time, you'll need either `text`, `int`, `bigint`, `numeric`, or `boolean`. If you're in doubt, do some research or ask your peers.
+
+Remember to **always** have the primary key `id` as a first column. Its type will always be `SERIAL`.
+
+```
+# EXAMPLE:
+
+id: SERIAL
+peep: text
+peep_time: time
+```
+
+## 4. Write the SQL.
+
+```sql
+-- EXAMPLE
+-- file: chitters_table.sql
+
+-- Replace the table name, columm names and types.
+
+CREATE TABLE chitters (
+ id SERIAL PRIMARY KEY,
+ peep text,
+ peep_time time
+);
+```
+
+## 5. Create the table.
+
+```bash
+psql -h 127.0.0.1 chitter_database < chitters_table.sql
+```
+
+
+
+---
+
+**How was this resource?**
+[😫](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Fsingle_table_design_recipe_template.md&prefill_Sentiment=😫) [😕](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Fsingle_table_design_recipe_template.md&prefill_Sentiment=😕) [😐](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Fsingle_table_design_recipe_template.md&prefill_Sentiment=😐) [🙂](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Fsingle_table_design_recipe_template.md&prefill_Sentiment=🙂) [😀](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Fsingle_table_design_recipe_template.md&prefill_Sentiment=😀)
+Click an emoji to tell us.
+
+
\ No newline at end of file
diff --git a/lib/chitter.rb b/lib/chitter.rb
new file mode 100644
index 0000000000..829143c432
--- /dev/null
+++ b/lib/chitter.rb
@@ -0,0 +1,5 @@
+class Chitter
+
+ # Replace the attributes by your own columns.
+ attr_accessor :id, :peep, :peep_time
+end
\ No newline at end of file
diff --git a/lib/chitter_repository.rb b/lib/chitter_repository.rb
new file mode 100644
index 0000000000..349e77da10
--- /dev/null
+++ b/lib/chitter_repository.rb
@@ -0,0 +1,47 @@
+require 'chitter'
+
+class ChitterRepository
+
+ # Selecting all records
+ # No arguments
+ def all
+ sql = 'SELECT id, peep, peep_time FROM chitters;'
+ result_set = DatabaseConnection.exec_params(sql, [])
+
+ chitters = []
+
+ result_set.each do |record|
+ chitter = Chitter.new
+
+ chitter.id = record['id'].to_i
+ chitter.peep = record['peep']
+ chitter.peep_time = record['peep_time']
+
+
+ chitters << chitter
+ end
+
+ return chitters
+ end
+
+ def order
+ sql = 'SELECT id, peep, peep_time FROM chitters;'
+ result_set = DatabaseConnection.exec_params(sql, [])
+
+ chitters = []
+
+ result_set.each do |record|
+ chitter = Chitter.new
+
+ chitter.id = record['id'].to_i
+ chitter.peep = record['peep']
+ chitter.peep_time = record['peep_time']
+
+
+ chitters << chitter
+ end
+
+ return chitters.reverse
+ end
+
+end
\ No newline at end of file
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/spec/chitter_repository_spec.rb b/spec/chitter_repository_spec.rb
new file mode 100644
index 0000000000..7c21280955
--- /dev/null
+++ b/spec/chitter_repository_spec.rb
@@ -0,0 +1,40 @@
+require 'chitter_repository'
+
+def reset_chitters_table
+ seed_sql = File.read('spec/seeds_chitters.sql')
+ connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_database_test' })
+ connection.exec(seed_sql)
+end
+
+describe ChitterRepository do
+ before(:each) do
+ reset_chitters_table
+ end
+
+ it 'Gets all chitters' do
+ repo = ChitterRepository.new
+
+ chitters = repo.all
+
+ expect(chitters.length).to eq 3
+
+ expect(chitters[0].id).to eq 1
+ expect(chitters[0].peep).to eq 'flying solo'
+ expect(chitters[0].peep_time).to eq '16:20:00'
+
+ expect(chitters[1].id).to eq 2
+ expect(chitters[1].peep).to eq 'falling'
+ expect(chitters[1].peep_time).to eq '16:21:00'
+ end
+
+ it 'Gets all chitters in reverse order' do
+ repo = ChitterRepository.new
+
+ ordered = repo.order
+
+ expect(ordered[0].peep_time).to eq '16:22:00'
+ expect(ordered[1].peep_time).to eq '16:21:00'
+ expect(ordered[2].peep_time).to eq '16:20:00'
+ expect(ordered[2].peep).to eq 'flying solo'
+ end
+end
\ No newline at end of file
diff --git a/spec/chitters_table.sql b/spec/chitters_table.sql
new file mode 100644
index 0000000000..309dc0a455
--- /dev/null
+++ b/spec/chitters_table.sql
@@ -0,0 +1,5 @@
+CREATE TABLE chitters (
+ id SERIAL PRIMARY KEY,
+ peep text,
+ peep_time time
+);
\ 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
diff --git a/spec/seeds.sql b/spec/seeds.sql
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spec/seeds_chitters.sql b/spec/seeds_chitters.sql
new file mode 100644
index 0000000000..29b26b4d20
--- /dev/null
+++ b/spec/seeds_chitters.sql
@@ -0,0 +1,17 @@
+-- EXAMPLE
+-- (file: spec/seeds_chitters.sql)
+
+-- Write your SQL seed here.
+
+-- First, you'd need to truncate the table - this is so our table is emptied between each test run,
+-- so we can start with a fresh state.
+-- (RESTART IDENTITY resets the primary key)
+
+TRUNCATE TABLE chitters RESTART IDENTITY; -- replace with your own table name.
+
+-- Below this line there should only be `INSERT` statements.
+-- Replace these statements with your own seed data.
+
+INSERT INTO chitters (peep, peep_time) VALUES ('flying solo', '16:20');
+INSERT INTO chitters (peep, peep_time) VALUES ('falling', '16:21');
+INSERT INTO chitters (peep, peep_time) VALUES ('dead', '16:22');
\ No newline at end of file
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 252747d899..b9b541f506 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,5 +1,10 @@
require 'simplecov'
require 'simplecov-console'
+require 'database_connection'
+
+# Make sure this connects to your test database
+# (its name should end with '_test')
+DatabaseConnection.connect('chitter_database_test')
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::Console,
From e58a81ff717a2b7ae363f59c441312d15b78ac76 Mon Sep 17 00:00:00 2001
From: Julian Festing
Date: Sun, 7 May 2023 17:51:35 +0100
Subject: [PATCH 02/17] passed create new test and post new test
---
app.rb | 48 +++++++++++---
config.ru | 2 +
lib/chitter_repository.rb | 30 +++------
lib/database_connection.rb | 20 ++++--
spec/chitter_repository_spec.rb | 28 +++++---
spec/integration/app_spec.rb | 66 ++++++++++++++++++
spec/spec_helper.rb | 114 +++++++++++++++++++++++++++-----
views/about.erb | 1 +
views/chitter_created.erb | 3 +
views/chitters.erb | 12 ++++
views/index.erb | 3 +
views/new_chitter.erb | 8 +++
12 files changed, 275 insertions(+), 60 deletions(-)
create mode 100644 views/about.erb
create mode 100644 views/chitter_created.erb
create mode 100644 views/chitters.erb
create mode 100644 views/index.erb
create mode 100644 views/new_chitter.erb
diff --git a/app.rb b/app.rb
index fcf4aacebb..5ad320e339 100644
--- a/app.rb
+++ b/app.rb
@@ -1,13 +1,45 @@
+require 'sinatra'
+require "sinatra/reloader"
require_relative 'lib/database_connection'
+require_relative 'lib/chitter_repository'
-# We need to give the database name to the method `connect`.
-DatabaseConnection.connect('music_library')
+DatabaseConnection.connect
-# Perform a SQL query on the database and get the result set.
-sql = 'SELECT id, title FROM albums;'
-result = DatabaseConnection.exec_params(sql, [])
+class Application < Sinatra::Base
+ configure :development do
+ register Sinatra::Reloader
+ also_reload 'lib/chitter_repository'
+ end
-# Print out each record from the result set .
-result.each do |record|
- p record
+ get '/' do
+ return erb(:index)
+ end
+
+ get '/about' do
+ return erb(:about)
+ end
+
+ get '/chitters' do
+ repo = ChitterRepository.new
+ @chitters = repo.all
+
+ return erb(:chitters)
+ end
+
+ post '/chitters' do
+ repo = ChitterRepository.new
+ chitter = Chitter.new
+
+ chitter.peep = params[:peep]
+ chitter.peep_time = params[:peep_time]
+ repo.create(chitter)
+
+ @new_chitter = params[:peep]
+
+ return erb(:chitter_created)
+ end
+
+ get '/chitters/new' do
+ return erb(:new_chitter)
+ end
end
\ No newline at end of file
diff --git a/config.ru b/config.ru
index e69de29bb2..30570ef105 100644
--- a/config.ru
+++ b/config.ru
@@ -0,0 +1,2 @@
+require './app'
+run Application
\ No newline at end of file
diff --git a/lib/chitter_repository.rb b/lib/chitter_repository.rb
index 349e77da10..7d25b0efcf 100644
--- a/lib/chitter_repository.rb
+++ b/lib/chitter_repository.rb
@@ -1,10 +1,9 @@
-require 'chitter'
+require_relative '../lib/chitter'
class ChitterRepository
- # Selecting all records
- # No arguments
def all
+
sql = 'SELECT id, peep, peep_time FROM chitters;'
result_set = DatabaseConnection.exec_params(sql, [])
@@ -21,27 +20,14 @@ def all
chitters << chitter
end
- return chitters
+ return chitters.reverse
end
- def order
- sql = 'SELECT id, peep, peep_time FROM chitters;'
- result_set = DatabaseConnection.exec_params(sql, [])
-
- chitters = []
-
- result_set.each do |record|
- chitter = Chitter.new
-
- chitter.id = record['id'].to_i
- chitter.peep = record['peep']
- chitter.peep_time = record['peep_time']
+ def create(chitter)
+ sql = 'INSERT INTO chitters (peep, peep_time) VALUES($1, $2);'
+ params = [chitter.peep, chitter.peep_time]
+ record = DatabaseConnection.exec_params(sql, params)
-
- chitters << chitter
- end
-
- return chitters.reverse
+ return nil
end
-
end
\ No newline at end of file
diff --git a/lib/database_connection.rb b/lib/database_connection.rb
index ac9ec32a31..4e4953737d 100644
--- a/lib/database_connection.rb
+++ b/lib/database_connection.rb
@@ -8,13 +8,22 @@ 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 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 = 'chitter_database_test'
+ else
+ database_name = 'chitter_database'
+ 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'\
@@ -23,4 +32,5 @@ def self.exec_params(query, params)
end
@connection.exec_params(query, params)
end
-end
\ No newline at end of file
+end
+
diff --git a/spec/chitter_repository_spec.rb b/spec/chitter_repository_spec.rb
index 7c21280955..9293d269f8 100644
--- a/spec/chitter_repository_spec.rb
+++ b/spec/chitter_repository_spec.rb
@@ -11,30 +11,38 @@ def reset_chitters_table
reset_chitters_table
end
- it 'Gets all chitters' do
+ it 'Gets all chitters in reverse order' do
repo = ChitterRepository.new
chitters = repo.all
expect(chitters.length).to eq 3
- expect(chitters[0].id).to eq 1
- expect(chitters[0].peep).to eq 'flying solo'
- expect(chitters[0].peep_time).to eq '16:20:00'
+ expect(chitters[0].id).to eq 3
+ expect(chitters[0].peep).to eq 'dead'
+ expect(chitters[0].peep_time).to eq '16:22:00'
expect(chitters[1].id).to eq 2
expect(chitters[1].peep).to eq 'falling'
expect(chitters[1].peep_time).to eq '16:21:00'
+
+ expect(chitters[2].id).to eq 1
+ expect(chitters[2].peep).to eq 'flying solo'
+ expect(chitters[2].peep_time).to eq '16:20:00'
+
end
- it 'Gets all chitters in reverse order' do
+ it 'creates a chitter' do
repo = ChitterRepository.new
- ordered = repo.order
+ new_chitter = Chitter.new
+ new_chitter.peep = 'Gin'
+ new_chitter.peep_time = '14:50'
+ repo.create(new_chitter)
+
+ chitters = repo.all
- expect(ordered[0].peep_time).to eq '16:22:00'
- expect(ordered[1].peep_time).to eq '16:21:00'
- expect(ordered[2].peep_time).to eq '16:20:00'
- expect(ordered[2].peep).to eq 'flying solo'
+ expect(chitters.length).to eq(4)
+ expect(chitters.first.peep).to eq('Gin')
end
end
\ No newline at end of file
diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb
index e69de29bb2..db675b1402 100644
--- a/spec/integration/app_spec.rb
+++ b/spec/integration/app_spec.rb
@@ -0,0 +1,66 @@
+require "spec_helper"
+require "rack/test"
+require_relative '../../app'
+
+def reset_chitters_table
+ seed_sql = File.read('spec/seeds_chitters.sql')
+ connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_database_test' })
+ connection.exec(seed_sql)
+end
+
+RSpec.describe Application do
+ before(:each) do
+ reset_chitters_table
+ end
+
+ # This is so we can use rack-test helper methods.
+ include Rack::Test::Methods
+
+ # We need to declare the `app` value by instantiating the Application
+ # class so our tests work.
+ let(:app) { Application.new }
+
+ context "GET /chitters" do
+ xit 'returns a list of chitters in html' do
+ response = get('/chitters')
+
+ expected_response_0 = '
Time: 16:20:00 Chitter: dead
'
+ expected_response_1 = '
Time: 16:21:00 Chitter: falling
'
+ expected_response_2 = '
Time: 16:22:00 Chitter: flying solo
'
+
+ expect(response.status).to eq(200)
+ expect(response.body).to include(expected_response_0)
+ expect(response.body).to include(expected_response_1)
+ expect(response.body).to include(expected_response_2)
+
+ end
+ end
+
+ context "POST /chitters" do
+ it 'returns 200 OK' do
+ response = post(
+ '/chitters',
+ peep: 'Spaghetti',
+ peep_time: "12:00",
+ )
+
+ expect(response.status).to eq(200)
+ expect(response.body).to include('Spaghetti has been added')
+
+ get_chitters = get('/chitters')
+
+ expect(get_chitters.body).to include('Spaghetti')
+ end
+ end
+
+ context 'GET /chitters/new' do
+ it 'returns a form page' do
+ response = get("/chitters/new")
+
+ expect(response.status).to eq(200)
+ expect(response.body).to include('
\ No newline at end of file
From 757a0d0aa4b7c13fbffdfc69047536e162634a48 Mon Sep 17 00:00:00 2001
From: Julian Festing
Date: Sun, 7 May 2023 22:08:42 +0100
Subject: [PATCH 03/17] passed tests for adding a real timestamp into code for
time created
---
app.rb | 2 +-
lib/chitter.rb | 2 +-
lib/chitter_repository.rb | 8 ++++----
spec/chitter_repository_spec.rb | 9 +++++----
spec/chitters_table.sql | 2 +-
spec/integration/app_spec.rb | 17 ++++++-----------
spec/seeds_chitters.sql | 6 +++---
views/chitters.erb | 2 +-
views/new_chitter.erb | 2 --
9 files changed, 22 insertions(+), 28 deletions(-)
diff --git a/app.rb b/app.rb
index 5ad320e339..3caa35936f 100644
--- a/app.rb
+++ b/app.rb
@@ -31,7 +31,7 @@ class Application < Sinatra::Base
chitter = Chitter.new
chitter.peep = params[:peep]
- chitter.peep_time = params[:peep_time]
+ chitter.created_at = Time.now
repo.create(chitter)
@new_chitter = params[:peep]
diff --git a/lib/chitter.rb b/lib/chitter.rb
index 829143c432..3e93eda41b 100644
--- a/lib/chitter.rb
+++ b/lib/chitter.rb
@@ -1,5 +1,5 @@
class Chitter
# Replace the attributes by your own columns.
- attr_accessor :id, :peep, :peep_time
+ attr_accessor :id, :peep, :created_at
end
\ No newline at end of file
diff --git a/lib/chitter_repository.rb b/lib/chitter_repository.rb
index 7d25b0efcf..d346347525 100644
--- a/lib/chitter_repository.rb
+++ b/lib/chitter_repository.rb
@@ -4,7 +4,7 @@ class ChitterRepository
def all
- sql = 'SELECT id, peep, peep_time FROM chitters;'
+ sql = 'SELECT id, peep, created_at FROM chitters;'
result_set = DatabaseConnection.exec_params(sql, [])
chitters = []
@@ -14,7 +14,7 @@ def all
chitter.id = record['id'].to_i
chitter.peep = record['peep']
- chitter.peep_time = record['peep_time']
+ chitter.created_at = Time.parse(record['created_at'])
chitters << chitter
@@ -24,8 +24,8 @@ def all
end
def create(chitter)
- sql = 'INSERT INTO chitters (peep, peep_time) VALUES($1, $2);'
- params = [chitter.peep, chitter.peep_time]
+ sql = 'INSERT INTO chitters (peep, created_at) VALUES($1, $2);'
+ params = [chitter.peep, chitter.created_at]
record = DatabaseConnection.exec_params(sql, params)
return nil
diff --git a/spec/chitter_repository_spec.rb b/spec/chitter_repository_spec.rb
index 9293d269f8..85a2ea1bbe 100644
--- a/spec/chitter_repository_spec.rb
+++ b/spec/chitter_repository_spec.rb
@@ -20,15 +20,15 @@ def reset_chitters_table
expect(chitters[0].id).to eq 3
expect(chitters[0].peep).to eq 'dead'
- expect(chitters[0].peep_time).to eq '16:22:00'
+ expect(chitters[0].created_at).to be_a(Time)
expect(chitters[1].id).to eq 2
expect(chitters[1].peep).to eq 'falling'
- expect(chitters[1].peep_time).to eq '16:21:00'
+ expect(chitters[1].created_at).to be_a(Time)
expect(chitters[2].id).to eq 1
expect(chitters[2].peep).to eq 'flying solo'
- expect(chitters[2].peep_time).to eq '16:20:00'
+ expect(chitters[2].created_at).to be_a(Time)
end
@@ -37,12 +37,13 @@ def reset_chitters_table
new_chitter = Chitter.new
new_chitter.peep = 'Gin'
- new_chitter.peep_time = '14:50'
+ new_chitter.created_at = Time.now
repo.create(new_chitter)
chitters = repo.all
expect(chitters.length).to eq(4)
expect(chitters.first.peep).to eq('Gin')
+ expect(chitters.first.created_at).to be_a(Time)
end
end
\ No newline at end of file
diff --git a/spec/chitters_table.sql b/spec/chitters_table.sql
index 309dc0a455..8fd9bb3771 100644
--- a/spec/chitters_table.sql
+++ b/spec/chitters_table.sql
@@ -1,5 +1,5 @@
CREATE TABLE chitters (
id SERIAL PRIMARY KEY,
peep text,
- peep_time time
+ created_at timestamp
);
\ No newline at end of file
diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb
index db675b1402..3e93d869b0 100644
--- a/spec/integration/app_spec.rb
+++ b/spec/integration/app_spec.rb
@@ -21,18 +21,14 @@ def reset_chitters_table
let(:app) { Application.new }
context "GET /chitters" do
- xit 'returns a list of chitters in html' do
+ it 'returns a list of chitters in html' do
response = get('/chitters')
- expected_response_0 = '
Time: 16:20:00 Chitter: dead
'
- expected_response_1 = '
Time: 16:21:00 Chitter: falling
'
- expected_response_2 = '
Time: 16:22:00 Chitter: flying solo
'
-
expect(response.status).to eq(200)
- expect(response.body).to include(expected_response_0)
- expect(response.body).to include(expected_response_1)
- expect(response.body).to include(expected_response_2)
-
+ expect(response.body).to include('dead')
+ expect(response.body).to include('falling')
+ expect(response.body).to include('flying solo')
+ expect(response.body).to match(/Time: \d{2}-\d{2} \d{2}:\d{2}:\d{2}/)
end
end
@@ -41,7 +37,7 @@ def reset_chitters_table
response = post(
'/chitters',
peep: 'Spaghetti',
- peep_time: "12:00",
+ created_at: Time.now
)
expect(response.status).to eq(200)
@@ -60,7 +56,6 @@ def reset_chitters_table
expect(response.status).to eq(200)
expect(response.body).to include('
\ No newline at end of file
From d7791a59d48033066a029803688bdd5387f362f7 Mon Sep 17 00:00:00 2001
From: Julian Festing
Date: Mon, 8 May 2023 16:30:10 +0100
Subject: [PATCH 04/17] added in a signup page that adds new user to database
---
app.rb | 31 +++++++
docs/chitter_table_recipe.md | 2 +-
docs/chitter_user_table_recipe.md | 144 ++++++++++++++++++++++++++++++
lib/chitter.rb | 2 +-
lib/chitter_repository.rb | 10 ++-
lib/user.rb | 5 ++
lib/user_repository.rb | 36 ++++++++
spec/chitter_repository_spec.rb | 4 +
spec/integration/app_spec.rb | 45 +++++++++-
spec/seeds.sql | 17 ++++
spec/seeds_chitters.sql | 6 +-
spec/seeds_users.sql | 8 ++
spec/user_repository_spec.rb | 59 ++++++++++++
views/index.erb | 6 +-
views/new_user.erb | 13 +++
views/user_created.erb | 3 +
views/users.erb | 12 +++
17 files changed, 392 insertions(+), 11 deletions(-)
create mode 100644 docs/chitter_user_table_recipe.md
create mode 100644 lib/user.rb
create mode 100644 lib/user_repository.rb
create mode 100644 spec/seeds_users.sql
create mode 100644 spec/user_repository_spec.rb
create mode 100644 views/new_user.erb
create mode 100644 views/user_created.erb
create mode 100644 views/users.erb
diff --git a/app.rb b/app.rb
index 3caa35936f..160634875f 100644
--- a/app.rb
+++ b/app.rb
@@ -2,6 +2,7 @@
require "sinatra/reloader"
require_relative 'lib/database_connection'
require_relative 'lib/chitter_repository'
+require_relative 'lib/user_repository'
DatabaseConnection.connect
@@ -42,4 +43,34 @@ class Application < Sinatra::Base
get '/chitters/new' do
return erb(:new_chitter)
end
+
+ get '/users' do
+ repo = UserRepository.new
+ @users = repo.all
+
+ return erb(:users)
+ end
+
+ get '/sign-up' do
+ return erb(:new_user)
+ end
+
+ post '/sign-up' do
+ repo = UserRepository.new
+ user = User.new
+
+ user.email = params[:email]
+ user.password = params[:password]
+ user.name = params[:name]
+ user.username = params[:username]
+ repo.create(user)
+
+ @new_user = params[:username]
+
+ return erb(:user_created)
+ end
+
+ get '/chitters/new' do
+ return erb(:new_chitter)
+ end
end
\ No newline at end of file
diff --git a/docs/chitter_table_recipe.md b/docs/chitter_table_recipe.md
index 7b3e3d3695..da28659032 100644
--- a/docs/chitter_table_recipe.md
+++ b/docs/chitter_table_recipe.md
@@ -21,7 +21,7 @@ I want to see the time at which it was made
```
Nouns:
-chiter, peep, peep_time
+chitter, peep, created_at
```
## 2. Infer the Table Name and Columns
diff --git a/docs/chitter_user_table_recipe.md b/docs/chitter_user_table_recipe.md
new file mode 100644
index 0000000000..626bc6154c
--- /dev/null
+++ b/docs/chitter_user_table_recipe.md
@@ -0,0 +1,144 @@
+# Two Tables Design Recipe Template
+
+_Copy this recipe template to design and create two related database tables from a specification._
+
+## 1. Extract nouns from the user stories or specification
+
+```
+As a Maker
+So that I can post messages on Chitter as me
+I want to sign up for Chitter
+
+I want to log in to Chitter
+
+I want to log out of Chitter
+
+I want to receive an email if I am tagged in a Peep
+```
+
+```
+Nouns:
+
+chitter, peep, created_at, users, email, password, name, username
+```
+
+## 2. Infer the Table Name and Columns
+
+Put the different nouns in this table. Replace the example with your own nouns.
+
+| Record | Properties |
+| --------------------- | ------------------ |
+| chitter | peep, created_at
+| users | email, password, name, username
+
+1. Name of the first table (always plural): `chitters`
+
+ Column names: `peep`, `created_at`
+
+2. Name of the second table (always plural): `users`
+
+ Column names: `email` `password` `name` `username`
+
+## 3. Decide the column types.
+
+[Here's a full documentation of PostgreSQL data types](https://www.postgresql.org/docs/current/datatype.html).
+
+Most of the time, you'll need either `text`, `int`, `bigint`, `numeric`, or `boolean`. If you're in doubt, do some research or ask your peers.
+
+Remember to **always** have the primary key `id` as a first column. Its type will always be `SERIAL`.
+
+```
+# EXAMPLE:
+
+Table: chitters
+id: SERIAL
+peep: text
+created_at: time
+
+Table: users
+id: SERIAL
+email: text
+password: text
+name: text
+username: text
+```
+
+## 4. Decide on The Tables Relationship
+
+Most of the time, you'll be using a **one-to-many** relationship, and will need a **foreign key** on one of the two tables.
+
+To decide on which one, answer these two questions:
+
+1. Can one [user] have many [peeps]? (Yes)
+2. Can one [peep] have many [users]? (No)
+
+You'll then be able to say that:
+
+1. **[A] has many [B]**
+2. And on the other side, **[B] belongs to [A]**
+3. In that case, the foreign key is in the table [B]
+
+Replace the relevant bits in this example with your own:
+
+```
+# EXAMPLE
+
+1. Can one artist have many albums? YES
+2. Can one album have many artists? NO
+
+-> Therefore,
+-> An user HAS MANY peeps
+-> A peep BELONGS TO an user
+
+-> Therefore, the foreign key is on the peeps table.
+```
+
+*If you can answer YES to the two questions, you'll probably have to implement a Many-to-Many relationship, which is more complex and needs a third table (called a join table).*
+
+## 4. Write the SQL.
+
+```sql
+-- EXAMPLE
+-- file: peeps_table.sql
+
+-- Replace the table name, columm names and types.
+
+-- Create the table without the foreign key first.
+CREATE TABLE users (
+ id SERIAL PRIMARY KEY,
+ email text,
+ password text,
+ name text,
+ username text
+);
+
+
+-- Then the table with the foreign key first.
+CREATE TABLE chitters (
+ id SERIAL PRIMARY KEY,
+ peep text,
+ created_at timestamp,
+-- The foreign key name is always {other_table_singular}_id
+ user_id int,
+ constraint fk_user foreign key(peep_id)
+ references users(id)
+ on delete cascade
+);
+
+```
+
+## 5. Create the tables.
+
+```bash
+psql -h 127.0.0.1 database_name < albums_table.sql
+```
+
+
+
+---
+
+**How was this resource?**
+[😫](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😫) [😕](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😕) [😐](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😐) [🙂](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=🙂) [😀](https://airtable.com/shrUJ3t7KLMqVRFKR?prefill_Repository=makersacademy%2Fdatabases&prefill_File=resources%2Ftwo_table_design_recipe_template.md&prefill_Sentiment=😀)
+Click an emoji to tell us.
+
+
\ No newline at end of file
diff --git a/lib/chitter.rb b/lib/chitter.rb
index 3e93eda41b..dd616225f7 100644
--- a/lib/chitter.rb
+++ b/lib/chitter.rb
@@ -1,5 +1,5 @@
class Chitter
# Replace the attributes by your own columns.
- attr_accessor :id, :peep, :created_at
+ attr_accessor :id, :peep, :created_at, :user_id
end
\ No newline at end of file
diff --git a/lib/chitter_repository.rb b/lib/chitter_repository.rb
index d346347525..37f087d5db 100644
--- a/lib/chitter_repository.rb
+++ b/lib/chitter_repository.rb
@@ -1,10 +1,11 @@
require_relative '../lib/chitter'
+require 'date'
class ChitterRepository
def all
- sql = 'SELECT id, peep, created_at FROM chitters;'
+ sql = 'SELECT id, peep, created_at, user_id FROM chitters;'
result_set = DatabaseConnection.exec_params(sql, [])
chitters = []
@@ -14,7 +15,8 @@ def all
chitter.id = record['id'].to_i
chitter.peep = record['peep']
- chitter.created_at = Time.parse(record['created_at'])
+ chitter.created_at = DateTime.parse(record['created_at']).to_time
+ chitter.user_id = record['user_id'].to_i
chitters << chitter
@@ -24,8 +26,8 @@ def all
end
def create(chitter)
- sql = 'INSERT INTO chitters (peep, created_at) VALUES($1, $2);'
- params = [chitter.peep, chitter.created_at]
+ sql = 'INSERT INTO chitters (peep, created_at, user_id) VALUES($1, $2, $3);'
+ params = [chitter.peep, chitter.created_at, chitter.user_id]
record = DatabaseConnection.exec_params(sql, params)
return nil
diff --git a/lib/user.rb b/lib/user.rb
new file mode 100644
index 0000000000..274cf30f17
--- /dev/null
+++ b/lib/user.rb
@@ -0,0 +1,5 @@
+class User
+
+ # Replace the attributes by your own columns.
+ attr_accessor :id, :email, :password, :name, :username
+end
\ No newline at end of file
diff --git a/lib/user_repository.rb b/lib/user_repository.rb
new file mode 100644
index 0000000000..4a14771f7a
--- /dev/null
+++ b/lib/user_repository.rb
@@ -0,0 +1,36 @@
+require_relative '../lib/user'
+require 'date'
+
+class UserRepository
+
+ def all
+
+ sql = 'SELECT id, email, password, name, username FROM users;'
+ result_set = DatabaseConnection.exec_params(sql, [])
+
+ users = []
+
+ result_set.each do |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']
+
+
+ users << user
+ end
+
+ return users
+ 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]
+ record = DatabaseConnection.exec_params(sql, params)
+
+ return nil
+ end
+end
\ No newline at end of file
diff --git a/spec/chitter_repository_spec.rb b/spec/chitter_repository_spec.rb
index 85a2ea1bbe..a8a5fec9d5 100644
--- a/spec/chitter_repository_spec.rb
+++ b/spec/chitter_repository_spec.rb
@@ -21,14 +21,17 @@ def reset_chitters_table
expect(chitters[0].id).to eq 3
expect(chitters[0].peep).to eq 'dead'
expect(chitters[0].created_at).to be_a(Time)
+ expect(chitters[0].user_id).to eq 3
expect(chitters[1].id).to eq 2
expect(chitters[1].peep).to eq 'falling'
expect(chitters[1].created_at).to be_a(Time)
+ expect(chitters[1].user_id).to eq 2
expect(chitters[2].id).to eq 1
expect(chitters[2].peep).to eq 'flying solo'
expect(chitters[2].created_at).to be_a(Time)
+ expect(chitters[2].user_id).to eq 2
end
@@ -38,6 +41,7 @@ def reset_chitters_table
new_chitter = Chitter.new
new_chitter.peep = 'Gin'
new_chitter.created_at = Time.now
+ new_chitter.user_id = 1
repo.create(new_chitter)
chitters = repo.all
diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb
index 3e93d869b0..a04661b96c 100644
--- a/spec/integration/app_spec.rb
+++ b/spec/integration/app_spec.rb
@@ -50,7 +50,7 @@ def reset_chitters_table
end
context 'GET /chitters/new' do
- it 'returns a form page' do
+ it 'returns a new chitter form page' do
response = get("/chitters/new")
expect(response.status).to eq(200)
@@ -58,4 +58,47 @@ def reset_chitters_table
expect(response.body).to include('')
end
end
+
+ context "GET /users" do
+ it 'returns a list of users in html' do
+ response = get('/users')
+
+ expect(response.status).to eq(200)
+ expect(response.body).to include('sjmog')
+ expect(response.body).to include('smorg')
+ expect(response.body).to include('TZ')
+ end
+ end
+
+ context 'get /sign-up' do
+ it 'returns a chitter sign-up page' do
+ response = get('/sign-up')
+
+ expect(response.status).to eq(200)
+ expect(response.body).to include('
\ No newline at end of file
diff --git a/views/user_created.erb b/views/user_created.erb
new file mode 100644
index 0000000000..cb05f10f9f
--- /dev/null
+++ b/views/user_created.erb
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/views/users.erb b/views/users.erb
new file mode 100644
index 0000000000..d69f1f7eb5
--- /dev/null
+++ b/views/users.erb
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
From cadf6bb1f216c1639067de0284af7f2492472c10 Mon Sep 17 00:00:00 2001
From: Julian Festing
Date: Tue, 9 May 2023 15:54:46 +0100
Subject: [PATCH 05/17] added find by email method
---
lib/user_repository.rb | 14 ++++++++++++++
spec/user_repository_spec.rb | 11 +++++++++++
2 files changed, 25 insertions(+)
diff --git a/lib/user_repository.rb b/lib/user_repository.rb
index 4a14771f7a..575864adc6 100644
--- a/lib/user_repository.rb
+++ b/lib/user_repository.rb
@@ -33,4 +33,18 @@ def create(user)
return nil
end
+
+ def find_by_email(email)
+ sql = 'SELECT id, email, password, name, username FROM users WHERE email = $1;'
+ result_set = DatabaseConnection.exec_params(sql, [email])
+
+ user = User.new
+ user.id = result_set[0]['id'].to_i
+ user.email = result_set[0]['email']
+ user.password = result_set[0]['password']
+ user.name = result_set[0]['name']
+ user.username = result_set[0]['username']
+
+ return user
+ end
end
\ No newline at end of file
diff --git a/spec/user_repository_spec.rb b/spec/user_repository_spec.rb
index bdecac295c..928cb02610 100644
--- a/spec/user_repository_spec.rb
+++ b/spec/user_repository_spec.rb
@@ -56,4 +56,15 @@ def reset_users_table
expect(users.last.name).to eq('Bobby Boberson')
expect(users.last.username).to eq('BlobFlop')
end
+
+ it 'finds user by email' do
+ repo = UserRepository.new
+
+ user = repo.find_by_email('chonky@chonkersacademy.com')
+
+ expect(user.id).to eq 2
+ expect(user.name).to eq 'Samuel Morganson'
+ expect(user.username).to eq 'smorg'
+
+ end
end
\ No newline at end of file
From c96386ec491515e1a2171eaaf857b6124ff0ce6d Mon Sep 17 00:00:00 2001
From: Julian Festing
Date: Tue, 9 May 2023 15:56:04 +0100
Subject: [PATCH 06/17] added log-in page and incorporated sessions, also added
in logout button
---
app.rb | 40 ++++++++++++++++++++++++--
docs/login_system_plan.md | 14 ++++++++++
spec/integration/app_spec.rb | 54 +++++++++++++++++++++++++++++++++---
views/index.erb | 26 +++++++++++++----
views/log_in.erb | 9 ++++++
views/login_error.erb | 3 ++
views/login_success.erb | 5 ++++
views/new_user.erb | 8 +++---
8 files changed, 142 insertions(+), 17 deletions(-)
create mode 100644 docs/login_system_plan.md
create mode 100644 views/log_in.erb
create mode 100644 views/login_error.erb
create mode 100644 views/login_success.erb
diff --git a/app.rb b/app.rb
index 160634875f..104f9fdde6 100644
--- a/app.rb
+++ b/app.rb
@@ -7,19 +7,32 @@
DatabaseConnection.connect
class Application < Sinatra::Base
+ enable :sessions
+
configure :development do
register Sinatra::Reloader
also_reload 'lib/chitter_repository'
end
+ # This route simply returns a homepage containing links to the other pages
get '/' do
+ @current_user = session[:user_username]
+
return erb(:index)
end
+ post '/' do
+ session[:user_username] = nil
+ return erb(:index)
+ end
+
+ # An about page, yet to be populated
get '/about' do
+
return erb(:about)
end
+ # rturns a page containing all posted chitters
get '/chitters' do
repo = ChitterRepository.new
@chitters = repo.all
@@ -27,6 +40,7 @@ class Application < Sinatra::Base
return erb(:chitters)
end
+ # This route processes the data input when a new chitter from has been submitted
post '/chitters' do
repo = ChitterRepository.new
chitter = Chitter.new
@@ -40,10 +54,12 @@ class Application < Sinatra::Base
return erb(:chitter_created)
end
+ # This route simply returns the new chitter form page (only accessible when logged in)
get '/chitters/new' do
return erb(:new_chitter)
end
+ # gets a list of all users
get '/users' do
repo = UserRepository.new
@users = repo.all
@@ -51,10 +67,12 @@ class Application < Sinatra::Base
return erb(:users)
end
+ # This route simply returns the create user page which contains a sign-up form
get '/sign-up' do
return erb(:new_user)
end
+ # This route processes the info submitted through the create user form
post '/sign-up' do
repo = UserRepository.new
user = User.new
@@ -70,7 +88,23 @@ class Application < Sinatra::Base
return erb(:user_created)
end
- get '/chitters/new' do
- return erb(:new_chitter)
+ # This route simply returns the login page
+ get '/log-in' do
+ return erb(:log_in)
+ end
+
+ # processes the data from a login form and matches it to a current user
+ post '/log-in' do
+ email = params[:email]
+ password = params[:password]
+
+ repo = UserRepository.new
+
+ user = repo.find_by_email(email)
+
+ return erb(:login_error) unless user.password == password
+ session[:user_username] = user.username
+ return erb(:login_success)
+
end
-end
\ No newline at end of file
+end
diff --git a/docs/login_system_plan.md b/docs/login_system_plan.md
new file mode 100644
index 0000000000..225dfb91b7
--- /dev/null
+++ b/docs/login_system_plan.md
@@ -0,0 +1,14 @@
+initialize @logged_in = false
+
+if not logged in
+ button to log in available
+ create chitter page redirects to login page
+
+when logging in
+ verify if the login details match an existing user
+ if match then @logged in variable changes to true
+
+while logged in
+ can access the create a chitter page
+ states that you are logged in somewhere on the page
+
diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb
index a04661b96c..29eb37640f 100644
--- a/spec/integration/app_spec.rb
+++ b/spec/integration/app_spec.rb
@@ -76,10 +76,10 @@ def reset_chitters_table
expect(response.status).to eq(200)
expect(response.body).to include('
+ <% else %>
+
+ <% end %>
+
+ Go to the about page
+ View chitters
+ Create your own chitter
+ View users
+
+
+
\ No newline at end of file
diff --git a/views/log_in.erb b/views/log_in.erb
new file mode 100644
index 0000000000..ce4f75981a
--- /dev/null
+++ b/views/log_in.erb
@@ -0,0 +1,9 @@
+
Log In Here
+
\ No newline at end of file
diff --git a/views/login_error.erb b/views/login_error.erb
new file mode 100644
index 0000000000..0e9e7a0a6d
--- /dev/null
+++ b/views/login_error.erb
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/views/login_success.erb b/views/login_success.erb
new file mode 100644
index 0000000000..d9f55387e6
--- /dev/null
+++ b/views/login_success.erb
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/views/new_user.erb b/views/new_user.erb
index 62f063fc29..7b2b9337a2 100644
--- a/views/new_user.erb
+++ b/views/new_user.erb
@@ -1,13 +1,13 @@
New User
-
+
-
+
-
+
\ No newline at end of file
From 947f90b8295d357e0df4063bcc4a38ac5e86afa1 Mon Sep 17 00:00:00 2001
From: Julian Festing
Date: Tue, 9 May 2023 17:45:57 +0100
Subject: [PATCH 07/17] verifies that the username and email are unique
---
Gemfile | 1 +
Gemfile.lock | 3 +++
app.rb | 18 ++++++++++++++++--
docs/login_system_plan.md | 4 +---
spec/chitters_table.sql | 5 -----
spec/integration/app_spec.rb | 25 +++++++++++++++++++++++--
spec/seeds_chitters.sql | 16 ++++------------
spec/seeds_users.sql | 5 -----
spec/user_repository_spec.rb | 2 +-
views/new_chitter.erb | 4 +++-
views/new_user.erb | 5 +++++
11 files changed, 57 insertions(+), 31 deletions(-)
diff --git a/Gemfile b/Gemfile
index c205bc57f8..ed00e7600a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -18,3 +18,4 @@ gem "sinatra", "~> 3.0"
gem "sinatra-contrib", "~> 3.0"
gem "webrick", "~> 1.8"
gem "rack-test", "~> 2.1"
+gem "sinatra-flash"
diff --git a/Gemfile.lock b/Gemfile.lock
index d7ce111533..4cdea218e2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -67,6 +67,8 @@ GEM
rack-protection (= 3.0.6)
sinatra (= 3.0.6)
tilt (~> 2.0)
+ sinatra-flash (0.3.0)
+ sinatra (>= 1.0.0)
terminal-table (3.0.1)
unicode-display_width (>= 1.1.1, < 3)
tilt (2.1.0)
@@ -85,6 +87,7 @@ DEPENDENCIES
simplecov-console
sinatra (~> 3.0)
sinatra-contrib (~> 3.0)
+ sinatra-flash
webrick (~> 1.8)
RUBY VERSION
diff --git a/app.rb b/app.rb
index 104f9fdde6..82450ea22d 100644
--- a/app.rb
+++ b/app.rb
@@ -1,5 +1,6 @@
require 'sinatra'
require "sinatra/reloader"
+require 'sinatra/flash'
require_relative 'lib/database_connection'
require_relative 'lib/chitter_repository'
require_relative 'lib/user_repository'
@@ -8,6 +9,7 @@
class Application < Sinatra::Base
enable :sessions
+ register Sinatra::Flash
configure :development do
register Sinatra::Reloader
@@ -28,7 +30,7 @@ class Application < Sinatra::Base
# An about page, yet to be populated
get '/about' do
-
+
return erb(:about)
end
@@ -56,7 +58,11 @@ class Application < Sinatra::Base
# This route simply returns the new chitter form page (only accessible when logged in)
get '/chitters/new' do
- return erb(:new_chitter)
+ if session[:user_username]
+ return erb(:new_chitter)
+ else
+ return erb(:log_in)
+ end
end
# gets a list of all users
@@ -75,12 +81,20 @@ class Application < Sinatra::Base
# This route processes the info submitted through the create user form
post '/sign-up' do
repo = UserRepository.new
+ all_users = repo.all
user = User.new
user.email = params[:email]
user.password = params[:password]
user.name = params[:name]
user.username = params[:username]
+
+ all_users.each do |users|
+ if users.email == user.email || users.username == user.username
+ flash[:error] = "The email or username you entered already exists. Please use a different email or username."
+ redirect '/sign-up'
+ end
+ end
repo.create(user)
@new_user = params[:username]
diff --git a/docs/login_system_plan.md b/docs/login_system_plan.md
index 225dfb91b7..5935e3f403 100644
--- a/docs/login_system_plan.md
+++ b/docs/login_system_plan.md
@@ -1,12 +1,10 @@
-initialize @logged_in = false
-
if not logged in
button to log in available
create chitter page redirects to login page
when logging in
verify if the login details match an existing user
- if match then @logged in variable changes to true
+ if match then notice appears on homepage
while logged in
can access the create a chitter page
diff --git a/spec/chitters_table.sql b/spec/chitters_table.sql
index 8fd9bb3771..e69de29bb2 100644
--- a/spec/chitters_table.sql
+++ b/spec/chitters_table.sql
@@ -1,5 +0,0 @@
-CREATE TABLE chitters (
- id SERIAL PRIMARY KEY,
- peep text,
- created_at timestamp
-);
\ No newline at end of file
diff --git a/spec/integration/app_spec.rb b/spec/integration/app_spec.rb
index 29eb37640f..332436bc16 100644
--- a/spec/integration/app_spec.rb
+++ b/spec/integration/app_spec.rb
@@ -51,6 +51,11 @@ def reset_chitters_table
context 'GET /chitters/new' do
it 'returns a new chitter form page' do
+ post(
+ '/log-in',
+ email: 'chonky@chonkersacademy.com',
+ password: 'birdwird'
+ )
response = get("/chitters/new")
expect(response.status).to eq(200)
@@ -83,7 +88,7 @@ def reset_chitters_table
end
end
- context "POST /signup" do
+ context "POST /sign-up" do
it 'returns 200 OK' do
response = post(
'/sign-up',
@@ -100,10 +105,26 @@ def reset_chitters_table
expect(get_users.body).to include('Donno99')
end
+
+ it 'finds that the username or email already exist and asks to re-enter' do
+ response = post(
+ '/sign-up',
+ email: 'sleepy@sleepersacademy.com',
+ password: 'zzzzzz',
+ name: 'asdasd',
+ username: 'TZ'
+ )
+
+ expect(response.status).to eq(302)
+
+ get_users = get('/users')
+
+ expect(get_users.body).not_to include('asdasd')
+ end
end
context 'get /log-in' do
- it 'returns a chitter log-in page' do
+ it 'returns a chitter log-in page' do
response = get('/log-in')
expect(response.status).to eq(200)
diff --git a/spec/seeds_chitters.sql b/spec/seeds_chitters.sql
index 33fe2b1cf3..2d90c53eeb 100644
--- a/spec/seeds_chitters.sql
+++ b/spec/seeds_chitters.sql
@@ -1,16 +1,8 @@
--- EXAMPLE
--- (file: spec/seeds_chitters.sql)
+TRUNCATE TABLE chitters, users RESTART IDENTITY; -- replace with your own table name.
--- Write your SQL seed here.
-
--- First, you'd need to truncate the table - this is so our table is emptied between each test run,
--- so we can start with a fresh state.
--- (RESTART IDENTITY resets the primary key)
-
-TRUNCATE TABLE chitters RESTART IDENTITY; -- replace with your own table name.
-
--- Below this line there should only be `INSERT` statements.
--- Replace these statements with your own seed data.
+INSERT INTO users (email, password, name, username) VALUES ('samm@makersacademy.com', 'password123', 'Sam Morgan', 'sjmog');
+INSERT INTO users (email, password, name, username) VALUES ('chonky@chonkersacademy.com', 'birdwird', 'Samuel Morganson', 'smorg');
+INSERT INTO users (email, password, name, username) VALUES ('sleepy@sleepersacademy.com', 'zzzzzz', 'Tony Harrison', 'TZ');
INSERT INTO chitters (peep, created_at, user_id) VALUES ('flying solo', CURRENT_TIMESTAMP, 2);
INSERT INTO chitters (peep, created_at, user_id) VALUES ('falling', CURRENT_TIMESTAMP, 2);
diff --git a/spec/seeds_users.sql b/spec/seeds_users.sql
index 6629f87adb..b28b04f643 100644
--- a/spec/seeds_users.sql
+++ b/spec/seeds_users.sql
@@ -1,8 +1,3 @@
-TRUNCATE TABLE users RESTART IDENTITY CASCADE; -- replace with your own table name.
-
-INSERT INTO users (email, password, name, username) VALUES ('samm@makersacademy.com', 'password123', 'Sam Morgan', 'sjmog');
-INSERT INTO users (email, password, name, username) VALUES ('chonky@chonkersacademy.com', 'birdwird', 'Samuel Morganson', 'smorg');
-INSERT INTO users (email, password, name, username) VALUES ('sleepy@sleepersacademy.com', 'zzzzzz', 'Tony Harrison', 'TZ');
\ No newline at end of file
diff --git a/spec/user_repository_spec.rb b/spec/user_repository_spec.rb
index 928cb02610..4ad0aa190b 100644
--- a/spec/user_repository_spec.rb
+++ b/spec/user_repository_spec.rb
@@ -1,7 +1,7 @@
require 'user_repository'
def reset_users_table
- seed_sql = File.read('spec/seeds_users.sql')
+ seed_sql = File.read('spec/seeds_chitters.sql')
connection = PG.connect({ host: '127.0.0.1', dbname: 'chitter_database_test' })
connection.exec(seed_sql)
end
diff --git a/views/new_chitter.erb b/views/new_chitter.erb
index 05c841356f..01df81481d 100644
--- a/views/new_chitter.erb
+++ b/views/new_chitter.erb
@@ -3,4 +3,6 @@
-
\ No newline at end of file
+
+
+return
\ No newline at end of file
diff --git a/views/new_user.erb b/views/new_user.erb
index 7b2b9337a2..7de2cfc797 100644
--- a/views/new_user.erb
+++ b/views/new_user.erb
@@ -1,4 +1,9 @@