-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pablo Joyce chitter challenge #2174
base: main
Are you sure you want to change the base?
Changes from 32 commits
5ccef5b
9956e10
04ddf5e
e4c30e0
a9307db
fb90cd7
f9417d0
6a3a0e4
60390cf
5821da3
5f73b84
3ff7f2b
964a449
8eda5ca
cca3382
4d53c3e
1144a1a
2897786
5f5a03e
0a2a574
fa32980
45dd4d3
44653c7
11fb2be
7e3e7f6
8f77719
378b67a
87684c9
9ea5c6f
28e1758
0047743
c8da0b6
dd80942
98178ce
195030b
ad1e613
dbf2c85
6e16997
316a1f1
cc3669b
54e41ec
0fd6fe2
a45ff71
77e969b
251ad3d
0cb10f7
b64a3e9
4d5e967
2f4c3ce
94a3411
b9954d3
53625b8
da5e800
8d7e703
e2337b2
c69b125
ec5acbe
4b4646f
4a4c1be
a58df1d
5f57bdf
3586557
94a0c34
853d26f
73f3ef2
cbe4f45
53e9a3f
3f71018
b0e66c1
975a2d7
6fde111
d054c50
8bad1fb
66ce8d4
b93f21f
948055e
755b40a
55f9ca9
212c657
eb65387
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
require_relative 'lib/database_connection' | ||
require 'sinatra/base' | ||
require 'sinatra/reloader' | ||
require_relative 'lib/user_repository' | ||
require_relative 'lib/peep_repository' | ||
require 'bcrypt' | ||
|
||
DatabaseConnection.connect | ||
|
||
class Application < Sinatra::Base | ||
|
||
enable :sessions # allows users sessions | ||
|
||
# This allows the app code to refresh | ||
# without having to restart the server. | ||
configure :development do | ||
register Sinatra::Reloader | ||
also_reload 'lib/user_repository' | ||
also_reload 'lib/peep_repository' | ||
set :message, "Log in to create new peeps." | ||
set :logged, false | ||
set :validation_error, "" | ||
end | ||
|
||
get '/' do | ||
repo = PeepRepository.new | ||
peeps = repo.all_with_names | ||
@peep_info = peeps.map{ |peep| [peep.username, peep.time, peep.body, peep.tags, peep.name]}.reverse | ||
return erb(:index) | ||
end | ||
|
||
get '/peeps/new' do | ||
@user_id = session[:user_id] # placeholder code for sending logged in user id!!! | ||
return erb(:add_peep) | ||
end | ||
|
||
post '/peeps' do | ||
@body, @tags, @user_id = params[:body], params[:tags],params[:user_id] | ||
script_check([@body, @tags, @user_id], '/peeps/new') | ||
validate_string(@body, "peep") | ||
repo = PeepRepository.new | ||
new_peep = Peep.new | ||
new_peep.body = @body | ||
new_peep.time = Time.now#.strftime("%Y-%m-%d %T") | ||
new_peep.tags = @tags | ||
new_peep.user_id = @user_id | ||
repo.create(new_peep) | ||
return redirect('/') | ||
end | ||
|
||
get '/register/new' do | ||
return erb(:register) | ||
end | ||
|
||
post '/register' do | ||
@name, @username, @email, @password = params[:name], params[:username], params[:email], params[:password] | ||
script_check([@name, @username, @email, @password], '/register/new') | ||
validate_string(@name, "name") | ||
validate_string(@username, "username") | ||
validate_email(@email) | ||
username_email_unique(@username, @email) | ||
validate_password(@password) | ||
user_repo = UserRepository.new | ||
new_user = User.new | ||
new_user.name = @name | ||
new_user.username = @username | ||
new_user.email = @email | ||
new_user.password = @password | ||
user_repo.create(new_user) | ||
user = user_repo.find_by_email(@email) | ||
login_user(user) | ||
return redirect('/') | ||
end | ||
|
||
get '/login/form' do | ||
return erb(:login) | ||
end | ||
|
||
post '/login' do | ||
@email = params[:email] | ||
@password = params[:password] | ||
script_check([@email, @password], '/login/form') | ||
email_exists(@email) | ||
user = UserRepository.new.find_by_email(@email) | ||
email_password_match(user, @password) | ||
return redirect('/') | ||
end | ||
|
||
get '/logout' do | ||
session.clear | ||
settings.logged = false | ||
settings.message = "Log in to create new peeps." | ||
return redirect('/') | ||
end | ||
|
||
helpers do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Could move the helpers functions into another file for readability! |
||
def validate_string(name, field) | ||
unless name.match?(/[a-zA-Z]/) | ||
settings.validation_error = "Invalid #{field}: must contain one or more letters.\n" | ||
return redirect('register/new') | ||
end | ||
end | ||
|
||
def validate_email(email) | ||
unless email =~ URI::MailTo::EMAIL_REGEXP | ||
settings.validation_error = "Invalid email: please enter a valid email to register.\n" | ||
return redirect('register/new') | ||
end | ||
end | ||
|
||
def validate_password(password) | ||
unless password.match(/^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,}$/) | ||
settings.validation_error = "Invalid password: minimum eight characters and contain at least one lowercase letter, uppercase letter and digit.\n" | ||
return redirect('register/new') | ||
end | ||
end | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good concise validation methods |
||
def username_email_unique(username, email) | ||
if UserRepository.new.all_usernames.include?(username) | ||
settings.validation_error = "That username is already taken.\n" | ||
return redirect('register/new') | ||
end | ||
if UserRepository.new.all_emails.include?(email) | ||
settings.validation_error = "That email is already registered to a user.\n" | ||
return redirect('register/new') | ||
end | ||
end | ||
|
||
def email_exists(email) | ||
emails = UserRepository.new.all_emails | ||
unless emails.include?(email) | ||
settings.validation_error = "Email and password do not match any registered user.\n" | ||
return redirect('login/form') | ||
end | ||
end | ||
|
||
def email_password_match(user, entered_password) | ||
stored_password = BCrypt::Password.new(user.password) | ||
unless stored_password == entered_password # i.e. UNLESS <stored-password-hash> == <entered-password> | ||
session[:user_id] = nil | ||
settings.logged = false | ||
settings.validation_error = "Email and password do not match any registered user.\n" | ||
return redirect('/login/form') | ||
end | ||
login_user(user) | ||
# session[:username] = user.username | ||
# session[:user_id] = user.id | ||
settings.logged = true | ||
end | ||
|
||
def login_user(user) | ||
session[:username] = user.username | ||
session[:user_id] = user.id | ||
settings.logged = true | ||
end | ||
|
||
def script_check(inputs_array, redirect_path) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: use ERB::Util.html.escape to better escape user input |
||
if inputs_array.join.match?(/[<>\/]/) | ||
session[:user_id] = nil | ||
settings.logged = false | ||
settings.validation_error = "'<', '>' and '/' are not permitted characters.\n" | ||
return redirect(redirect_path) | ||
end | ||
end | ||
|
||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
require './app' | ||
run Application |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
require 'pg' | ||
|
||
class DatabaseConnection | ||
# This method connects to PostgreSQL using the PG gem. We connect to 127.0.0.1 | ||
|
||
################## RENDER connect method | ||
# 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_test' | ||
# else | ||
# database_name = 'chitter_render_db' | ||
# end | ||
# @connection = PG.connect({ host: '127.0.0.1', dbname: database_name }) | ||
# end | ||
|
||
|
||
|
||
|
||
################### local connect method - NOT for RENDER | ||
def self.connect | ||
if ENV['ENV'] == 'test' | ||
database_name = 'chitter_test' | ||
else | ||
database_name = 'chitter' | ||
end | ||
@connection = PG.connect({ host: '127.0.0.1', dbname: database_name }) | ||
end | ||
|
||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class Peep | ||
attr_accessor :id, :body, :time, :tags, :user_id, :username, :name | ||
|
||
# def initialize | ||
# @tags = [] | ||
# end | ||
end |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Use an ORM to access the database instead! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
require_relative './peep' | ||
require_relative './user' | ||
require 'time' | ||
|
||
class PeepRepository | ||
def all # return all peeps | ||
sql = 'SELECT * FROM peeps;' | ||
results = DatabaseConnection.exec_params(sql, []) | ||
peeps = [] | ||
results.each{ |record| peeps << peep_builder(record) } | ||
return peeps | ||
end | ||
|
||
def all_with_names | ||
sql = 'SELECT users.name, users.username, peeps.body, peeps.time, peeps.tags, peeps.user_id | ||
FROM users | ||
JOIN peeps | ||
ON peeps.user_id = users.id;' | ||
results = DatabaseConnection.exec_params(sql, []) | ||
peeps_with_names = [] | ||
p results | ||
results.each do |record| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use a peep builder! |
||
peep = Peep.new | ||
peep.id = record['id'].to_i | ||
peep.body = record['body'] | ||
peep.time = (record['time']) | ||
peep.tags = record['tags'] | ||
peep.user_id = record['user_id'].to_i | ||
peep.name = record['name'] | ||
peep.username = record['username'] | ||
peeps_with_names << peep | ||
end | ||
return peeps_with_names | ||
end | ||
|
||
def create(peep) | ||
sql = 'INSERT INTO peeps (body, time, tags, user_id) VALUES ($1, $2, $3, $4);' | ||
params = [peep.body, peep.time, peep.tags, peep.user_id] | ||
DatabaseConnection.exec_params(sql, params) | ||
end | ||
|
||
private | ||
|
||
def peep_builder(record) # used to build peeps in iteration by #all | ||
peep = Peep.new | ||
peep.id = record['id'].to_i | ||
peep.body = record['body'] | ||
peep.time = record['time'] | ||
peep.tags = record['tags'] | ||
peep.user_id = record['user_id'].to_i | ||
return peep | ||
end | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could include how to run the program