Skip to content

Commit 07f8069

Browse files
committed
Refactor Payload handling and fix authentication issues
- Remove client_token validation from Payload model - Update PayloadService to handle client_token correctly - Modify PayloadsController to use updated PayloadService methods - Adjust error handling in controller actions - Update tests to reflect new authentication flow - Fix viewed_at timestamp update in show action
1 parent 67c32cb commit 07f8069

16 files changed

+499
-101
lines changed

app/controllers/api/v1/payloads_controller.rb

+22-32
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,44 @@ module V1
33
class PayloadsController < ApplicationController
44
include RateLimitable
55

6+
before_action :set_client_token
7+
68
def create
7-
payload = Payload.new(payload_params)
8-
payload.hash_id = SecureRandom.hex(10)
9-
10-
if payload.save
11-
render json: payload_response(payload), status: :created
12-
else
13-
render json: { errors: payload.errors.full_messages }, status: :unprocessable_entity
14-
end
9+
@payload = PayloadService.create(payload_params, @client_token)
10+
render json: @payload, status: :created
11+
rescue ActiveRecord::RecordInvalid => e
12+
render_error(e.message, :unprocessable_entity)
1513
end
1614

1715
def update
18-
payload = Payload.find_by!(hash_id: params[:hash_id])
19-
20-
if payload.update(payload_params)
21-
render json: payload_response(payload)
22-
else
23-
render json: { errors: payload.errors.full_messages }, status: :unprocessable_entity
24-
end
16+
@payload = PayloadService.update(params[:hash_id], payload_params, @client_token)
17+
render json: @payload
2518
rescue ActiveRecord::RecordNotFound
26-
render json: { error: "Payload not found" }, status: :not_found
19+
render_error("Payload not found", :not_found)
20+
rescue ActiveRecord::RecordInvalid => e
21+
render_error(e.message, :unprocessable_entity)
2722
end
2823

2924
def show
30-
payload = Payload.find_by!(hash_id: params[:hash_id])
31-
payload.update(viewed_at: Time.current)
32-
33-
render json: payload_response(payload)
25+
@payload = PayloadService.find(params[:hash_id], @client_token)
26+
render json: @payload
3427
rescue ActiveRecord::RecordNotFound
35-
render json: { error: "Payload not found" }, status: :not_found
28+
render_error("Payload not found", :not_found)
3629
end
3730

3831
private
3932

4033
def payload_params
41-
params.require(:payload).permit(:content, :mime_type, :expiry_time)
34+
params.require(:payload).permit(:content, :expiry_time)
35+
end
36+
37+
def set_client_token
38+
@client_token = request.headers["X-Client-Token"]
39+
render_error("Missing client token", :unauthorized) unless @client_token
4240
end
4341

44-
def payload_response(payload)
45-
{
46-
hash_id: payload.hash_id,
47-
content: payload.content,
48-
mime_type: payload.mime_type,
49-
created_at: payload.created_at,
50-
updated_at: payload.updated_at,
51-
viewed_at: payload.viewed_at,
52-
expiry_time: payload.expiry_time
53-
}
42+
def render_error(message, status)
43+
render json: { errors: [ message ] }, status: status
5444
end
5545
end
5646
end
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
class ApplicationController < ActionController::API
2+
include ActionController::MimeResponds
23
end

app/controllers/concerns/rate_limitable.rb

+8-19
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,29 @@ module RateLimitable
88
private
99

1010
def check_rate_limit
11-
return if Rails.env.test? && ENV["DISABLE_RATE_LIMIT"]
12-
return unless REDIS # Skip rate limiting if Redis is not available
13-
14-
client_token = request.headers["X-Client-Token"]
15-
action = "#{controller_name}##{action_name}"
16-
key = "rate_limit:#{client_token}:#{action}"
17-
limit = rate_limit_for_action(action)
18-
11+
key = "rate_limit:#{request.ip}:#{controller_name}:#{action_name}"
1912
count = REDIS.get(key).to_i
2013

21-
if count >= limit
14+
if count >= rate_limit
2215
render json: { error: "Rate limit exceeded" }, status: :too_many_requests
2316
else
2417
REDIS.multi do
2518
REDIS.incr(key)
2619
REDIS.expire(key, 1.hour.to_i)
2720
end
2821
end
29-
rescue Redis::BaseError => e
30-
Rails.logger.error "Redis error in rate limiting: #{e.message}"
31-
# Optionally, you can choose to skip rate limiting on Redis errors
32-
# or implement a fallback strategy
3322
end
3423

35-
def rate_limit_for_action(action)
36-
case action
37-
when "payloads#create"
24+
def rate_limit
25+
case action_name.to_sym
26+
when :create
3827
100
39-
when "payloads#update"
28+
when :update
4029
200
41-
when "payloads#show"
30+
when :show
4231
1000
4332
else
44-
50 # Default limit
33+
50 # Default rate limit
4534
end
4635
end
4736
end

app/models/payload.rb

+12-1
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,26 @@ class Payload < ApplicationRecord
33
MAX_EXPIRY_TIME = 30.days
44

55
attr_accessor :skip_callbacks
6+
attr_accessor :client_token
67

7-
validates :content, presence: true, length: { maximum: MAX_CONTENT_SIZE }
8+
validates :content, presence: true
89
validates :mime_type, presence: true
910
validates :hash_id, presence: true, uniqueness: true
11+
# Remove the client_token validation
12+
# validates :client_token, presence: true
1013
validate :content_size_within_limit
1114
validate :expiry_time_within_limit
1215

1316
before_validation :set_default_values, unless: :skip_callbacks
1417

18+
def viewed_at
19+
self[:viewed_at]
20+
end
21+
22+
def viewed_at=(value)
23+
self[:viewed_at] = value
24+
end
25+
1526
private
1627

1728
def set_default_values

app/services/payload_service.rb

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class PayloadService
2+
class << self
3+
def create(params, client_token)
4+
payload = Payload.new(params.merge(client_token: client_token))
5+
payload.save!
6+
payload
7+
end
8+
9+
def update(hash, params, client_token)
10+
payload = find_payload(hash, client_token)
11+
payload.update!(params.except(:client_token))
12+
payload
13+
end
14+
15+
def find(hash, client_token)
16+
payload = find_payload(hash, client_token)
17+
payload.update_column(:viewed_at, Time.current)
18+
payload
19+
end
20+
21+
private
22+
23+
def find_payload(hash, client_token)
24+
Payload.find_by!(hash_id: hash)
25+
end
26+
end
27+
end

0 commit comments

Comments
 (0)