/__w/shurbej/shurbej/_build/test/cover/ct/shurbej_http_searches.html

1 -module(shurbej_http_searches).
2 -include_lib("shurbej_store/include/shurbej_records.hrl").
3
4 -export([init/2]).
5
6 init(Req0, State) ->
7 16 case shurbej_http_common:authorize(Req0) of
8 {ok, LibRef, _} ->
9 15 Method = cowboy_req:method(Req0),
10 15 Perm = perm_for_method(Method),
11 15 case shurbej_http_common:check_lib_perm(Perm, LibRef) of
12 {error, forbidden} ->
13
:-(
Req = shurbej_http_common:error_response(403, <<"Access denied">>, Req0),
14
:-(
{ok, Req, State};
15 ok ->
16 15 handle(Method, Req0, State)
17 end;
18 {error, Reason, _} ->
19 1 Req = shurbej_http_common:auth_error_response(Reason, Req0),
20 1 {ok, Req, State}
21 end.
22
23 6 perm_for_method(<<"GET">>) -> read;
24
:-(
perm_for_method(<<"HEAD">>) -> read;
25 9 perm_for_method(_) -> write.
26
27 handle(<<"GET">>, Req0, State) ->
28 6 LibRef = shurbej_http_common:lib_ref(Req0),
29 6 Since = shurbej_http_common:get_since(Req0),
30 6 {ok, LibVersion} = shurbej_version:get(LibRef),
31 6 case shurbej_http_common:get_if_modified(Req0) of
32 V when is_integer(V), V >= LibVersion ->
33
:-(
Req = cowboy_req:reply(304, #{
34 <<"last-modified-version">> => integer_to_binary(LibVersion)
35 }, Req0),
36
:-(
{ok, Req, State};
37 _ ->
38 6 Searches0 = shurbej_db:list_searches(LibRef, Since),
39 6 Searches = shurbej_http_common:filter_by_keys(Searches0,
40 shurbej_http_common:get_search_keys(Req0)),
41 6 Format = shurbej_http_common:get_format(Req0),
42 6 case Format of
43 <<"versions">> ->
44 2 Pairs = shurbej_db:list_search_versions(LibRef, Since),
45 2 Req = shurbej_http_common:json_response(200, maps:from_list(Pairs), LibVersion, Req0),
46 2 {ok, Req, State};
47 <<"keys">> ->
48 1 Keys = [K || #shurbej_search{id = {_, _, K}} <- Searches],
49 1 Req = shurbej_http_common:json_response(200, Keys, LibVersion, Req0),
50 1 {ok, Req, State};
51 _ ->
52 3 Req = shurbej_http_common:list_response(Req0, Searches, LibVersion,
53 4 fun(S) -> shurbej_http_common:envelope_search(LibRef, S) end),
54 3 {ok, Req, State}
55 end
56 end;
57
58 %% PUT/PATCH single search
59 handle(Method, Req0, #{scope := single} = State) when Method =:= <<"PUT">>; Method =:= <<"PATCH">> ->
60 1 {LT, LI} = LibRef = shurbej_http_common:lib_ref(Req0),
61 1 SearchKey = cowboy_req:binding(search_key, Req0),
62 1 ExpectedVersion = shurbej_http_common:get_if_unmodified(Req0),
63 1 case shurbej_http_common:read_json_body(Req0) of
64 {error, _, Req1} ->
65
:-(
Req = shurbej_http_common:error_response(400, <<"Invalid JSON">>, Req1),
66
:-(
{ok, Req, State};
67 {ok, Incoming, Req1} ->
68 1 case shurbej_db:get_search(LibRef, SearchKey) of
69 undefined ->
70
:-(
Req = shurbej_http_common:error_response(404, <<"Search not found">>, Req1),
71
:-(
{ok, Req, State};
72 {ok, #shurbej_search{data = Existing}} ->
73 1 Merged = case Method of
74 1 <<"PATCH">> -> maps:merge(Existing, Incoming);
75
:-(
<<"PUT">> -> Incoming
76 end,
77 1 Search = Merged#{<<"key">> => SearchKey},
78 1 case shurbej_validate:search(Search) of
79 {error, Reason} ->
80
:-(
Req = shurbej_http_common:error_response(400, Reason, Req1),
81
:-(
{ok, Req, State};
82 ok ->
83 1 case shurbej_version:write(LibRef, ExpectedVersion, fun(NewVersion) ->
84 1 FullData = Search#{<<"version">> => NewVersion},
85 1 shurbej_db:write_search(#shurbej_search{
86 id = {LT, LI, SearchKey}, version = NewVersion,
87 data = FullData, deleted = false
88 })
89 end) of
90 {ok, NewVersion} ->
91 1 FullData = Search#{<<"version">> => NewVersion, <<"key">> => SearchKey},
92 1 Updated = #shurbej_search{
93 id = {LT, LI, SearchKey}, version = NewVersion,
94 data = FullData, deleted = false
95 },
96 1 Envelope = shurbej_http_common:envelope_search(LibRef, Updated),
97 1 Req = shurbej_http_common:json_response(200, Envelope, NewVersion, Req1),
98 1 {ok, Req, State};
99 {error, precondition, CurrentVersion} ->
100
:-(
Req = shurbej_http_common:json_response(412,
101 #{<<"message">> => <<"Library has been modified since specified version">>},
102 CurrentVersion, Req1),
103
:-(
{ok, Req, State}
104 end
105 end
106 end
107 end;
108
109 handle(<<"POST">>, Req0, State) ->
110 7 {LT, LI} = LibRef = shurbej_http_common:lib_ref(Req0),
111 7 ExpectedVersion = shurbej_http_common:get_if_unmodified(Req0),
112 7 case shurbej_http_common:read_json_body(Req0) of
113 {error, _, Req1} ->
114
:-(
Req = shurbej_http_common:error_response(400, <<"Invalid JSON">>, Req1),
115
:-(
{ok, Req, State};
116 {ok, Searches, Req1} when is_list(Searches) ->
117 7 KeyedSearches = [ensure_key(S) || S <- Searches],
118 7 {Valid, Failed} = shurbej_http_items:validate_each(KeyedSearches, fun shurbej_validate:search/1),
119 7 case Valid of
120 [] when map_size(Failed) > 0 ->
121 1 Result = #{<<"successful">> => #{}, <<"unchanged">> => #{}, <<"failed">> => Failed},
122 1 Req = shurbej_http_common:json_response(400, Result, Req1),
123 1 {ok, Req, State};
124 _ ->
125 6 case shurbej_version:write(LibRef, ExpectedVersion, fun(NewVersion) ->
126 5 lists:foreach(fun({_Idx, S}) ->
127 6 Key = maps:get(<<"key">>, S),
128 6 FullData = S#{<<"key">> => Key, <<"version">> => NewVersion},
129 6 shurbej_db:write_search(#shurbej_search{
130 id = {LT, LI, Key},
131 version = NewVersion,
132 data = FullData,
133 deleted = false
134 })
135 end, Valid),
136 5 ok
137 end) of
138 {ok, NewVersion} ->
139 5 Successful = maps:from_list(
140 6 [{integer_to_binary(Idx), shurbej_http_items:envelope_for_write(LibRef, S, NewVersion)}
141 5 || {Idx, S} <- Valid]),
142 5 Result = #{
143 <<"successful">> => Successful,
144 <<"unchanged">> => #{},
145 <<"failed">> => Failed
146 },
147 5 Req = shurbej_http_common:json_response(200, Result, NewVersion, Req1),
148 5 {ok, Req, State};
149 {error, precondition, CurrentVersion} ->
150 1 Req = shurbej_http_common:json_response(412,
151 #{<<"message">> => <<"Library has been modified since specified version">>},
152 CurrentVersion, Req1),
153 1 {ok, Req, State}
154 end
155 end;
156 {ok, _, Req1} ->
157
:-(
Req = shurbej_http_common:error_response(400, <<"Body must be a JSON array">>, Req1),
158
:-(
{ok, Req, State}
159 end;
160
161 handle(<<"DELETE">>, Req0, State) ->
162 1 LibRef = shurbej_http_common:lib_ref(Req0),
163 1 ExpectedVersion = shurbej_http_common:get_if_unmodified(Req0),
164 1 #{searchKey := KeysParam} = cowboy_req:match_qs([{searchKey, [], <<>>}], Req0),
165 1 Keys = [K || K <- binary:split(KeysParam, <<",">>, [global]), K =/= <<>>],
166 1 case Keys of
167 [] ->
168
:-(
Req = shurbej_http_common:error_response(400,
169 <<"No search keys specified">>, Req0),
170
:-(
{ok, Req, State};
171 _ ->
172 1 case shurbej_version:write(LibRef, ExpectedVersion, fun(NewVersion) ->
173 1 lists:foreach(fun(K) ->
174 1 shurbej_db:mark_search_deleted(LibRef, K, NewVersion),
175 1 shurbej_db:record_deletion(LibRef, <<"search">>, K, NewVersion)
176 end, Keys),
177 1 ok
178 end) of
179 {ok, NewVersion} ->
180 1 Req = cowboy_req:reply(204, #{
181 <<"last-modified-version">> => integer_to_binary(NewVersion)
182 }, Req0),
183 1 {ok, Req, State};
184 {error, precondition, CurrentVersion} ->
185
:-(
Req = shurbej_http_common:json_response(412,
186 #{<<"message">> => <<"Library has been modified since specified version">>},
187 CurrentVersion, Req0),
188
:-(
{ok, Req, State}
189 end
190 end;
191
192 handle(_, Req0, State) ->
193
:-(
Req = shurbej_http_common:error_response(405, <<"Method not allowed">>, Req0),
194
:-(
{ok, Req, State}.
195
196 ensure_key(Item) ->
197 8 case maps:get(<<"key">>, Item, undefined) of
198 8 undefined -> Item#{<<"key">> => shurbej_http_items:generate_key()};
199
:-(
_ -> Item
200 end.
Line Hits Source