chore: remove rails app

This commit is contained in:
Juan Rodriguez
2024-05-12 15:07:56 +02:00
parent 8eb27f2c8a
commit 720b70c6a0
101 changed files with 0 additions and 10276 deletions
-68
View File
@@ -1,68 +0,0 @@
# frozen_string_literal: true
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.6.3'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.6'
# Use postgresql as the database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
# Use Puma as the app server
gem 'puma', '~> 4.3.8'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker'
# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'mini_racer', platforms: :ruby
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: %i[mri mingw x64_mingw]
end
group :development do
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'web-console', '>= 3.3.0'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
# A Ruby static code analyzer and formatter, based on the community Ruby style guide.
gem 'rubocop', '~> 1.17'
# A RuboCop extension focused on enforcing Rails best practices and coding conventions.
gem 'rubocop-rails'
end
group :test do
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '>= 2.15'
gem 'selenium-webdriver'
# Easy installation and use of chromedriver to run system tests with Chrome
gem 'webdrivers'
# SimpleCov is a code coverage analysis tool for Ruby
gem 'simplecov'
# Simple console output formatter for SimpleCov
gem 'simplecov-console'
end
-269
View File
@@ -1,269 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (5.2.6)
actionpack (= 5.2.6)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.6)
actionview (= 5.2.6)
activesupport (= 5.2.6)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.2.6)
activesupport (= 5.2.6)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.6)
activesupport (= 5.2.6)
globalid (>= 0.3.6)
activemodel (5.2.6)
activesupport (= 5.2.6)
activerecord (5.2.6)
activemodel (= 5.2.6)
activesupport (= 5.2.6)
arel (>= 9.0)
activestorage (5.2.6)
actionpack (= 5.2.6)
activerecord (= 5.2.6)
marcel (~> 1.0.0)
activesupport (5.2.6)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
ansi (1.5.0)
arel (9.0.0)
ast (2.4.2)
bcrypt (3.1.16)
bcrypt (3.1.16-java)
bindex (0.8.1)
bootsnap (1.7.5)
msgpack (~> 1.0)
builder (3.2.4)
byebug (11.1.3)
capybara (3.35.3)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
childprocess (3.0.0)
concurrent-ruby (1.1.9)
crass (1.0.6)
docile (1.4.0)
erubi (1.10.0)
execjs (2.8.1)
ffi (1.15.1)
ffi (1.15.1-java)
ffi (1.15.1-x64-mingw32)
ffi (1.15.1-x86-mingw32)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
jbuilder (2.11.2)
activesupport (>= 5.0.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
loofah (2.10.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (1.0.1)
method_source (1.0.0)
mini_mime (1.1.0)
mini_portile2 (2.5.3)
minitest (5.14.4)
msgpack (1.4.2)
msgpack (1.4.2-java)
nio4r (2.5.7)
nio4r (2.5.7-java)
nokogiri (1.11.7)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
nokogiri (1.11.7-java)
racc (~> 1.4)
nokogiri (1.11.7-x64-mingw32)
racc (~> 1.4)
nokogiri (1.11.7-x86-mingw32)
racc (~> 1.4)
parallel (1.20.1)
parser (3.0.1.1)
ast (~> 2.4.1)
pg (1.2.3)
pg (1.2.3-x64-mingw32)
pg (1.2.3-x86-mingw32)
public_suffix (4.0.6)
puma (4.3.8)
nio4r (~> 2.0)
puma (4.3.8-java)
nio4r (~> 2.0)
racc (1.5.2)
racc (1.5.2-java)
rack (2.2.3)
rack-proxy (0.7.0)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.6)
actioncable (= 5.2.6)
actionmailer (= 5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
activemodel (= 5.2.6)
activerecord (= 5.2.6)
activestorage (= 5.2.6)
activesupport (= 5.2.6)
bundler (>= 1.3.0)
railties (= 5.2.6)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
railties (5.2.6)
actionpack (= 5.2.6)
activesupport (= 5.2.6)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (13.0.3)
rb-fsevent (0.11.0)
rb-inotify (0.10.1)
ffi (~> 1.0)
regexp_parser (2.1.1)
rexml (3.2.5)
rubocop (1.17.0)
parallel (~> 1.10)
parser (>= 3.0.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml
rubocop-ast (>= 1.7.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.7.0)
parser (>= 3.0.1.1)
rubocop-rails (2.10.1)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.7.0, < 2.0)
ruby-progressbar (1.11.0)
ruby_dep (1.5.0)
rubyzip (2.3.0)
selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
semantic_range (3.0.0)
simplecov (0.21.2)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-console (0.9.1)
ansi
simplecov
terminal-table
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.3)
spring (2.1.1)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
terminal-table (3.0.1)
unicode-display_width (>= 1.1.1, < 3)
thor (1.1.0)
thread_safe (0.3.6)
thread_safe (0.3.6-java)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (1.2.9)
thread_safe (~> 0.1)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (2.0.0)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
bindex (>= 0.4.0)
railties (>= 5.0)
webdrivers (4.6.0)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (>= 3.0, < 4.0)
webpacker (5.4.0)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-driver (0.7.5-java)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
PLATFORMS
java
ruby
x64-mingw32
x86-mingw32
x86-mswin32
DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap (>= 1.1.0)
byebug
capybara (>= 2.15)
jbuilder (~> 2.5)
listen (>= 3.0.5, < 3.2)
pg (>= 0.18, < 2.0)
puma (~> 4.3.8)
rails (~> 5.2.6)
rubocop (~> 1.17)
rubocop-rails
selenium-webdriver
simplecov
simplecov-console
spring
spring-watcher-listen (~> 2.0.0)
turbolinks (~> 5)
uglifier (>= 1.3.0)
web-console (>= 3.3.0)
webdrivers
webpacker
RUBY VERSION
ruby 2.6.3p62
BUNDLED WITH
2.1.4 2.1.4
-49
View File
@@ -1,49 +0,0 @@
# URL shortener
<img width="1200" alt="image" src="https://user-images.githubusercontent.com/27580836/227800665-4ff7e2ae-8189-4593-8961-496b7c9ac861.png">
# Features
- [x] Create link model (make sure to create a index for the slug and click counter)
- [x] Generate unique slug
- [x] Link unit tests
- [x] Stimulus setup
- [x] Link controller (handle redirection)
- [x] Main page with input box
- [x] Create user model
- [x] User unit tests
- [x] Add userId key to link model
- [x] Login and logout (sessions)
- [x] User links view
- [x] Modals layout
- [x] Deployment CI
# How to run
## Development
- Run migrations
```bash
docker-compose up -d db
docker-compose run --rm app bundle exec rails db:migrate
```
- Run
```bash
docker-compose up
```
## Testing
```bash
docker-compose run --rm app bundle exec rails test
```
## Rubocop
```bash
docker-compose run --rm app bundle exec rubocop
```
## Dokku deployment
```bash
bundle exec rails db:migrate
```
## Production link
https://url-shortener.sjdonado.de
-8
View File
@@ -1,8 +0,0 @@
# frozen_string_literal: true
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require_relative 'config/application'
Rails.application.load_tasks
@@ -1,7 +0,0 @@
# frozen_string_literal: true
class ApplicationController < ActionController::Base
def authenticate
@current_user = User.find_by(id: session[:user_id])
end
end
-49
View File
@@ -1,49 +0,0 @@
# frozen_string_literal: true
class LinksController < ApplicationController
include LinksHelper
before_action :authenticate, only: %i[create]
before_action :set_link, only: %i[redirect counter]
def redirect
if @link
@link.increment!(:click_counter) # rubocop:disable Rails/SkipsModelValidations
redirect_to @link.parsed_url
else
render file: Rails.root.join('/public/404'), status: :not_found
end
end
def counter
if @link
render json: @link.click_counter
else
render json: nil, status: :not_found
end
end
def create
url = stripped_url(link_params[:url])
@link = Link.find_or_create_by(url: url) do |link|
link.user = @current_user if @current_user
end
if @link.errors.any?
render json: @link.errors, status: :unprocessable_entity
else
render partial: 'links/show', locals: { link: @link }, status: :ok
end
end
private
def set_link
@link = Link.find_by(slug: params[:slug])
end
def link_params
params.require(:link).permit(:url)
end
end
-31
View File
@@ -1,31 +0,0 @@
# frozen_string_literal: true
class SessionsController < ApplicationController
before_action :authenticate, except: %i[create]
before_action :set_user, only: %i[create]
def create
if @user&.authenticate(session_params[:password])
session[:user_id] = @user.id
session[:username] = @user.username
render json: nil, status: :ok
else
render json: { username: ['Credentials not valid, try again or create an account'] }, status: :unauthorized
end
end
def destroy
reset_session
render json: nil, status: :ok
end
private
def set_user
@user = User.find_by(username: session_params[:username])
end
def session_params
params.permit(:username, :password)
end
end
-30
View File
@@ -1,30 +0,0 @@
# frozen_string_literal: true
class UsersController < ApplicationController
around_action :confirm_password_validation, only: %i[create]
def create
@user = User.create(user_params)
if @user.errors.any?
render json: @user.errors, status: :unprocessable_entity
else
session[:user_id] = @user.id
session[:username] = @user.username
render json: nil, status: :ok
end
end
private
def confirm_password_validation
if user_params[:password] == params[:user][:confirm_password]
yield
else
render json: { password: ['Password not match with Confirm Password'] }, status: :bad_request
end
end
def user_params
params.require(:user).permit(:username, :password)
end
end
-7
View File
@@ -1,7 +0,0 @@
# frozen_string_literal: true
module LinksHelper
def stripped_url(url)
url.sub(%r{^.*://(www\.)?}, '').sub(/^www\./, '')
end
end
-7
View File
@@ -1,7 +0,0 @@
# frozen_string_literal: true
module SessionsHelper
def current_user_username
session[:username]
end
end
-10
View File
@@ -1,10 +0,0 @@
// Load all the controllers within this directory and all subdirectories.
// Controller files must be named *_controller.js.
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"
const application = Application.start()
const context = require.context("controllers", true, /_controller\.js$/)
application.load(definitionsFromContext(context))
@@ -1,60 +0,0 @@
import { Controller } from "stimulus"
import Turbolinks from "turbolinks"
export default class extends Controller {
static targets = ["url", "output", "userLinks"]
initialize() {
this.lastLink = null
this.sessionUsername = localStorage.getItem("session-username")
}
onCreateLinkSuccess(event) {
const [, , xhr] = event.detail
this.outputTarget.innerHTML = xhr.response
if (this.sessionUsername && this.lastLink && this.lastLink.includes(this.sessionUsername)
&& !this.userLinksTarget.innerHTML.includes(this.lastLink)) {
this.userLinksTarget.innerHTML = this.lastLink + this.userLinksTarget.innerHTML
}
this.lastLink = xhr.response
}
onCreateLinkError(event) {
const [data, ,] = event.detail
const urlError = `Url: ${data.url.join(' ')}`
alert(urlError)
}
async updateLinkCounter(counterElem, slug) {
const clickCounter = await fetch(`links/${slug}/counter`, {
headers: {
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
}).then((res) => res.json());
if (clickCounter) {
counterElem.innerText = clickCounter
}
}
openLink(event) {
const counterElem = event.target.parentElement.parentElement.parentElement.getElementsByClassName("counter")[0]
const link = event.target.innerText
let visibilitychange = 0
const visibilitychangeListener = () => {
if(visibilitychange > 0) {
document.removeEventListener("visibilitychange", visibilitychangeListener)
this.updateLinkCounter(counterElem, link.substring(link.lastIndexOf('/') + 1))
return
}
visibilitychange += 1
}
document.addEventListener("visibilitychange", visibilitychangeListener)
window.open(link, "_blank")
}
}
@@ -1,61 +0,0 @@
import { Controller } from "stimulus"
import Turbolinks from "turbolinks"
export default class extends Controller {
static targets = ["signupModal", "loginModal"]
openLoginModal() {
this.loginModalTarget.classList.remove("hidden")
}
closeLoginModal() {
this.loginModalTarget.classList.add("hidden")
}
openSignupModal() {
this.closeLoginModal()
this.signupModalTarget.classList.remove("hidden")
}
closeSignupModal() {
this.signupModalTarget.classList.add("hidden")
}
onSignupSuccess() {
this.closeSignupModal();
Turbolinks.visit('/')
}
onLoginSuccess() {
this.closeLoginModal();
Turbolinks.visit('/')
}
onError(event) {
const [data, ,] = event.detail
const errors = []
if (data.username) {
errors.push(`Username: ${data.username.join(' ')}`)
}
if (data.password) {
errors.push(`Password: ${data.password.join(' ')}`)
}
alert(errors.join(','))
}
confirmLogout(event) {
if (!window.confirm("Do you really want to leave?")) {
event.stopPropagation()
return
}
}
onSuccessLogout() {
localStorage.removeItem("session-username")
Turbolinks.visit('/')
}
}
-5
View File
@@ -1,5 +0,0 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
@import "../stylesheets/base.css";
-23
View File
@@ -1,23 +0,0 @@
/* eslint no-console:0 */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)
require("@rails/ujs").start()
require("turbolinks").start()
import "controllers"
import "./application.css"
-3
View File
@@ -1,3 +0,0 @@
a, button, input[type=submit] {
cursor: pointer;
}
-5
View File
@@ -1,5 +0,0 @@
# frozen_string_literal: true
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
-34
View File
@@ -1,34 +0,0 @@
# frozen_string_literal: true
class Link < ApplicationRecord
validates :url, presence: true
validates :slug, uniqueness: true
validates :url,
format: {
with: %r{\A(?:https?://)?(?:\w+\.)?(?:google\.com|sjdonado\.de)(?:/[\w-]+)*/?\z},
message: 'domains allowed for demo purposes: [google.com, sjdonado.de]'
}
validates :url, length: { within: 3..30_000, on: :create, message: 'max length is 30000' }
before_validation :generate_slug
def parsed_url
"https://#{url}"
end
def generate_slug(attempts = 0)
return if slug.present? || attempts == 3
# Number of combinations 62P6
generated_slug = SecureRandom.alphanumeric(6)
if Link.exists?(slug: generated_slug)
generate_slug(attempts + 1)
else
self.slug = generated_slug
end
end
belongs_to :user, optional: true
end
-8
View File
@@ -1,8 +0,0 @@
# frozen_string_literal: true
class User < ApplicationRecord
validates :username, uniqueness: true
has_secure_password
has_many :links, dependent: :nullify
end
-10
View File
@@ -1,10 +0,0 @@
<div data-users-target="<%= target %>" class="fixed z-10 inset-0 overflow-y-auto hidden" aria-labelledby="modal-title" role="dialog" aria-modal="true">
<div class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" aria-hidden="true"></div>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<%= yield %>
</div>
</div>
-33
View File
@@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>URL Shortener</title>
<meta name="description" content="Tailwind + Stimulus + Rails 5 app">
<meta name="keywords" content="url-shortener, shortener, url">
<meta property="og:title" content="URL Shortener">
<meta property="og:type" content="website">
<meta property="og:url" content="https://url-shortener.sjdonado.de">
<meta property="og:site_name" content="URL Shortener">
<meta property="og:description" content="Tailwind + Stimulus + Rails 5 app">
<meta property="og:image" content="https://user-images.githubusercontent.com/27580836/227800665-4ff7e2ae-8189-4593-8961-496b7c9ac861.png">
<meta property="og:image:alt" content="URL Shortener screenshot">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= yield %>
</body>
</html>
-14
View File
@@ -1,14 +0,0 @@
<%= form_with model: Link.new, url: links_path(@link), data: { action: 'ajax:success->links#onCreateLinkSuccess ajax:error->links#onCreateLinkError' } do |f| %>
<div class="col-span-3 sm:col-span-2">
<label for="company_website" class="text-lg leading-6 font-medium text-gray-900">
URL Shortener
</label>
<div class="mt-4 flex rounded-md shadow-sm">
<%= f.text_field :url, pattern: '(https?:\/\/)?(www\.)?([a-zA-Z0-9_-]+\.)+[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?([\/?#][^\s]*)?', data: { target: "links.url" }, placeholder: "https://google.com", class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300" %>
</div>
</div>
<div class="py-3 text-right">
<%= f.submit "Shorten", class: "inline-flex w-full sm:w-auto justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %>
</div>
<% end %>
-8
View File
@@ -1,8 +0,0 @@
<% unless @current_user.nil? %>
<h2 class="text-2xl leading-6 font-medium text-gray-900 mx-4 my-6">My links</h2>
<div data-links-target="userLinks">
<% @current_user.links.order(created_at: :desc).each do |link| %>
<%= render partial: "links/show", locals: { link: link } %>
<% end %>
</div>
<% end %>
-4
View File
@@ -1,4 +0,0 @@
<div class="bg-white shadow overflow-hidden sm:rounded-lg m-3 p-6">
<%= render partial: "links/form" %>
</div>
<div data-links-target="output" class="my-6"></div>
-38
View File
@@ -1,38 +0,0 @@
<div class="bg-white shadow overflow-hidden sm:rounded-lg m-3">
<div class="border-t border-gray-200">
<dl>
<div class="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium text-gray-500">
Website
</dt>
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
<a href="<%= link.parsed_url %>" class="mt-1 text-sm text-gray-600 underline" target="_blank" rel="noreferrer"><%= link.url %></a>
</dd>
</div>
<div class="bg-white px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium text-gray-500">
Shortened URL
</dt>
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
<button data-action="click->links#openLink" class="mt-1 text-sm text-gray-600 underline"><%= short_url(slug: link.slug) %></button>
</dd>
</div>
<div class="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium text-gray-500">
Click counter
</dt>
<dd class="counter mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
<%= link.click_counter %>
</dd>
</div>
<div class="bg-white px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
<dt class="text-sm font-medium text-gray-500">
Created by
</dt>
<dd class="counter mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
<%= link.user ? link.user.username : 'Guest user' %>
</dd>
</div>
</dl>
</div>
</div>
-34
View File
@@ -1,34 +0,0 @@
<%= form_with url: '/login', data: { action: 'ajax:success->users#onLoginSuccess ajax:error->users#onError' }, class: "inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" do |f| %>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div class="flex-1 mt-3 text-center sm:mt-0 sm:mx-4 sm:text-left">
<h3 class="text-xl leading-6 font-medium text-gray-900">
Login
</h3>
<div class="flex-col mt-4">
<div class="my-2">
<label for="username" class="block text-sm font-medium text-gray-700 text-left">
Username
</label>
<%= f.text_field :username, class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300" %>
</div>
<div class="my-2">
<label for="password" class="block text-sm font-medium text-gray-700 text-left">
Password
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<%= f.password_field :password, class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300" %>
</div>
</div>
</div>
</div>
</div>
<button type="button" data-action="click->users#openSignupModal" class="block w-full text-sm font-medium sm:pl-4 pt-6 underline text-center sm:text-left">Create an account</button>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<%= f.submit "Login", class: "my-1 mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" %>
<button data-action="click->users#closeLoginModal" type="button" class="my-1 sm:mt-0 w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
<%end%>
-21
View File
@@ -1,21 +0,0 @@
<div data-controller="users">
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<% if @current_user.nil? %>
<button data-action="click->users#openLoginModal" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
Login
</button>
<% end %>
<%= render partial: "users/show" %>
</div>
<%= render partial: "users/new", layout: "layouts/modal", locals: { target: 'signupModal' } %>
<%= render partial: "sessions/new", layout: "layouts/modal", locals: { target: 'loginModal' } %>
</div>
<div data-controller="links">
<%= render partial: "links/new" %>
<%= render partial: "links/index" %>
</div>
<% unless @current_user.nil? %>
<script>localStorage.setItem("session-username", "<%= current_user_username %>");</script>
<% end %>
-39
View File
@@ -1,39 +0,0 @@
<%= form_with model: User.new, url: users_path(@user), data: { action: 'ajax:success->users#onSignupSuccess ajax:error->users#onError' }, class: "inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" do |f| %>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="flex-1 mt-3 text-center sm:mt-0 sm:mx-4 sm:text-left">
<h3 class="text-xl leading-6 font-medium text-gray-900">
Sign Up
</h3>
<div class="flex-col mt-4">
<div class="my-2">
<label for="username" class="block text-sm font-medium text-gray-700 text-left">
Username
</label>
<%= f.text_field :username, class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300" %>
</div>
<div class="my-2">
<label for="password" class="block text-sm font-medium text-gray-700 text-left">
Password
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<%= f.password_field :password, class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300" %>
</div>
</div>
<div class="my-2">
<label for="confirm_password" class="block text-sm font-medium text-gray-700 text-left">
Confirm password
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<%= f.password_field :confirm_password, class: "focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-md sm:text-sm border-gray-300" %>
</div>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<%= f.submit "Sign Up", class: "my-1 mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" %>
<button data-action="click->users#closeSignupModal" type="button" class="my-1 sm:mt-0 w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">
Cancel
</button>
</div>
<%end%>
-4
View File
@@ -1,4 +0,0 @@
<% unless @current_user.nil? %>
<%= link_to "Logout", '/session/logout', data: { action: 'ajax:before->users#confirmLogout ajax:success->users#onSuccessLogout' }, remote: true, class: "mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" %>
<h1 class="px-2 py-2 text-sm font-medium">You are Logged In, <%= @current_user.username %></h1>
<%end%>
-70
View File
@@ -1,70 +0,0 @@
module.exports = function(api) {
var validEnv = ['development', 'test', 'production']
var currentEnv = api.env()
var isDevelopmentEnv = api.env('development')
var isProductionEnv = api.env('production')
var isTestEnv = api.env('test')
if (!validEnv.includes(currentEnv)) {
throw new Error(
'Please specify a valid `NODE_ENV` or ' +
'`BABEL_ENV` environment variables. Valid values are "development", ' +
'"test", and "production". Instead, received: ' +
JSON.stringify(currentEnv) +
'.'
)
}
return {
presets: [
isTestEnv && [
'@babel/preset-env',
{
targets: {
node: 'current'
}
}
],
(isProductionEnv || isDevelopmentEnv) && [
'@babel/preset-env',
{
forceAllTransforms: true,
useBuiltIns: 'entry',
corejs: 3,
modules: false,
exclude: ['transform-typeof-symbol']
}
]
].filter(Boolean),
plugins: [
'babel-plugin-macros',
'@babel/plugin-syntax-dynamic-import',
isTestEnv && 'babel-plugin-dynamic-import-node',
'@babel/plugin-transform-destructuring',
[
'@babel/plugin-proposal-class-properties',
{
loose: false
}
],
[
'@babel/plugin-proposal-object-rest-spread',
{
useBuiltIns: true
}
],
[
'@babel/plugin-transform-runtime',
{
helpers: false
}
],
[
'@babel/plugin-transform-regenerator',
{
async: false
}
]
].filter(Boolean)
}
}
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
load Gem.bin_path('bundler', 'bundle')
-6
View File
@@ -1,6 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
-6
View File
@@ -1,6 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require_relative '../config/boot'
require 'rake'
Rake.application.run
-38
View File
@@ -1,38 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'fileutils'
include FileUtils
# path to your application root.
APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end
chdir APP_ROOT do
# This script is a starting point to setup your application.
# Add necessary setup steps to this file.
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
# Install JavaScript dependencies if using Yarn
# system('bin/yarn')
# puts "\n== Copying sample files =="
# unless File.exist?('config/database.yml')
# cp 'config/database.yml.sample', 'config/database.yml'
# end
puts "\n== Preparing database =="
system! 'bin/rails db:setup'
puts "\n== Removing old logs and tempfiles =="
system! 'bin/rails log:clear tmp:clear'
puts "\n== Restarting application server =="
system! 'bin/rails restart'
end
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'fileutils'
include FileUtils
# path to your application root.
APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end
chdir APP_ROOT do
# This script is a way to update your development environment automatically.
# Add necessary update steps to this file.
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
# Install JavaScript dependencies if using Yarn
# system('bin/yarn')
puts "\n== Updating database =="
system! 'bin/rails db:migrate'
puts "\n== Removing old logs and tempfiles =="
system! 'bin/rails log:clear tmp:clear'
puts "\n== Restarting application server =="
system! 'bin/rails restart'
end
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
ENV['RAILS_ENV'] ||= ENV['RACK_ENV'] || 'development'
ENV['NODE_ENV'] ||= 'development'
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
Pathname.new(__FILE__).realpath)
require 'bundler/setup'
require 'webpacker'
require 'webpacker/webpack_runner'
APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::WebpackRunner.run(ARGV)
end
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
ENV['RAILS_ENV'] ||= ENV['RACK_ENV'] || 'development'
ENV['NODE_ENV'] ||= 'development'
require 'pathname'
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
Pathname.new(__FILE__).realpath)
require 'bundler/setup'
require 'webpacker'
require 'webpacker/dev_server_runner'
APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::DevServerRunner.run(ARGV)
end
-11
View File
@@ -1,11 +0,0 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do
exec 'yarnpkg', *ARGV
rescue Errno::ENOENT
warn 'Yarn executable was not detected in the system.'
warn 'Download Yarn at https://yarnpkg.com/en/docs/install'
exit 1
end
-7
View File
@@ -1,7 +0,0 @@
# frozen_string_literal: true
# This file is used by Rack-based servers to start the application.
require_relative 'config/environment'
run Rails.application
-21
View File
@@ -1,21 +0,0 @@
# frozen_string_literal: true
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module App
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.2
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
end
end
-6
View File
@@ -1,6 +0,0 @@
# frozen_string_literal: true
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
-8
View File
@@ -1,8 +0,0 @@
development:
adapter: async
test:
adapter: async
production:
adapter: async
-1
View File
@@ -1 +0,0 @@
/UPkhc4cuB6geZB3wUkY6YEc2RAEr775PbtKCLNL47TG7qdyd8Cl2rcrgwpGBnqJY2ZTXGqoIV20O5HyejxD6+jiFmuEjXi/scS451d0SoMQDZobH2G2+wSfPCIoz5uW5E9ZRE+HUEIa8Ja2fQ4rUK/TFa90RLt5x67SKWBNFoXkbJ4NR+s6/3B6b7LUyoTc8SpWuzxLbXjfXSoUAB6VZNvfN/wX8U5wK+vKb9cZVkd1ltGvAm1QLbrWfAKQTL5uzy/pNJflH9AFEga5d/JMG1NAui7T87NVSh08iYpkJOEpjbqAEwQOE1WRyCCQ6v+nsQSV7sEaMxjMOEItHAi/8gEnbMP5NmXmJ1/7VTgDFZVoolww7T64KyIiFShORxg71z1BqojwdKTjsWQ2XjVlchZIk0CYakMukJC/--daZZ3htNyJPK0uYc--VdreTqiXCOY5i5RJnF0dmg==
-89
View File
@@ -1,89 +0,0 @@
# PostgreSQL. Versions 9.1 and up are supported.
#
# Install the pg driver:
# gem install pg
# On OS X with Homebrew:
# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On OS X with MacPorts:
# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
# gem install pg
# Choose the win32 build.
# Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem 'pg'
#
default: &default
adapter: postgresql
encoding: unicode
# For details on connection pooling, see Rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
host: db
database: url_shortener
username: app_user
password: secure_12345
# The specified database role being used to connect to postgres.
# To create additional roles in postgres see `$ createuser --help`.
# When left blank, postgres will use the default role. This is
# the same name as the operating system user that initialized the database.
#username: app
# The password associated with the postgres role (username).
#password:
# Connect on a TCP socket. Omitted by default since the client uses a
# domain socket that doesn't need configuration. Windows does not have
# domain sockets, so uncomment these lines.
#host: localhost
# The TCP port the server listens on. Defaults to 5432.
# If your server runs on a different port number, change accordingly.
#port: 5432
# Schema search path. The server defaults to $user,public
#schema_search_path: myapp,sharedapp,public
# Minimum log levels, in increasing order:
# debug5, debug4, debug3, debug2, debug1,
# log, notice, warning, error, fatal, and panic
# Defaults to warning.
#min_messages: notice
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
host: db
database: test_url_shortener
username: app_user
password: secure_12345
# As with config/secrets.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%= ENV['DATABASE_URL'] %>
#
production:
<<: *default
url: <%= ENV['DATABASE_URL'] %>
-7
View File
@@ -1,7 +0,0 @@
# frozen_string_literal: true
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
-65
View File
@@ -1,65 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports.
config.consider_all_requests_local = true
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join('tmp/caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
config.action_mailer.perform_caching = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
# Suppress logger output for asset requests.
config.assets.quiet = true
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
Rails.application.routes.default_url_options[:host] = "#{ENV['HOSTNAME']}:#{ENV['RAILS_PORT']}"
end
-97
View File
@@ -1,97 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
config.require_master_key = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = true
# Compress JavaScripts and CSS.
config.assets.js_compressor = Uglifier.new(harmony: true)
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = true
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
# config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
# Prepend all log lines with the following tags.
config.log_tags = [:request_id]
config.cache_store = :memory_store
# Use a real queuing backend for Active Job (and separate queues per environment)
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "app_#{Rails.env}"
config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV['RAILS_LOG_TO_STDOUT'].present?
logger = ActiveSupport::Logger.new($stdout)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
Rails.application.routes.default_url_options[:host] = ENV['HOSTNAME']
end
-49
View File
@@ -1,49 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
}
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Store uploaded files on the local file system in a temporary directory
config.active_storage.service = :test
config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
Rails.application.routes.default_url_options[:host] = "#{ENV['HOSTNAME']}:#{ENV['RAILS_PORT']}"
end
@@ -1,9 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# ActiveSupport::Reloader.to_prepare do
# ApplicationController.renderer.defaults.merge!(
# http_host: 'example.org',
# https: false
# )
# end
-16
View File
@@ -1,16 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
# Add Yarn node_modules folder to the asset load path.
Rails.application.config.assets.paths << Rails.root.join('node_modules')
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
@@ -1,8 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!
@@ -1,26 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Rails.application.config.content_security_policy do |policy|
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
# policy.object_src :none
# policy.script_src :self, :https
# policy.style_src :self, :https
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true
@@ -1,7 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Specify a serializer for the signed and encrypted cookie jars.
# Valid options are :json, :marshal, and :hybrid.
Rails.application.config.action_dispatch.cookies_serializer = :json
@@ -1,6 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password]
-17
View File
@@ -1,17 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
-5
View File
@@ -1,5 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
-16
View File
@@ -1,16 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end
-33
View File
@@ -1,33 +0,0 @@
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t 'hello'
#
# In views, this is aliased to just `t`:
#
# <%= t('hello') %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# The following keys must be escaped otherwise they will not be retrieved by
# the default I18n backend:
#
# true, false, on, off, yes, no
#
# Instead, surround them with single quotes.
#
# en:
# 'true': 'foo'
#
# To learn more, please read the Rails Internationalization guide
# available at http://guides.rubyonrails.org/i18n.html.
en:
hello: "Hello world"
-39
View File
@@ -1,39 +0,0 @@
# frozen_string_literal: true
# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
threads_count = ENV.fetch('RAILS_MAX_THREADS', 5)
threads threads_count, threads_count
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch('PORT', 3000)
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch('RAILS_ENV', 'development')
# Specifies the `pidfile` that Puma will use.
pidfile ENV.fetch('PIDFILE', 'tmp/pids/server.pid')
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked webserver processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
# preload_app!
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
-14
View File
@@ -1,14 +0,0 @@
# frozen_string_literal: true
Rails.application.routes.draw do
root 'sessions#index'
get '/:slug', to: 'links#redirect', as: :short
get 'links/:slug/counter', to: 'links#counter', as: :counter
get 'session/logout', to: 'sessions#destroy', as: :logout
post 'login', to: 'sessions#create', as: :login
resources :links, only: %i[create]
resources :users, only: %i[create]
end
-8
View File
@@ -1,8 +0,0 @@
# frozen_string_literal: true
%w[
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
].each { |path| Spring.watch(path) }
-34
View File
@@ -1,34 +0,0 @@
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon:
# service: S3
# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
# region: us-east-1
# bucket: your_own_bucket
# Remember not to checkin your GCS keyfile to a repository
# google:
# service: GCS
# project: your_project
# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
# bucket: your_own_bucket
# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
# microsoft:
# service: AzureStorage
# storage_account_name: your_account_name
# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
# container: your_container_name
# mirror:
# service: Mirror
# primary: local
# mirrors: [ amazon, google, microsoft ]
-5
View File
@@ -1,5 +0,0 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
-3
View File
@@ -1,3 +0,0 @@
const { environment } = require('@rails/webpacker')
module.exports = environment
-5
View File
@@ -1,5 +0,0 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
-5
View File
@@ -1,5 +0,0 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
-92
View File
@@ -1,92 +0,0 @@
# Note: You must restart bin/webpack-dev-server for changes to take effect
default: &default
source_path: app/javascript
source_entry_path: packs
public_root_path: public
public_output_path: packs
cache_path: tmp/cache/webpacker
webpack_compile_output: true
# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
additional_paths: []
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
# Extract and emit a css file
extract_css: false
static_assets_extensions:
- .jpg
- .jpeg
- .png
- .gif
- .tiff
- .ico
- .svg
- .eot
- .otf
- .ttf
- .woff
- .woff2
extensions:
- .mjs
- .js
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
- .jpeg
- .jpg
development:
<<: *default
compile: false
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
host: localhost
port: 3035
public: localhost:3035
hmr: false
# Inline should be set to true if using HMR
inline: true
overlay: true
compress: true
disable_host_check: true
use_local_ip: false
quiet: false
pretty: false
headers:
'Access-Control-Allow-Origin': '*'
watch_options:
ignored: '**/node_modules/**'
test:
<<: *default
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
production:
<<: *default
# Production depends on precompilation of packs prior to booting for performance.
compile: true
# Extract and emit a css file
extract_css: true
# Cache manifest.json for performance
cache_manifest: true
-13
View File
@@ -1,13 +0,0 @@
# frozen_string_literal: true
class CreateLinks < ActiveRecord::Migration[5.2]
def change
create_table :links do |t|
t.string :slug, null: false
t.text :url
t.integer :click_counter, default: 0
t.timestamps
end
end
end
@@ -1,7 +0,0 @@
# frozen_string_literal: true
class AddSlugIndexToLinks < ActiveRecord::Migration[5.2]
def change
add_index :links, :slug
end
end
-12
View File
@@ -1,12 +0,0 @@
# frozen_string_literal: true
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :username
t.string :password_digest
t.timestamps
end
end
end
@@ -1,7 +0,0 @@
# frozen_string_literal: true
class AddUserIdToLinks < ActiveRecord::Migration[5.2]
def change
add_reference :links, :user, foreign_key: true
end
end
@@ -1,7 +0,0 @@
# frozen_string_literal: true
class AddUsernameIndexToUsers < ActiveRecord::Migration[5.2]
def change
add_index :users, :username, unique: true
end
end
@@ -1,8 +0,0 @@
# frozen_string_literal: true
class UniqueSlugIndex < ActiveRecord::Migration[5.2]
def change
remove_index :links, column: :slug
add_index :links, :slug, unique: true
end
end
-38
View File
@@ -1,38 +0,0 @@
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_06_15_200050) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "links", force: :cascade do |t|
t.string "slug", null: false
t.text "url"
t.integer "click_counter", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "user_id"
t.index ["slug"], name: "index_links_on_slug", unique: true
t.index ["user_id"], name: "index_links_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "username"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["username"], name: "index_users_on_username", unique: true
end
add_foreign_key "links", "users"
end
-8
View File
@@ -1,8 +0,0 @@
# frozen_string_literal: true
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
#
# Examples:
#
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first)
-42
View File
@@ -1,42 +0,0 @@
version: '3'
services:
db:
build:
context: .
dockerfile: Dockerfile.db
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_USER: app_user
POSTGRES_PASSWORD: secure_12345
ports:
- 5432:5432
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/usr/src/app
- gem_cache:/usr/local/bundle/gems
command: bundle exec rails s -b '0.0.0.0'
tty: true
environment:
RAILS_ENV: development
HOSTNAME: 0.0.0.0
ports:
- 3000:3000
depends_on:
- db
webpack:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/usr/src/app
- gem_cache:/usr/local/bundle/gems
command: bin/webpack --watch --colors --progress
tty: true
volumes:
gem_cache:
db_data:
-5
View File
@@ -1,5 +0,0 @@
CREATE DATABASE url_shortener;
CREATE DATABASE test_url_shortener;
GRANT ALL PRIVILEGES ON DATABASE url_shortener TO app_user;
GRANT ALL PRIVILEGES ON DATABASE test_url_shortener TO app_user;
-9
View File
@@ -1,9 +0,0 @@
#!/bin/sh
set -e
bundle check || bundle install --jobs 20 --retry 5
rm -f $APP_PATH/tmp/pids/server.pid
${@}
-7
View File
@@ -1,7 +0,0 @@
#!/bin/sh
set -e
rm -f "$APP_PATH/tmp/pids/server.pid"
"${@}"
View File
-22
View File
@@ -1,22 +0,0 @@
{
"name": "app",
"private": true,
"dependencies": {
"@rails/ujs": "^6.0.3-7",
"@rails/webpacker": "5.4.0",
"@tailwindcss/forms": "^0.3.3",
"autoprefixer": "^9",
"css-loader": "^5.2.6",
"css-minimizer-webpack-plugin": "^3.0.1",
"mini-css-extract-plugin": "^1.6.0",
"postcss": "^8.2.10",
"stimulus": "^2.0.0",
"tailwindcss": "npm:@tailwindcss/postcss7-compat",
"turbolinks": "^5.2.0",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12"
},
"devDependencies": {
"webpack-dev-server": "^3.11.2"
}
}
-13
View File
@@ -1,13 +0,0 @@
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
}
-67
View File
@@ -1,67 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>The page you were looking for doesn't exist (404)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
.rails-default-error-page {
background-color: #EFEFEF;
color: #2E2F30;
text-align: center;
font-family: arial, sans-serif;
margin: 0;
}
.rails-default-error-page div.dialog {
width: 95%;
max-width: 33em;
margin: 4em auto 0;
}
.rails-default-error-page div.dialog > div {
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #BBB;
border-top: #B00100 solid 4px;
border-top-left-radius: 9px;
border-top-right-radius: 9px;
background-color: white;
padding: 7px 12% 0;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
.rails-default-error-page h1 {
font-size: 100%;
color: #730E15;
line-height: 1.5em;
}
.rails-default-error-page div.dialog > p {
margin: 0 0 1em;
padding: 1em;
background-color: #F7F7F7;
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #999;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top-color: #DADADA;
color: #666;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
</style>
</head>
<body class="rails-default-error-page">
<!-- This file lives in public/404.html -->
<div class="dialog">
<div>
<h1>The page you were looking for doesn't exist.</h1>
<p>You may have mistyped the address or the page may have moved.</p>
</div>
<p>If you are the application owner check the logs for more information.</p>
</div>
</body>
</html>
-67
View File
@@ -1,67 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>The change you wanted was rejected (422)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
.rails-default-error-page {
background-color: #EFEFEF;
color: #2E2F30;
text-align: center;
font-family: arial, sans-serif;
margin: 0;
}
.rails-default-error-page div.dialog {
width: 95%;
max-width: 33em;
margin: 4em auto 0;
}
.rails-default-error-page div.dialog > div {
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #BBB;
border-top: #B00100 solid 4px;
border-top-left-radius: 9px;
border-top-right-radius: 9px;
background-color: white;
padding: 7px 12% 0;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
.rails-default-error-page h1 {
font-size: 100%;
color: #730E15;
line-height: 1.5em;
}
.rails-default-error-page div.dialog > p {
margin: 0 0 1em;
padding: 1em;
background-color: #F7F7F7;
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #999;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top-color: #DADADA;
color: #666;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
</style>
</head>
<body class="rails-default-error-page">
<!-- This file lives in public/422.html -->
<div class="dialog">
<div>
<h1>The change you wanted was rejected.</h1>
<p>Maybe you tried to change something you didn't have access to.</p>
</div>
<p>If you are the application owner check the logs for more information.</p>
</div>
</body>
</html>
-66
View File
@@ -1,66 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>We're sorry, but something went wrong (500)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
.rails-default-error-page {
background-color: #EFEFEF;
color: #2E2F30;
text-align: center;
font-family: arial, sans-serif;
margin: 0;
}
.rails-default-error-page div.dialog {
width: 95%;
max-width: 33em;
margin: 4em auto 0;
}
.rails-default-error-page div.dialog > div {
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #BBB;
border-top: #B00100 solid 4px;
border-top-left-radius: 9px;
border-top-right-radius: 9px;
background-color: white;
padding: 7px 12% 0;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
.rails-default-error-page h1 {
font-size: 100%;
color: #730E15;
line-height: 1.5em;
}
.rails-default-error-page div.dialog > p {
margin: 0 0 1em;
padding: 1em;
background-color: #F7F7F7;
border: 1px solid #CCC;
border-right-color: #999;
border-left-color: #999;
border-bottom-color: #999;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-top-color: #DADADA;
color: #666;
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
}
</style>
</head>
<body class="rails-default-error-page">
<!-- This file lives in public/500.html -->
<div class="dialog">
<div>
<h1>We're sorry, but something went wrong.</h1>
</div>
<p>If you are the application owner check the logs for more information.</p>
</div>
</body>
</html>
View File
View File
-1
View File
@@ -1 +0,0 @@
# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
-13
View File
@@ -1,13 +0,0 @@
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [
require('@tailwindcss/forms'),
],
}
-7
View File
@@ -1,7 +0,0 @@
# frozen_string_literal: true
require 'test_helper'
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
end
-63
View File
@@ -1,63 +0,0 @@
# frozen_string_literal: true
require 'test_helper'
class LinksControllerTest < ActionDispatch::IntegrationTest
test 'Should get index page' do
get '/'
assert_response :success
end
test 'Should return 404 for unavailable slug' do
get '/test'
assert_response :not_found
end
test 'Should create a link' do
url = 'https://test.sjdonado.de'
post links_url, params: { link: { url: url } }
assert_response :success
end
test 'Should create a link with user' do
user = users(:one)
post login_url, params: { username: user.username, password: '12345' }
assert_response :success
url = 'https://test.sjdonado.de'
post links_url, params: { link: { url: url } }
assert_response :success
end
test 'Should return 422 on create an invalid link' do
url = 'test'
post links_url, params: { link: { url: url } }
assert_response :unprocessable_entity
end
test 'Should redirect from slug to url' do
link = links(:one)
slug = link.slug
get short_url(slug: slug)
assert_redirected_to link.parsed_url
end
test 'Should get link counter' do
link = links(:one)
get counter_url(slug: link.slug)
assert_response :success
end
test 'Should return 404 on get counter with an invalid slug' do
get counter_url(slug: 'test')
assert_response :not_found
end
end
@@ -1,34 +0,0 @@
# frozen_string_literal: true
require 'test_helper'
class SessionsControllerTest < ActionDispatch::IntegrationTest
test 'Should create an user session' do
user = users(:one)
params = { username: user.username, password: '12345' }
post login_url, params: params
assert_response :success
end
test 'Should return 401 with not available user' do
params = { username: nil, password: 'test' }
post login_url, params: params
assert_response :unauthorized
end
test 'Should return 401 with wrong credentials' do
user = users(:one)
params = { username: user.username, password: 'test' }
post login_url, params: params
assert_response :unauthorized
end
test 'Should destroy session' do
get logout_url
assert_response :success
end
end
-28
View File
@@ -1,28 +0,0 @@
# frozen_string_literal: true
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test 'Should create an user' do
params = { user: { username: 'testing', password: 'testing', confirm_password: 'testing' } }
post users_url, params: params
assert_response :success
end
test 'Should return 400 on create an user without confirm_password' do
user = users(:one)
params = { user: { username: user.username, password: 'testing' } }
post users_url, params: params
assert_response :bad_request
end
test 'Should return 422 on create an user with existing username' do
user = users(:one)
params = { user: { username: user.username, password: 'testing', confirm_password: 'testing' } }
post users_url, params: params
assert_response :unprocessable_entity
end
end
-16
View File
@@ -1,16 +0,0 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
slug: ktr4ms
url: 'https://google.com'
click_counter: 1
two:
slug: qwu62l
url: 'https://www.google.com'
click_counter: 1
three:
slug: rwi43l
url: 'google.com'
click_counter: 1
-9
View File
@@ -1,9 +0,0 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
username: sjdonado
password_digest: <%= BCrypt::Password.create('12345') %>
two:
username: other_user
password_digest: <%= BCrypt::Password.create('67891') %>
-47
View File
@@ -1,47 +0,0 @@
# frozen_string_literal: true
require 'test_helper'
require 'minitest/mock'
class LinkTest < ActiveSupport::TestCase
test 'Should not save a link without a url' do
link = Link.new
assert_not link.save, 'Saved the link without a url'
end
test 'Should not save a link with a invalid url - number' do
link = Link.new
link.url = 0
assert_not link.save, 'Saved the link with invalid url format'
end
test 'Should not save a link with a invalid url - string' do
link = Link.new
link.url = 'test'
assert_not link.save, 'Saved the link with invalid url format'
end
test 'Should generate a slug on save a new link - format https://google.com' do
link = links(:one)
assert link.save, 'Slug generated on save a new link'
end
test 'Should generate a slug on save a new link - format http://www.google.com' do
link = links(:two)
assert link.save, 'Slug generated on save a new link'
end
test 'Should generate a slug on save a new link - format google.com' do
link = links(:three)
assert link.save, 'Slug generated on save a new link'
end
test 'Should generate an unique slug' do
SecureRandom.stub :alphanumeric, 'ktr4ms' do
link = Link.new
link.url = 'https://test.sjdonado.de'
link.generate_slug
assert_raise(ActiveRecord::NotNullViolation) { link.save }
end
end
end
-23
View File
@@ -1,23 +0,0 @@
# frozen_string_literal: true
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test 'Should create an user' do
user = User.new
user.username = 'testing'
user.password = 'testing'
assert user.save, 'User not created'
end
test 'Should not create a user if username is already taken' do
test_user = users(:one)
user = User.new
user.username = test_user.username
user.password = 'testing'
assert_not user.save, 'User created with duplicate username'
end
end
-35
View File
@@ -1,35 +0,0 @@
# frozen_string_literal: true
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
if ENV['RAILS_ENV'] == 'test'
require 'simplecov'
SimpleCov.start 'rails' do
add_filter '/app/channels'
add_filter '/app/mailers'
add_filter '/app/jobs'
enable_coverage :branch
end
simplecov_formatters = [
SimpleCov::Formatter::HTMLFormatter,
SimpleCov::Formatter::Console
]
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(simplecov_formatters)
SimpleCov::Formatter::Console.show_covered = true
puts 'required simplecov'
end
module ActiveSupport
class TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end
end
View File

Some files were not shown because too many files have changed in this diff Show More