feat(specialists): owner is non-deletable specialist on commercial create
Bootstrap calendar_specialist for owner (active); DELETE owner → 403; toggle via status. Fixes solo assign-to-slot. Refs EventHub/EventHubBack#66
This commit is contained in:
@@ -187,6 +187,8 @@ remove_specialist(Req) ->
|
||||
handler_utils:send_json(Req1, 200, #{status => <<"deleted">>});
|
||||
{error, not_found} ->
|
||||
handler_utils:send_error(Req1, 404, <<"Not found">>);
|
||||
{error, owner_specialist_protected} ->
|
||||
handler_utils:send_error(Req1, 403, <<"Owner specialist cannot be removed">>);
|
||||
{error, access_denied} ->
|
||||
handler_utils:send_error(Req1, 403, <<"Access denied">>);
|
||||
{error, not_commercial} ->
|
||||
|
||||
@@ -46,7 +46,18 @@ create_calendar(UserId, Title, Description, Confirmation, Type) ->
|
||||
case Result of
|
||||
{ok, Cal} ->
|
||||
logic_automoderation:apply_after_save(calendar, Cal#calendar.id, Action, Words),
|
||||
core_calendar:get_by_id(Cal#calendar.id);
|
||||
case core_calendar:get_by_id(Cal#calendar.id) of
|
||||
{ok, Cal2} = Ok ->
|
||||
case Cal2#calendar.type of
|
||||
commercial ->
|
||||
_ = logic_calendar_specialist:ensure_owner_specialist(Cal2);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
Ok;
|
||||
Error ->
|
||||
Error
|
||||
end;
|
||||
Error ->
|
||||
Error
|
||||
end
|
||||
@@ -118,7 +129,12 @@ convert_or_delete_extra_personal(#calendar{id = Id} = Cal) ->
|
||||
case calendar_has_content(Id) of
|
||||
true ->
|
||||
%% System backfill: bypass subscription gate.
|
||||
_ = core_calendar:update(Id, [{type, commercial}]),
|
||||
case core_calendar:update(Id, [{type, commercial}]) of
|
||||
{ok, Updated} ->
|
||||
_ = logic_calendar_specialist:ensure_owner_specialist(Updated);
|
||||
_ ->
|
||||
ok
|
||||
end,
|
||||
ok;
|
||||
false ->
|
||||
_ = core_calendar:delete(Id),
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
-module(logic_calendar_specialist).
|
||||
-include("records.hrl").
|
||||
|
||||
-export([list/2, add/5, update/4, remove/3, to_json/1]).
|
||||
-export([list/2, add/5, update/4, remove/3, to_json/1, ensure_owner_specialist/1]).
|
||||
|
||||
-spec list(ActorId :: binary(), CalendarId :: binary()) ->
|
||||
{ok, [#calendar_specialist{}]} | {error, not_found | access_denied}.
|
||||
@@ -47,14 +47,34 @@ update(OwnerId, CalendarId, UserId, Updates) ->
|
||||
end.
|
||||
|
||||
-spec remove(OwnerId :: binary(), CalendarId :: binary(), UserId :: binary()) ->
|
||||
ok | {error, not_found | access_denied | not_commercial | term()}.
|
||||
ok | {error, not_found | access_denied | not_commercial |
|
||||
owner_specialist_protected | term()}.
|
||||
remove(OwnerId, CalendarId, UserId) ->
|
||||
case require_owner_commercial(OwnerId, CalendarId) of
|
||||
{ok, #calendar{owner_id = CalOwnerId}} when UserId =:= CalOwnerId ->
|
||||
{error, owner_specialist_protected};
|
||||
{ok, _} ->
|
||||
core_calendar_specialist:delete(CalendarId, UserId);
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
%% @doc Idempotent: commercial calendar always has a specialist row for owner.
|
||||
%% Default status=active; name from nickname (else email). No-op if already present.
|
||||
-spec ensure_owner_specialist(#calendar{}) -> ok | {error, term()}.
|
||||
ensure_owner_specialist(#calendar{id = CalId, owner_id = OwnerId, type = commercial}) ->
|
||||
case core_calendar_specialist:get_by_calendar_and_user(CalId, OwnerId) of
|
||||
{ok, _} ->
|
||||
ok;
|
||||
{error, not_found} ->
|
||||
case core_calendar_specialist:create(CalId, OwnerId, owner_display_name(OwnerId), []) of
|
||||
{ok, _} -> ok;
|
||||
{error, already_exists} -> ok;
|
||||
{error, _} = Err -> Err
|
||||
end
|
||||
end;
|
||||
ensure_owner_specialist(_) ->
|
||||
ok.
|
||||
|
||||
-spec to_json(#calendar_specialist{}) -> map().
|
||||
to_json(S) ->
|
||||
#{
|
||||
@@ -82,3 +102,13 @@ require_owner_commercial(OwnerId, CalendarId) ->
|
||||
{error, access_denied};
|
||||
Error -> Error
|
||||
end.
|
||||
|
||||
owner_display_name(OwnerId) ->
|
||||
case core_user:get_by_id(OwnerId) of
|
||||
{ok, #user{nickname = Nick}} when is_binary(Nick), Nick =/= <<>> ->
|
||||
Nick;
|
||||
{ok, #user{email = Email}} when is_binary(Email), Email =/= <<>> ->
|
||||
Email;
|
||||
_ ->
|
||||
<<"Owner">>
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user