Localizza errori API, sistema layout mobile e documenta allineamento iOS.

Gli header Accept-Language dalle app e i fix di padding/menu sul web chiudono il giro password-policy; il doc guida il lavoro su Mac.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-08 14:14:42 +02:00
co-authored by Cursor
parent dd9901519a
commit 1d1cbf9f3f
25 changed files with 430 additions and 98 deletions
@@ -8,7 +8,7 @@ module Api
def update
name = params[:name].to_s.strip
if name.blank?
return render json: { error: "Name is required" }, status: :unprocessable_entity
return render json: { error: I18n.t("flash.accounts.name_required") }, status: :unprocessable_entity
end
if current_user.update(name: name)
@@ -30,7 +30,7 @@ module Api
return render json: { error: password_error_message(result.error) }, status: :unprocessable_entity
end
render json: { message: "Password updated" }
render json: { message: I18n.t("flash.accounts.password_updated") }
end
private
@@ -46,14 +46,13 @@ module Api
def password_error_message(code)
case code
when :current_incorrect then "Current password is incorrect"
when :too_short then "Password must be at least 8 characters"
when :too_long then "Password cannot exceed 72 characters"
when :too_weak
"Password must include at least 3 of: lowercase, uppercase, number, symbol"
when :same_as_current then "New password must be different from the current password"
when :mismatch then "Passwords do not match"
else "Unable to update password"
when :current_incorrect then I18n.t("flash.accounts.password_current_incorrect")
when :too_short then I18n.t("flash.accounts.password_too_short")
when :too_long then I18n.t("flash.accounts.password_too_long")
when :too_weak then I18n.t("flash.accounts.password_too_weak")
when :same_as_current then I18n.t("flash.accounts.password_same_as_current")
when :mismatch then I18n.t("flash.accounts.password_mismatch")
else I18n.t("flash.accounts.password_update_failed")
end
end
end
@@ -22,18 +22,18 @@ module Api
if user&.authenticate(params[:password])
render json: token_response(user), status: :ok
else
render json: { error: "Invalid credentials" }, status: :unauthorized
render json: { error: I18n.t("flash.sessions.invalid_credentials") }, status: :unauthorized
end
end
def logout
render json: { message: "Logged out" }
render json: { message: I18n.t("flash.sessions.logged_out") }
end
def refresh
payload = JsonWebToken.decode(params[:refresh_token] || bearer_token)
user = User.find_by(id: payload&.dig(:user_id))
return render json: { error: "Invalid token" }, status: :unauthorized unless user
return render json: { error: I18n.t("flash.sessions.invalid_token") }, status: :unauthorized unless user
render json: token_response(user)
end
@@ -45,7 +45,7 @@ module Api
def forgot_password
Users::RequestPasswordReset.call(email: params[:email])
render json: {
message: "If the email is registered, you will receive a password reset link shortly."
message: I18n.t("flash.password_resets.email_sent")
}
end
@@ -1,17 +1,25 @@
class ApplicationController < ActionController::API
include ActionController::HttpAuthentication::Token::ControllerMethods
before_action :set_api_locale
before_action :authenticate_request!
attr_reader :current_user
private
def set_api_locale
explicit = LocaleResolver.normalize(request.headers["X-Locale"])
I18n.locale = explicit ||
LocaleResolver.from_accept_language(request.headers["Accept-Language"]) ||
I18n.default_locale
end
def authenticate_request!
token = bearer_token
payload = JsonWebToken.decode(token)
@current_user = User.find_by(id: payload[:user_id]) if payload
render json: { error: "Unauthorized" }, status: :unauthorized unless @current_user
render json: { error: I18n.t("flash.sessions.unauthorized") }, status: :unauthorized unless @current_user
end
def bearer_token
@@ -29,8 +29,8 @@ module Public
)
unless result.ok?
flash.now[:alert] = t("flash.accounts.password_#{result.error}")
return render :show, status: :unprocessable_entity
redirect_to public_account_path, alert: t("flash.accounts.password_#{result.error}")
return
end
redirect_to public_account_path, notice: t("flash.accounts.password_updated")
@@ -13,7 +13,7 @@ module Public
def edit
@user = User.find_by_password_reset_token(params[:token])
if @user.nil? || @user.password_reset_expired?
redirect_to new_public_password_reset_path,
redirect_to public_password_forgot_path,
alert: t("flash.password_resets.invalid_or_expired_link")
return
end
@@ -23,7 +23,7 @@ module Public
def update
@user = User.find_by_password_reset_token(params[:token])
if @user.nil? || @user.password_reset_expired?
redirect_to new_public_password_reset_path,
redirect_to public_password_forgot_path,
alert: t("flash.password_resets.invalid_or_expired_link")
return
end