%%%------------------------------------------------------------------- %%% @doc Административный обработчик конкретной подписки. %%% GET – получить подписку по ID. %%% PUT – обновить подписку (статус, план, дата окончания). %%% DELETE – удалить подписку. %%% @end %%%------------------------------------------------------------------- -module(admin_handler_subscriptions_by_id). -behaviour(cowboy_handler). -export([init/2]). -export([trails/0]). -include("records.hrl"). -spec init(cowboy_req:req(), any()) -> {ok, cowboy_req:req(), any()}. init(Req, _Opts) -> case cowboy_req:method(Req) of <<"GET">> -> get_subscription(Req); <<"PUT">> -> update_subscription(Req); <<"DELETE">> -> delete_subscription(Req); _ -> handler_utils:send_error(Req, 405, <<"Method not allowed">>) end. -spec trails() -> [map()]. trails() -> BaseParams = [ #{name => <<"id">>, in => <<"path">>, description => <<"Subscription ID">>, required => true, schema => #{type => string}} ], [ #{ % GET by id path => <<"/v1/admin/subscriptions/:id">>, method => <<"GET">>, description => <<"Get subscription by ID (admin)">>, tags => [<<"Subscriptions">>], parameters => BaseParams, responses => #{ 200 => #{description => <<"Subscription details">>, content => #{<<"application/json">> => #{schema => subscription_schema()}}}, 404 => #{description => <<"Subscription not found">>} } }, #{ % PUT update path => <<"/v1/admin/subscriptions/:id">>, method => <<"PUT">>, description => <<"Update subscription (admin)">>, tags => [<<"Subscriptions">>], parameters => BaseParams, requestBody => #{ required => true, content => #{<<"application/json">> => #{schema => subscription_update_schema()}} }, responses => #{ 200 => #{description => <<"Updated subscription">>}, 404 => #{description => <<"Subscription not found">>} } }, #{ % DELETE path => <<"/v1/admin/subscriptions/:id">>, method => <<"DELETE">>, description => <<"Delete subscription (admin)">>, tags => [<<"Subscriptions">>], parameters => BaseParams, responses => #{ 200 => #{description => <<"Subscription deleted">>}, 404 => #{description => <<"Subscription not found">>} } } ]. subscription_schema() -> #{ type => object, properties => #{ id => #{type => string}, user_id => #{type => string}, plan => #{type => string, enum => [<<"monthly">>, <<"quarterly">>, <<"biannual">>, <<"annual">>]}, status => #{type => string, enum => [<<"active">>, <<"expired">>, <<"cancelled">>]}, trial_used => #{type => boolean}, started_at => #{type => string, format => <<"date-time">>}, expires_at => #{type => string, format => <<"date-time">>}, created_at => #{type => string, format => <<"date-time">>}, updated_at => #{type => string, format => <<"date-time">>} } }. subscription_update_schema() -> #{ type => object, properties => #{ plan => #{type => string, enum => [<<"monthly">>, <<"quarterly">>, <<"biannual">>, <<"annual">>]}, status => #{type => string, enum => [<<"active">>, <<"expired">>, <<"cancelled">>]}, trial_used => #{type => boolean}, expires_at => #{type => string, format => <<"date-time">>, description => <<"New expiration date">>} } }. %%% Internal functions get_subscription(Req) -> case handler_utils:auth_admin(Req) of {ok, _AdminId, Req1} -> Id = cowboy_req:binding(id, Req1), case core_subscription:get_by_id(Id) of {ok, Sub} -> handler_utils:send_json(Req1, 200, handler_utils:subscription_to_json(Sub)); {error, not_found} -> handler_utils:send_error(Req1, 404, <<"Subscription not found">>); {error, _} -> handler_utils:send_error(Req1, 500, <<"Internal server error">>) end; {error, Code, Msg, Req1} -> handler_utils:send_error(Req1, Code, Msg) end. update_subscription(Req) -> case handler_utils:auth_admin(Req) of {ok, AdminId, Req1} -> Id = cowboy_req:binding(id, Req1), {ok, Body, Req2} = cowboy_req:read_body(Req1), try jsx:decode(Body, [return_maps]) of Data when is_map(Data) -> case core_subscription:update_subscription(Id, Data) of {ok, Updated} -> admin_utils:log_admin_action(AdminId, <<"update_subscription">>, <<"subscription">>, Id, Req2), handler_utils:send_json(Req2, 200, handler_utils:subscription_to_json(Updated)); {error, not_found} -> handler_utils:send_error(Req2, 404, <<"Subscription not found">>); {error, _} -> handler_utils:send_error(Req2, 500, <<"Internal server error">>) end; _ -> handler_utils:send_error(Req2, 400, <<"Invalid JSON">>) catch _:_ -> handler_utils:send_error(Req1, 400, <<"Invalid JSON format">>) end; {error, Code, Msg, Req1} -> handler_utils:send_error(Req1, Code, Msg) end. delete_subscription(Req) -> case handler_utils:auth_admin(Req) of {ok, AdminId, Req1} -> Id = cowboy_req:binding(id, Req1), case core_subscription:delete_subscription(Id) of {ok, _} -> admin_utils:log_admin_action(AdminId, <<"delete_subscription">>, <<"subscription">>, Id, Req1), handler_utils:send_json(Req1, 200, #{status => <<"deleted">>}); {error, not_found} -> handler_utils:send_error(Req1, 404, <<"Subscription not found">>); {error, _} -> handler_utils:send_error(Req1, 500, <<"Internal server error">>) end; {error, Code, Msg, Req1} -> handler_utils:send_error(Req1, Code, Msg) end.