diff --git a/source/Gemfile b/source/Gemfile index 9627b8b..c915f50 100644 --- a/source/Gemfile +++ b/source/Gemfile @@ -27,7 +27,7 @@ gem 'sdoc', '~> 0.4.0', group: :doc gem 'spring', group: :development # Use ActiveModel has_secure_password -# gem 'bcrypt', '~> 3.1.7' +gem 'bcrypt', '~> 3.1.7' # Use unicorn as the app server # gem 'unicorn' @@ -39,3 +39,5 @@ gem 'spring', group: :development # gem 'debugger', group: [:development, :test] gem 'rspec-rails', group: [:development, :test] + gem 'pry' + gem 'faraday' diff --git a/source/Gemfile.lock b/source/Gemfile.lock index fcf8b98..1f37a5d 100644 --- a/source/Gemfile.lock +++ b/source/Gemfile.lock @@ -28,33 +28,43 @@ GEM thread_safe (~> 0.1) tzinfo (~> 1.1) arel (5.0.1.20140414130214) + bcrypt (3.1.10) builder (3.2.2) + coderay (1.1.0) coffee-rails (4.0.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) - coffee-script (2.3.0) + coffee-script (2.4.1) coffee-script-source execjs - coffee-script-source (1.8.0) + coffee-script-source (1.9.1.1) diff-lcs (1.2.5) erubis (2.7.0) - execjs (2.2.1) + execjs (2.5.2) + faraday (0.9.1) + multipart-post (>= 1.2, < 3) hike (1.2.3) - i18n (0.6.11) - jbuilder (2.2.2) + i18n (0.7.0) + jbuilder (2.2.16) activesupport (>= 3.0.0, < 5) multi_json (~> 1.2) jquery-rails (3.1.2) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) - json (1.8.1) - mail (2.6.1) + json (1.8.3) + mail (2.6.3) mime-types (>= 1.16, < 3) - mime-types (2.4.1) - minitest (5.4.2) - multi_json (1.10.1) - rack (1.5.2) - rack-test (0.6.2) + method_source (0.8.2) + mime-types (2.6.1) + minitest (5.7.0) + multi_json (1.11.0) + multipart-post (2.0.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rack (1.5.3) + rack-test (0.6.3) rack (>= 1.0) rails (4.1.6) actionmailer (= 4.1.6) @@ -71,53 +81,55 @@ GEM activesupport (= 4.1.6) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rake (10.3.2) - rdoc (4.1.2) + rake (10.4.2) + rdoc (4.2.0) json (~> 1.4) - rspec-core (3.1.6) - rspec-support (~> 3.1.0) - rspec-expectations (3.1.2) + rspec-core (3.2.3) + rspec-support (~> 3.2.0) + rspec-expectations (3.2.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.1.0) - rspec-mocks (3.1.3) - rspec-support (~> 3.1.0) - rspec-rails (3.1.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.1.0) - rspec-expectations (~> 3.1.0) - rspec-mocks (~> 3.1.0) - rspec-support (~> 3.1.0) - rspec-support (3.1.2) + rspec-support (~> 3.2.0) + rspec-mocks (3.2.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.2.0) + rspec-rails (3.2.3) + actionpack (>= 3.0, < 4.3) + activesupport (>= 3.0, < 4.3) + railties (>= 3.0, < 4.3) + rspec-core (~> 3.2.0) + rspec-expectations (~> 3.2.0) + rspec-mocks (~> 3.2.0) + rspec-support (~> 3.2.0) + rspec-support (3.2.2) sass (3.2.19) - sass-rails (4.0.3) + sass-rails (4.0.5) railties (>= 4.0.0, < 5.0) - sass (~> 3.2.0) - sprockets (~> 2.8, <= 2.11.0) + sass (~> 3.2.2) + sprockets (~> 2.8, < 3.0) sprockets-rails (~> 2.0) sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) - spring (1.1.3) - sprockets (2.11.0) + slop (3.6.0) + spring (1.3.6) + sprockets (2.12.3) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.2.0) + sprockets-rails (2.3.1) actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) - sqlite3 (1.3.9) + sqlite3 (1.3.10) thor (0.19.1) - thread_safe (0.3.4) + thread_safe (0.3.5) tilt (1.4.1) - turbolinks (2.4.0) + turbolinks (2.5.3) coffee-rails tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.5.3) + uglifier (2.7.1) execjs (>= 0.3.0) json (>= 1.8.0) @@ -125,9 +137,12 @@ PLATFORMS ruby DEPENDENCIES + bcrypt (~> 3.1.7) coffee-rails (~> 4.0.0) + faraday jbuilder (~> 2.0) jquery-rails + pry rails (= 4.1.6) rspec-rails sass-rails (~> 4.0.3) @@ -136,3 +151,6 @@ DEPENDENCIES sqlite3 turbolinks uglifier (>= 1.3.0) + +BUNDLED WITH + 1.10.3 diff --git a/source/app/assets/stylesheets/application.css b/source/app/assets/stylesheets/application.css index a443db3..9470714 100644 --- a/source/app/assets/stylesheets/application.css +++ b/source/app/assets/stylesheets/application.css @@ -13,3 +13,9 @@ *= require_tree . *= require_self */ + .field_with_errors { + @extend .has-error; + .form-control { + color: $state-danger-text; + } + } diff --git a/source/app/assets/stylesheets/scaffolds.css.scss b/source/app/assets/stylesheets/scaffolds.css.scss new file mode 100644 index 0000000..6ec6a8f --- /dev/null +++ b/source/app/assets/stylesheets/scaffolds.css.scss @@ -0,0 +1,69 @@ +body { + background-color: #fff; + color: #333; + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; +} + +p, ol, ul, td { + font-family: verdana, arial, helvetica, sans-serif; + font-size: 13px; + line-height: 18px; +} + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; +} + +a { + color: #000; + &:visited { + color: #666; + } + &:hover { + color: #fff; + background-color: #000; + } +} + +div { + &.field, &.actions { + margin-bottom: 10px; + } +} + +#notice { + color: green; +} + +.field_with_errors { + padding: 2px; + background-color: red; + display: table; +} + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px; + padding-bottom: 0; + margin-bottom: 20px; + background-color: #f0f0f0; + h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + margin-bottom: 0px; + background-color: #c00; + color: #fff; + } + ul li { + font-size: 12px; + list-style: square; + } +} diff --git a/source/app/assets/stylesheets/urls.css.scss b/source/app/assets/stylesheets/urls.css.scss index a4281ec..87f0d17 100644 --- a/source/app/assets/stylesheets/urls.css.scss +++ b/source/app/assets/stylesheets/urls.css.scss @@ -1,3 +1,9 @@ // Place all the styles related to the Urls controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ +table { + width: 100%; + td { + border: 1px solid black; + } +} diff --git a/source/app/controllers/application_controller.rb b/source/app/controllers/application_controller.rb index d83690e..d8b3d09 100644 --- a/source/app/controllers/application_controller.rb +++ b/source/app/controllers/application_controller.rb @@ -2,4 +2,5 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + include SessionsHelper end diff --git a/source/app/controllers/sessions_controller.rb b/source/app/controllers/sessions_controller.rb index 16d11b5..e00b760 100644 --- a/source/app/controllers/sessions_controller.rb +++ b/source/app/controllers/sessions_controller.rb @@ -1,2 +1,23 @@ class SessionsController < ApplicationController + + def new + end + + def create + user = User.find_by(email: params[:session][:email].downcase) + if user && user.authenticate(params[:session][:password]) + log_in user + flash[:success] = "You are now logged in" + redirect_to urls_path + else + flash.now[:danger] = "User could not be authenticated" + render 'new' + end + end + + def destroy + log_out + flash[:success] = "You are logged out" + redirect_to root_url + end end diff --git a/source/app/controllers/urls_controller.rb b/source/app/controllers/urls_controller.rb index ef26710..0b2c104 100644 --- a/source/app/controllers/urls_controller.rb +++ b/source/app/controllers/urls_controller.rb @@ -1,2 +1,84 @@ +require 'pry' + class UrlsController < ApplicationController + + before_action :get_url, only: [:show, :destroy] + before_action :logged_in_user, only: [:edit, :update, :create, :destroy] + before_action :correct_user, only: [:edit, :update, :destroy] + + def index + @urls = Url.all + end + + def create + @url = Url.new(url_params) + @url.user_id = current_user + if @url.save + flash[:success] = 'Url was successfully created' + redirect_to urls_path + else + flash[:failure] = 'Url could not be created' + render 'new' + end + end + + def new + @url = Url.new + end + + def edit + @url = get_url + end + + def update + @url = get_url + if @url.update(url_params) + flash[:success] = "Url successfully updated" + redirect_to urls_path + else + render 'edit' + end + end + + def destroy + @url.destroy + redirect_to_index + end + + def expand_link + @url = Url.find_by unique_key: params[:unique_key] + redirect_to_url + end + + def redirect_to_index + redirect_to urls_path + end + + def redirect_to_url + @url.click_count += 1 + @url.save + redirect_to @url.address + end + + def get_url + @url = Url.find(params[:id]) + end + + private + + def url_params + params.require(:url).permit(:address) + end + + def logged_in_user + unless logged_in? + flash[:danger] = "Please log in" + redirect_to login_url + end + end + + def correct_user + user = User.find(get_url.user_id) + redirect_to(root_url) unless current_user?(user) || admin? + end end diff --git a/source/app/controllers/users_controller.rb b/source/app/controllers/users_controller.rb index 3e74dea..ca6780b 100644 --- a/source/app/controllers/users_controller.rb +++ b/source/app/controllers/users_controller.rb @@ -1,2 +1,23 @@ class UsersController < ApplicationController + + def new + @user = User.new + end + + def create + @user = User.new(user_params) + if @user.save + log_in @user + flash[:success] = "User successfully created" + redirect_to urls_path + else + render 'new' + end + end + + private + + def user_params + params.require(:user).permit(:name, :email, :password, :password_confirmation) + end end diff --git a/source/app/helpers/sessions_helper.rb b/source/app/helpers/sessions_helper.rb index 309f8b2..e0f78ca 100644 --- a/source/app/helpers/sessions_helper.rb +++ b/source/app/helpers/sessions_helper.rb @@ -1,2 +1,26 @@ module SessionsHelper + def log_in(user) + session[:user_id] = user.id + end + + def current_user + @current_user ||= User.find_by(id: session[:user_id]) + end + + def logged_in? + !current_user.nil? + end + + def log_out + session.delete(:user_id) + @current_user = nil + end + + def current_user?(user) + user == current_user + end + + def admin? + current_user.admin + end end diff --git a/source/app/models/url.rb b/source/app/models/url.rb new file mode 100644 index 0000000..23929c5 --- /dev/null +++ b/source/app/models/url.rb @@ -0,0 +1,42 @@ +require 'uri' +require "net/http" +require 'faraday' + +class Url < ActiveRecord::Base + before_save :shorten_address + validate :validate_url + # validates :address, :format => URI::regexp(%w(http https)) + validates_uniqueness_of :unique_key + + private + + def validate_url + if self.address.match(/^https?:\/\//).nil? + errors.add(:address, "needs to be a valid url") + else + if self.address.match(URI::regexp(%w(http https))).nil? + errors.add(:address, "needs to be a valid url") + end + + begin + response = send_http_request(self.address) + if response.status.to_i >= 400 + errors.add(:address, "needs to be a valid url") + end + rescue Faraday::ConnectionFailed + errors.add(:address, "needs to be a valid url") + end + end + end + + def shorten_address + if self.unique_key.nil? + self.unique_key = 8.times.map { [*'0'..'9', *'a'..'z'].sample }.join + end + end + + def send_http_request url + Faraday.head url + end + +end diff --git a/source/app/models/user.rb b/source/app/models/user.rb new file mode 100644 index 0000000..d52449d --- /dev/null +++ b/source/app/models/user.rb @@ -0,0 +1,10 @@ +class User < ActiveRecord::Base + before_save { self.email = email.downcase } + VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i + validates :email, presence: true, + length: { maximum: 255 }, + format: { with: VALID_EMAIL_REGEX }, + uniqueness: { case_sensitive: false } + has_secure_password + validates :password, presence: true, length: { minimum: 6 } +end diff --git a/source/app/views/layouts/application.html.erb b/source/app/views/layouts/application.html.erb index f946432..153ce37 100644 --- a/source/app/views/layouts/application.html.erb +++ b/source/app/views/layouts/application.html.erb @@ -7,8 +7,24 @@ <%= csrf_meta_tags %>
+<%= link_to "Log out", logout_path, method: :delete %>
+ <% if admin? %> +YOU'RE AN ADMIN!
+ <% end %> + <% else %> +<%= link_to "Log in", login_path %>
+ <% end %> +