From 73ee4c447924f2af7a543559ab25c77597a00aab Mon Sep 17 00:00:00 2001 From: sjdonado Date: Thu, 20 Mar 2025 08:13:07 +0100 Subject: [PATCH] fix: user id and link id int64 types --- app/controllers/link.cr | 51 ++++++++++++++++------------------- app/models/click.cr | 2 +- app/models/link.cr | 2 +- app/models/user.cr | 2 +- app/services/cli.cr | 1 - app/services/click_tracker.cr | 5 ++-- app/services/slug.cr | 2 +- scripts/cli.cr | 1 - spec/spec_helper.cr | 12 +++------ 9 files changed, 33 insertions(+), 45 deletions(-) diff --git a/app/controllers/link.cr b/app/controllers/link.cr index b5c0bb7..5143069 100644 --- a/app/controllers/link.cr +++ b/app/controllers/link.cr @@ -1,5 +1,3 @@ -require "uuid" - module App::Controllers class LinkController < App::Lib::BaseController include App::Models @@ -12,21 +10,19 @@ module App::Controllers end def create - user = current_user body = parse_body(["url"]) url = body["url"].to_s - query = Database::Query.where(url: url, user_id: user.id.as(String)).limit(1) + query = Database::Query.where(url: url, user_id: current_user_id).limit(1) existing_link = Database.all(Link, query, preload: [:clicks]).first? if existing_link return render_json({"data" => App::Serializers::Link.new(existing_link)}) end link = Link.new - link.id = UUID.v4.to_s link.url = url - link.user = user - link.slug = SlugService.shorten_url(url, user.id.to_s) + link.user_id = current_user_id + link.slug = SlugService.shorten_url(url, current_user_id) changeset = Database.insert(link) if !changeset.valid? @@ -46,7 +42,7 @@ module App::Controllers # slug autoindex has better perormance than the covering index Database.raw_query("SELECT id, url FROM links WHERE slug = (?)", slug) do |result| if result.move_next - link_data = {result.read(String), result.read(String)} + link_data = {result.read(Int64), result.read(String)} end end raise App::NotFoundException.new(@env) unless link_data @@ -66,10 +62,9 @@ module App::Controllers end def list_all - user = current_user limit, cursor = pagination_params - query = Database::Query.where(user_id: user.id.as(String)) + query = Database::Query.where(user_id: current_user_id) query = query.where("id < ?", cursor) if cursor query = query.order_by("id DESC").limit(limit + 1) @@ -79,14 +74,13 @@ module App::Controllers end def get - user = current_user - link_id = @env.params.url["id"] + link_id = @env.params.url["id"].to_i64 - query = Database::Query.where(id: link_id.as(String), user_id: user.id.as(String)).limit(1) + query = Database::Query.where(id: link_id, user_id: current_user_id).limit(1) link = Database.all(Link, query).first? raise App::NotFoundException.new(@env) if link.nil? - clicks_query = Database::Query.where(link_id: link_id.as(String)) + clicks_query = Database::Query.where(link_id: link_id) .order_by("id DESC") .limit(100) link.clicks = Database.all(Click, clicks_query) @@ -95,17 +89,16 @@ module App::Controllers end def list_clicks - user = current_user - link_id = @env.params.url["id"] + link_id = @env.params.url["id"].to_i64 # Verify link exists and belongs to user - link_query = Database::Query.where(id: link_id.as(String), user_id: user.id.as(String)).limit(1) + link_query = Database::Query.where(id: link_id, user_id: current_user_id).limit(1) link = Database.all(Link, link_query).first? raise App::NotFoundException.new(@env) if link.nil? limit, cursor = pagination_params - query = Database::Query.where(link_id: link_id.as(String)) + query = Database::Query.where(link_id: link_id) query = query.where("id < ?", cursor) if cursor query = query.order_by("id DESC").limit(limit + 1) @@ -115,8 +108,7 @@ module App::Controllers end def update - user = current_user - id = @env.params.url["id"] + id = @env.params.url["id"].to_i64 body = parse_body(["url"]) new_url = body["url"].to_s @@ -124,16 +116,16 @@ module App::Controllers link = Database.all(Link, query, preload: [:clicks]).first? raise App::NotFoundException.new(@env) if link.nil? - raise App::ForbiddenException.new(@env) if link.user_id != user.id + raise App::ForbiddenException.new(@env) if link.user_id != current_user_id # Check for existing URL - existing_query = Database::Query.where(url: new_url, user_id: user.id.to_s).limit(1) + existing_query = Database::Query.where(url: new_url, user_id: current_user_id).limit(1) if Database.all(Link, existing_query).first? raise App::UnprocessableEntityException.new(@env, { "url" => ["URL already exists"] }) end link.url = new_url - link.slug = SlugService.shorten_url(new_url, user.id.to_s) + link.slug = SlugService.shorten_url(new_url, current_user_id) changeset = Database.update(link) if !changeset.valid? @@ -144,12 +136,11 @@ module App::Controllers end def delete - user = current_user - id = @env.params.url["id"] + id = @env.params.url["id"].to_i64 link = Database.get(Link, id) raise App::NotFoundException.new(@env) if !link - raise App::ForbiddenException.new(@env) if link.user_id != user.id + raise App::ForbiddenException.new(@env) if link.user_id != current_user_id result = Database.raw_exec("DELETE FROM links WHERE id = (?)", link.id) if result.rows_affected == 0 @@ -163,6 +154,10 @@ module App::Controllers @env.get("user").as(User) end + private def current_user_id : Int64 + current_user.id.as(Int64) + end + private def track_click(link_id, client_ip, user_agent_str) source = @env.params.query["utm_source"]? || "Direct" referer = @env.request.headers["Referer"]?.try { |r| begin URI.parse(r).host rescue r end } || source @@ -177,7 +172,7 @@ module App::Controllers end private def pagination_params - limit = (@env.params.query["limit"]? || "100").to_i + limit = (@env.params.query["limit"]? || "100").to_i32 cursor = @env.params.query["cursor"]? {limit, cursor} end @@ -191,7 +186,7 @@ module App::Controllers "data" => items.map { |item| yield item }, "pagination" => { "has_more" => has_more, - "next" => next_cursor + "next_cursor" => next_cursor } }) end diff --git a/app/models/click.cr b/app/models/click.cr index 2b3c8fe..d7311ec 100644 --- a/app/models/click.cr +++ b/app/models/click.cr @@ -3,7 +3,7 @@ require "crecto" module App::Models class Click < Crecto::Model schema :clicks do - field :id, String, primary_key: true + field :id, Int64, primary_key: true field :user_agent, String field :country, String field :browser, String diff --git a/app/models/link.cr b/app/models/link.cr index c0bec23..6b0f4cf 100644 --- a/app/models/link.cr +++ b/app/models/link.cr @@ -6,7 +6,7 @@ require "./user.cr" module App::Models class Link < Crecto::Model schema :links do - field :id, String, primary_key: true + field :id, Int64, primary_key: true field :slug, String field :url, String diff --git a/app/models/user.cr b/app/models/user.cr index 8d24202..cf65212 100644 --- a/app/models/user.cr +++ b/app/models/user.cr @@ -4,7 +4,7 @@ require "crecto" module App::Models class User < Crecto::Model schema :users do - field :id, String, primary_key: true + field :id, Int64, primary_key: true field :name, String field :api_key, String end diff --git a/app/services/cli.cr b/app/services/cli.cr index 4f57e8f..4105ad6 100644 --- a/app/services/cli.cr +++ b/app/services/cli.cr @@ -8,7 +8,6 @@ require "../models/*" module App::Services::Cli def self.create_user(name, api_key = nil) user = App::Models::User.new - user.id = UUID.v4.to_s user.name = name user.api_key = api_key || Random::Secure.urlsafe_base64() diff --git a/app/services/click_tracker.cr b/app/services/click_tracker.cr index d0ef38c..47275f2 100644 --- a/app/services/click_tracker.cr +++ b/app/services/click_tracker.cr @@ -5,7 +5,7 @@ IpLookup.load_mmdb("data/GeoLite2-Country.mmdb") module App::Services class ClickTracker - @@queue = Channel(Tuple(String, String, String, String, String)).new(1000) + @@queue = Channel(Tuple(Int64, String, String, String, String)).new(1000) @@initialized = false def self.init @@ -25,7 +25,6 @@ module App::Services user_agent = user_agent_str != "Unknown" ? UserAgent.new(user_agent_str) : nil click = App::Models::Click.new - click.id = UUID.v4.to_s click.link_id = link_id click.country = country click.user_agent = user_agent_str @@ -45,7 +44,7 @@ module App::Services end end - def self.track(link_id : String, client_ip : String, user_agent : String, source : String, referer : String) + def self.track(link_id : Int64, client_ip : String, user_agent : String, source : String, referer : String) init if !@@initialized @@queue.send({link_id, client_ip, user_agent, source, referer}) diff --git a/app/services/slug.cr b/app/services/slug.cr index 4a89ecb..970510d 100644 --- a/app/services/slug.cr +++ b/app/services/slug.cr @@ -2,7 +2,7 @@ require "digest" require "base64" module App::Services::SlugService - def self.shorten_url(url : String, user_id : String) : String + def self.shorten_url(url : String, user_id : Int64) : String combined = "#{user_id}-#{url}" crc32_hash = Digest::CRC32.digest(combined) base62_encoded = Base64.urlsafe_encode(crc32_hash).strip.tr("-_=", "") diff --git a/scripts/cli.cr b/scripts/cli.cr index f0024d9..519b07e 100644 --- a/scripts/cli.cr +++ b/scripts/cli.cr @@ -1,4 +1,3 @@ -require "uuid" require "option_parser" require "../app/services/cli" diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index 236ef98..416614d 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -1,4 +1,3 @@ -require "uuid" require "file_utils" require "spec-kemal" @@ -24,7 +23,6 @@ end def create_test_user user = App::Models::User.new - user.id = UUID.v4.to_s user.name = "Tester" user.api_key = Random::Secure.urlsafe_base64() @@ -39,8 +37,7 @@ end def create_test_link(user, url) link = App::Models::Link.new - link.id = UUID.v4.to_s - link.slug = App::Services::SlugService.shorten_url(url, user.id.to_s) + link.slug = App::Services::SlugService.shorten_url(url, user.id) link.url = url link.user = user @@ -57,7 +54,6 @@ end def create_test_click(link) click = App::Models::Click.new - click.id = UUID.v4.to_s click.user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:127.0) Gecko/20100101 Firefox/127.0" click.browser = "Firefox" click.os = "Mac OS X" @@ -75,8 +71,8 @@ def create_test_click(link) click end -def get_test_link(link_id) - query = App::Lib::Database::Query.where(id: link_id.as(String)).limit(1) +def get_test_link(link_id: Int64) + query = App::Lib::Database::Query.where(id: link_id).limit(1) link = App::Lib::Database.all(App::Models::Link, query, preload: [:clicks]).first? raise "Link not found" if link.nil? @@ -84,6 +80,6 @@ def get_test_link(link_id) link end -def delete_test_link(link_id) +def delete_test_link(link_id: Int64) App::Lib::Database.raw_exec("DELETE FROM links WHERE id = (?)", link_id) # tempfix: Database.delete does not work end