# frozen_string_literal: true require 'roda' require 'securerandom' require 'json' require 'sequel' require 'open-uri' # URL Shortener App class class App < Roda plugin :sessions, secret: ENV.delete('APP_SESSION_SECRET') plugin :render, escape: true plugin :flash plugin :json_parser plugin :request_headers DB = Sequel.sqlite("db/#{ENV.fetch('DB_NAME', nil)}") links = DB[:links] route do |r| r.root do @message = flash['message'] || 'Enter a URL' view :home end r.get String do |url_code| link = links.filter(code: url_code) r.redirect link.first[:url] unless link.first.nil? @message = "Link #{url_code} doesn't exist" response.status = 404 view :home end r.post 'create' do url = r.params['url'] if url.nil? || url.empty? flash['message'] = 'Please enter a valid URL' r.redirect '/' end begin OpenURI.open_uri(url) rescue URI::BadURIError flash['message'] = 'Invalid URL' r.redirect '/' rescue OpenURI::HTTPError flash['message'] = 'URL not found' r.redirect '/' rescue SocketError flash['message'] = 'URL does not resolve' r.redirect '/' end if links.filter(url:).first.nil? code = SecureRandom.urlsafe_base64 4 links.insert(url:, code:) @message = 'Link created' end code = links.filter(url:).first[:code] @message ||= 'Link exists' @new_link = "http://#{request.env['HTTP_HOST']}/#{code}" view :create end r.on 'links' do r.post do if r.headers['CONTENT_TYPE'] != 'application/json' response.status = 400 return { message: 'not a valid json request' }.to_json end url = r.params['url'] if url.nil? response.status = 400 return { message: 'missing url parameter' }.to_json end if url.empty? response.status = 400 return { message: 'invalid url parameter' }.to_json end begin OpenURI.open_uri(url) rescue URI::BadURIError response.status = 400 return { message: 'invalid url parameter' }.to_json rescue OpenURI::HTTPError response.status = 400 return { message: 'url not found' }.to_json rescue SocketError response.status = 400 return { message: 'url does not resolve' }.to_json end if links.filter(url:).first.nil? code = SecureRandom.urlsafe_base64 4 links.insert(url:, code:) end code = links.filter(url:).first[:code] @new_link = "http://#{request.env['HTTP_HOST']}/#{code}" return { url:, code:, link: @new_link }.to_json end end end end