-
+ <% @peeps.reverse.each do |peep| %>
+
- <%= peep.peep %>Posted on <%= peep.date %>. + <% end %> +
diff --git a/Gemfile b/Gemfile
index 99d8e519..d0d971e8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,6 +6,7 @@ ruby '3.0.2'
gem 'pg'
gem 'sinatra'
+gem 'sinatra-contrib'
group :test do
gem 'capybara'
diff --git a/Gemfile.lock b/Gemfile.lock
index 7d4eb449..33f398de 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -16,8 +16,11 @@ GEM
diff-lcs (1.4.4)
docile (1.4.0)
mini_mime (1.1.1)
+ multi_json (1.15.0)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
+ nokogiri (1.12.3-arm64-darwin)
+ racc (~> 1.4)
nokogiri (1.12.3-x86_64-darwin)
racc (~> 1.4)
parallel (1.20.1)
@@ -75,6 +78,12 @@ GEM
rack (~> 2.2)
rack-protection (= 2.1.0)
tilt (~> 2.0)
+ sinatra-contrib (2.1.0)
+ multi_json
+ mustermann (~> 1.0)
+ rack-protection (= 2.1.0)
+ sinatra (= 2.1.0)
+ tilt (~> 2.0)
terminal-table (3.0.1)
unicode-display_width (>= 1.1.1, < 3)
tilt (2.0.10)
@@ -83,7 +92,9 @@ GEM
nokogiri (~> 1.8)
PLATFORMS
+ arm64-darwin-20
x86_64-darwin-20
+ x86_64-darwin-21
DEPENDENCIES
capybara
@@ -93,6 +104,7 @@ DEPENDENCIES
simplecov
simplecov-console
sinatra
+ sinatra-contrib
RUBY VERSION
ruby 3.0.2p107
diff --git a/README.md b/README.md
index f9638b66..085ad6ac 100644
--- a/README.md
+++ b/README.md
@@ -1,66 +1,31 @@
-## Chitter Challenge
+## How to install Chitter
-* Challenge time: until the end of the day
-* Feel free to use google, your notes, books etc but please work on your own
-* Please raise a pull request when you start this challenge, and keep pushing updates as and when you make commits throughout the day
-* There is _no expectation_ to finish all or any of the user stories, please use this time to reflect on where you feel you are with the skill and what may support your learning.
-* If you get blocked, please reflect on what blocked you and any strategies you adopted that helped you make progress.
-
-We are going to write a small Twitter clone that will allow the users to post messages to a public stream.
+- Clone this repo into a local repository
## Set up
To setup the database:
-* Connect to psql
-* Create the database using the psql command `CREATE DATABASE chitter;`
-* Connect to the database using the psql command `\c chitter`;
-* Run the query we have saved in the file 01_create_chitter_table.sql
-* Populate your table with a row by running `INSERT INTO peeps (message) values ('This is a peep!');`
+- Connect to psql
+- Create the database using the psql command `CREATE DATABASE chitter;`
+- Connect to the database using the psql command `\c chitter`;
+- Run the query we have saved in the file db/migrations/01_create_chitter_table.sql
+- Populate your table with a row by running `INSERT INTO peeps (message) values ('This is a peep!');`
-To check you have everything set up ok, please take a look at the peeps table inside the chitter database. You should see one row in there.
+To check you have everything set up ok, please take a look at the peeps table inside the chitter database. You should see one row in there.
To setup the test database:
-* Connect to psql
-* Create the database using the psql
-command `CREATE DATABASE chitter_test;`;
-* Connect to the database using the psql command `\c chitter_test`
-* Run the query we have saved in the file 01_create_chitter_table.sql
-
-* `bundle install`
-* `rspec`
-
-You should see 1 passing test.
-
-## User stories
-```
-As a Maker
-So that I can see what people are doing
-I want to see all the messages (peeps)
-in a browser
-```
+- Connect to psql
+- Create the database using the psql
+ command `CREATE DATABASE chitter_test;`;
+- Connect to the database using the psql command `\c chitter_test`
+- Run the query we have saved in the file db/migrations/01_create_chitter_table.sql
-```
-As a Maker
-So that I can let people know what I am doing
-I want to post a message (peep) to chitter
-```
+- `bundle install'
-```
-As a Maker
-So that I can see when people are doing things
-I want to see the date the message was posted
-```
-(Hint the database table will need to change to store the date too)
+## Run Chitter
-```
-As a Maker
-So that I can easily see the latest peeps
-I want to see a list of peeps in reverse chronological order
-```
-```
-As a Maker
-So that I can find relevant peeps
-I want to filter on a specific keyword
-```
+- 'ruby app.rb'
+- Go to http://localhost:4567/ in your web browser
+- To stop viewing Chitter, press CTRL+C twice in the Terminal.
diff --git a/app.rb b/app.rb
index 2450fb92..fd6916a5 100644
--- a/app.rb
+++ b/app.rb
@@ -1,9 +1,33 @@
+require 'sinatra'
require 'sinatra/base'
+require 'sinatra/reloader'
+require_relative 'database_connection_setup'
+require './lib/peeps'
class Chitter < Sinatra::Base
+
+ configure :development do
+ register Sinatra::Reloader
+ end
+
get '/test' do
'Test page'
end
+ get '/' do
+ @peeps = Peeps.all
+ erb :index
+ end
+
+ post '/add' do
+ Peeps.create(peep: params[:peep])
+ redirect '/'
+ end
+
+ post '/search' do
+ @peeps = Peeps.search_by_keyword(keyword: params[:search])
+ erb :search
+ end
+
run! if app_file == $0
end
diff --git a/database_connection_setup.rb b/database_connection_setup.rb
new file mode 100644
index 00000000..888b2a96
--- /dev/null
+++ b/database_connection_setup.rb
@@ -0,0 +1,7 @@
+require './lib/database_connection'
+
+if ENV['ENVIRONMENT'] == 'test'
+ DatabaseConnection.setup('chitter_test')
+else
+ DatabaseConnection.setup('chitter')
+end
diff --git a/db/migrations/01_create_chitter_table.sql b/db/migrations/01_create_chitter_table.sql
index 6e077248..133709a1 100644
--- a/db/migrations/01_create_chitter_table.sql
+++ b/db/migrations/01_create_chitter_table.sql
@@ -1 +1 @@
-CREATE TABLE peeps(id SERIAL PRIMARY KEY, message VARCHAR(60));
+CREATE TABLE peeps(id SERIAL PRIMARY KEY, message VARCHAR(60), date DATE NOT NULL DEFAULT CURRENT_DATE);
diff --git a/lib/database_connection.rb b/lib/database_connection.rb
new file mode 100644
index 00000000..9089b758
--- /dev/null
+++ b/lib/database_connection.rb
@@ -0,0 +1,15 @@
+require 'pg'
+
+class DatabaseConnection
+ def self.setup(db_name)
+ @connection = PG.connect(dbname: db_name)
+ end
+
+ class << self
+ attr_reader :connection
+ end
+
+ def self.query(sql)
+ @connection.exec(sql)
+ end
+end
diff --git a/lib/peeps.rb b/lib/peeps.rb
new file mode 100644
index 00000000..f72b1767
--- /dev/null
+++ b/lib/peeps.rb
@@ -0,0 +1,43 @@
+require_relative 'database_connection'
+
+class Peeps
+
+ attr_reader :id, :peep, :date
+
+ def initialize(id:, peep:, date:)
+ @id = id
+ @peep = peep
+ @date = date
+ end
+
+ def self.create(peep:)
+ result = DatabaseConnection.query(
+ "INSERT INTO peeps (message) VALUES ('#{peep}') RETURNING id, message, date;"
+ )
+ Peeps.new(id: result[0]['id'], peep: result[0]['message'], date: result[0]['date'])
+ end
+
+ def self.all
+ result = DatabaseConnection.query("SELECT * FROM peeps")
+ result.map do |peep|
+ Peeps.new(
+ id: peep['id'],
+ peep: peep['message'],
+ date: peep['date']
+ )
+ end
+ end
+
+ def self.search_by_keyword(keyword:)
+ result = DatabaseConnection.query(
+ "SELECT * FROM peeps WHERE message LIKE '%#{keyword}%';"
+ )
+ result.map do |peep|
+ Peeps.new(
+ id: peep['id'],
+ peep: peep['message'],
+ date: peep['date']
+ )
+ end
+ end
+end
diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css
new file mode 100644
index 00000000..45939dea
--- /dev/null
+++ b/public/stylesheets/style.css
@@ -0,0 +1,102 @@
+* {
+ font-family: roboto;
+ color: #232323;
+ max-width: 960px;
+ margin: auto;
+}
+
+h1 {
+ font-size: 3em;
+ font-style: normal;
+ color: blue;
+}
+
+ul.no-bullets {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+.top-header {
+ display: flex;
+ width: 100%;
+ position: fixed;
+ top: 0;
+ z-index: 1;
+ border-bottom: 1px solid lightgrey;
+ background-color: white;
+}
+
+.header-items {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-right: 1em;
+}
+
+.main-content {
+ position: relative;
+ margin-top: 75px;
+}
+
+.new-peep {
+ position: fixed;
+ margin-top: 5px;
+ width: 100%;
+ background-color: white;
+ z-index: 1;
+}
+
+.peep-container {
+ margin-top: 50px;
+ border: 1px solid lightgray;
+}
+
+.peep {
+ font-size: large;
+ border-bottom: solid;
+ border-width: 2px;
+ border-color: lightgray;
+ padding: 50px;
+}
+
+.peep-text {
+ text-align: left;
+}
+
+.date-text {
+ margin-left: 20px;
+ font-size: small;
+ font-weight: lighter;
+}
+
+.input {
+ padding: 10px;
+ border: 1px solid lightgray;
+ border-radius: 5px;
+ margin-bottom: 10px;
+}
+
+.chitter-button {
+ background-color: blue;
+ color: white;
+ border: none;
+ border-radius: 5px;
+ padding: 10px;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ margin: 4px 2px;
+ cursor: pointer;
+ transition-duration: 0.4s;
+}
+
+.chitter-button:hover {
+ background-color: goldenrod;
+}
+
+.chitter-button:active {
+ box-shadow: 0 0 0 0 goldenrod;
+ transform: scale(96%);
+}
diff --git a/spec/database_connection_spec.rb b/spec/database_connection_spec.rb
new file mode 100644
index 00000000..901d5201
--- /dev/null
+++ b/spec/database_connection_spec.rb
@@ -0,0 +1,21 @@
+require 'database_connection'
+
+describe DatabaseConnection do
+ describe '#setup' do
+ it 'sets up a connection to the database with PG' do
+ expect(PG).to receive(:connect).with(dbname: 'chitter_test')
+
+ DatabaseConnection.setup('chitter_test')
+ end
+ end
+
+ describe '#query' do
+ it 'executes a query via PG' do
+ connection = DatabaseConnection.setup('chitter_test')
+
+ expect(connection).to receive(:exec).with('SELECT * FROM peeps;')
+
+ DatabaseConnection.query('SELECT * FROM peeps;')
+ end
+ end
+end
diff --git a/spec/database_helpers.rb b/spec/database_helpers.rb
new file mode 100644
index 00000000..e69de29b
diff --git a/spec/features/post_a_peep_spec.rb b/spec/features/post_a_peep_spec.rb
new file mode 100644
index 00000000..29ac8c3b
--- /dev/null
+++ b/spec/features/post_a_peep_spec.rb
@@ -0,0 +1,8 @@
+feature 'post a peep' do
+ scenario 'the user can post a peep' do
+ visit('/')
+ fill_in('peep', with: "I posted a peep!")
+ click_button('Peep!')
+ expect(page).to have_content "I posted a peep!"
+ end
+end
diff --git a/spec/features/search_peeps_spec.rb b/spec/features/search_peeps_spec.rb
new file mode 100644
index 00000000..3be68739
--- /dev/null
+++ b/spec/features/search_peeps_spec.rb
@@ -0,0 +1,14 @@
+feature 'filter peeps by keyword' do
+ scenario 'the user can filter peeps by keyword' do
+ Peeps.create(peep: 'This is a peep!')
+ Peeps.create(peep: 'This is another peep!')
+ Peeps.create(peep: 'This is a third peep!')
+
+ visit('/')
+ fill_in('search', with: 'third')
+ click_button('Search')
+ expect(page).to have_content 'This is a third peep!'
+ expect(page).to have_no_content 'This is a peep!'
+ expect(page).to have_no_content 'This is another peep!'
+ end
+end
diff --git a/spec/features/viewing_peeps_spec.rb b/spec/features/viewing_peeps_spec.rb
new file mode 100644
index 00000000..38dff071
--- /dev/null
+++ b/spec/features/viewing_peeps_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../setup_test_database'
+
+feature 'viewing peeps' do
+ scenario 'the user can view peeps on the homepage with the date posted' do
+ add_row_to_test_database
+ visit('/')
+ expect(page).to have_content "This is a peep! Posted on 2022-04-01."
+ end
+end
diff --git a/spec/peeps_spec.rb b/spec/peeps_spec.rb
new file mode 100644
index 00000000..cae1424e
--- /dev/null
+++ b/spec/peeps_spec.rb
@@ -0,0 +1,38 @@
+require 'peeps'
+
+describe Peeps do
+ describe '#all' do
+ it 'returns all peeps' do
+ peep = Peeps.create(peep: 'This is a peep!')
+ Peeps.create(peep: 'This is another peep!')
+ Peeps.create(peep: 'This is a third peep!')
+ peeps = Peeps.all
+
+ expect(peeps.length).to eq(3)
+ expect(peeps.first).to be_a Peeps
+ expect(peeps.first.id).to eq peep.id
+ expect(peeps.first.peep).to eq "This is a peep!"
+ expect(peeps.first.date).to eq Time.now.strftime("%Y-%m-%d")
+ end
+
+ it 'creates a peep' do
+ peep = Peeps.create(peep: 'This is a peep!')
+ expect(peep).to be_a Peeps
+ expect(peep.peep).to eq 'This is a peep!'
+ expect(peep.date).to eq Time.now.strftime("%Y-%m-%d")
+ end
+ end
+
+ it 'searches peeps on a specific keyword' do
+ Peeps.create(peep: 'This is a peep!')
+ Peeps.create(peep: 'This is another peep!')
+ peep = Peeps.create(peep: 'This is a third peep!')
+ peeps = Peeps.search_by_keyword(keyword: 'third')
+
+ expect(peeps.length).to eq(1)
+ expect(peeps.first).to be_a Peeps
+ expect(peeps.first.id).to eq peep.id
+ expect(peeps.first.peep).to eq "This is a third peep!"
+ expect(peeps.first.date).to eq Time.now.strftime("%Y-%m-%d")
+ end
+end
diff --git a/spec/setup_test_database.rb b/spec/setup_test_database.rb
index af832f7d..19ff7fb3 100644
--- a/spec/setup_test_database.rb
+++ b/spec/setup_test_database.rb
@@ -1,6 +1,7 @@
require 'pg'
def setup_test_database
+ p 'Setting up test database...'
connection = PG.connect(dbname: 'chitter_test')
connection.exec("TRUNCATE peeps;")
end
diff --git a/views/index.erb b/views/index.erb
new file mode 100644
index 00000000..6420e765
--- /dev/null
+++ b/views/index.erb
@@ -0,0 +1,29 @@
+Chitter
+
+ <% @peeps.reverse.each do |peep| %>
+
+