tanshuku 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8450b3eed6f8d725bec0a20f44800db1e604f6d4e2d26e1d832fd689c53ab926
4
+ data.tar.gz: '08a7ad0f33eb83a5c231832a5b000a7b3bbf4d31fa78b1e480abaab16677bec2'
5
+ SHA512:
6
+ metadata.gz: f2649e896ad520627924ccb3259de36bf6163d3c555609f5d40b769f91a2627a2178e324153a55cef4791a529b85d8d083f0abc67ccc3c44271b10bebc03e7de
7
+ data.tar.gz: b0d1f57bb3bf30a9d9344642aaf6a96163d927f3895e365c3c33f9e8d923031a8bfb1fed5aff14ab0ecb99d41e8276528f2f006b0d4beab4b16c6a8cfc032ba7
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Takumi KAGIYAMA
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require "rubocop/rake_task"
6
+
7
+ RuboCop::RakeTask.new
8
+
9
+ task default: :rubocop
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tanshuku
4
+ class UrlsController < ActionController::API
5
+ def show
6
+ url = Url.find_by!(key: params[:key])
7
+ redirect_to url.url, status: :moved_permanently, allow_other_host: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record"
4
+ require "addressable"
5
+ require "digest/sha2"
6
+ require "rack"
7
+ require "securerandom"
8
+
9
+ module Tanshuku
10
+ class Url < ActiveRecord::Base
11
+ MAX_URL_LENGTH = 10_000
12
+ URL_PATTERN = %r{\Ahttps?://\w+}
13
+ KEY_LENGTH = 20
14
+
15
+ validates :url, :hashed_url, :key, presence: true
16
+ validates :url, length: { maximum: MAX_URL_LENGTH }
17
+ validates :url, format: { with: URL_PATTERN }
18
+
19
+ # Don't validate uniqueness of unique attributes. Raise ActiveRecord::RecordNotUnique instead if the attributes get
20
+ # duplicated. Then rescue the exception and try to retry.
21
+ # validates :url, :hashed_url, :key, uniqueness: true
22
+
23
+ def self.shorten(original_url, retries: 0)
24
+ url = normalize_url(original_url)
25
+
26
+ record =
27
+ create_or_find_by!(hashed_url: hash_url(url)) do |r|
28
+ r.attributes = { url:, key: generate_key }
29
+ end
30
+
31
+ Tanshuku::Engine.routes.url_for(controller: "tanshuku/urls", action: :show, key: record.key)
32
+ rescue ActiveRecord::RecordNotUnique => e
33
+ if retries < 10
34
+ shorten(url, retries: retries + 1)
35
+ else
36
+ report_exception(exception: e, original_url:)
37
+ original_url
38
+ end
39
+ rescue StandardError => e
40
+ report_exception(exception: e, original_url:)
41
+ original_url
42
+ end
43
+
44
+ # Normalize a trailing slash, `?` for an empty query, and so on, and sort query keys.
45
+ def self.normalize_url(url)
46
+ parsed_url = Addressable::URI.parse(url)
47
+ parsed_url.query_values = Rack::Utils.parse_query(parsed_url.query)
48
+ parsed_url.normalize.to_s
49
+ end
50
+
51
+ def self.hash_url(url)
52
+ Digest::SHA512.hexdigest(url)
53
+ end
54
+
55
+ def self.generate_key
56
+ SecureRandom.alphanumeric(KEY_LENGTH)
57
+ end
58
+
59
+ def self.report_exception(exception:, original_url:)
60
+ logger.warn("Tanshuku - Failed to shorten a URL: #{exception.inspect} for #{original_url.inspect}")
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,15 @@
1
+ en:
2
+ activerecord:
3
+ errors:
4
+ models:
5
+ tanshuku/url:
6
+ attributes:
7
+ url:
8
+ invalid: should start with https:// or http://
9
+ models:
10
+ tanshuku/url: Shortened URL
11
+ attributes:
12
+ tanshuku/url:
13
+ url: URL
14
+ hashed_url: hashed URL
15
+ key: unique key
@@ -0,0 +1,15 @@
1
+ ja:
2
+ activerecord:
3
+ errors:
4
+ models:
5
+ tanshuku/url:
6
+ attributes:
7
+ url:
8
+ invalid: は https:// または http:// で始まる必要があります
9
+ models:
10
+ tanshuku/url: 短縮URL
11
+ attributes:
12
+ tanshuku/url:
13
+ url: URL
14
+ hashed_url: ハッシュ化URL
15
+ key: ユニークキー
data/config/routes.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Tanshuku::Engine.routes.draw do
4
+ default_url_options Rails.application.routes.default_url_options
5
+
6
+ get "/:key", to: "urls#show"
7
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateRailsUrlShortenerUrls < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table :tanshuku_urls do |t|
6
+ t.text :url, null: false
7
+ t.string :hashed_url, null: false, limit: 128, index: { unique: true }, comment: "cf. Tanshuku::Url.hash_url"
8
+ t.string :key, null: false, limit: 20, index: { unique: true }, comment: "cf. Tanshuku::Url.generate_key"
9
+ t.datetime :created_at, null: false, precision: nil
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tanshuku
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Tanshuku
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tanshuku
4
+ VERSION = "0.0.1"
5
+ end
data/lib/tanshuku.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tanshuku/engine"
4
+ require_relative "tanshuku/version"
5
+
6
+ module Tanshuku
7
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tanshuku
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - kg8m
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-02-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: addressable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-performance
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Tanshuku is a Rails engine for shortening URLs. Tanshuku generates a
126
+ shortened URL per a normalized original URL.
127
+ email:
128
+ - takumi.kagiyama@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - LICENSE
134
+ - Rakefile
135
+ - app/controllers/tanshuku/urls_controller.rb
136
+ - app/models/tanshuku/url.rb
137
+ - config/locales/en.yml
138
+ - config/locales/ja.yml
139
+ - config/routes.rb
140
+ - db/migrate/20230220123456_create_tanshuku_urls.rb
141
+ - lib/tanshuku.rb
142
+ - lib/tanshuku/engine.rb
143
+ - lib/tanshuku/version.rb
144
+ homepage: https://github.com/kg8m/tanshuku
145
+ licenses:
146
+ - MIT
147
+ metadata:
148
+ homepage_uri: https://github.com/kg8m/tanshuku
149
+ source_code_uri: https://github.com/kg8m/tanshuku
150
+ changelog_uri: https://github.com/kg8m/tanshuku/releases
151
+ rubygems_mfa_required: 'true'
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '3.2'
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubygems_version: 3.4.1
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Tanshuku is a Rails engine for shortening URLs.
171
+ test_files: []