davisp commented on a change in pull request #2666: soft-deletion for database
URL: https://github.com/apache/couchdb/pull/2666#discussion_r400295708
 
 

 ##########
 File path: src/chttpd/src/chttpd_misc.erl
 ##########
 @@ -146,6 +147,143 @@ handle_all_dbs_req(#httpd{method='GET'}=Req) ->
 handle_all_dbs_req(Req) ->
     send_method_not_allowed(Req, "GET,HEAD").
 
+handle_deleted_dbs_req(#httpd{path_parts=[<<"_deleted_dbs">>]}=Req) ->
+    deleted_dbs_req(Req);
+handle_deleted_dbs_req(#httpd{path_parts=[<<"_deleted_dbs">>, DbName]}=Req) ->
+    deleted_dbs_info_req(Req, DbName);
+handle_deleted_dbs_req(Req) ->
+    chttpd:send_error(Req, not_found).
+
+deleted_dbs_req(#httpd{method='GET'}=Req) ->
+    #mrargs{
+        start_key = StartKey,
+        end_key = EndKey,
+        direction = Dir,
+        limit = Limit,
+        skip = Skip
+    } = couch_mrview_http:parse_params(Req, undefined),
+
+    Options = [
+        {start_key, StartKey},
+        {end_key, EndKey},
+        {dir, Dir},
+        {limit, Limit},
+        {skip, Skip}
+    ],
+
+    % Eventually the Etag for this request will be derived
+    % from the \xFFmetadataVersion key in fdb
+    Etag = <<"foo">>,
+
+    {ok, Resp} = chttpd:etag_respond(Req, Etag, fun() ->
+        {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, 
[{"ETag",Etag}]),
+        Callback = fun all_dbs_callback/2,
+        Acc = #vacc{req=Req,resp=Resp},
+        fabric2_db:list_deleted_dbs(Callback, Acc, Options)
+    end),
+    case is_record(Resp, vacc) of
+        true -> {ok, Resp#vacc.resp};
+        _ -> {ok, Resp}
+    end;
+deleted_dbs_req(#httpd{method='POST'}=Req) ->
+    deleted_dbs_post_req(Req);
+deleted_dbs_req(Req) ->
+    send_method_not_allowed(Req, "GET,POST,HEAD").
+
+deleted_dbs_info_req(#httpd{user_ctx=Ctx}=Req, DbName) ->
+    couch_httpd:verify_is_server_admin(Req),
+    case fabric2_db:deleted_dbs_info(DbName, [{user_ctx, Ctx}]) of
+        {ok, Result} ->
+            {ok, Resp} = chttpd:start_json_response(Req, 200),
+            send_chunk(Resp, "["),
+            lists:foldl(fun({Timestamp, Info}, AccSeparator) ->
+                Json = ?JSON_ENCODE({[
+                    {key, DbName},
+                    {timestamp, Timestamp},
+                    {value, {Info}}
+                ]}),
+                send_chunk(Resp, AccSeparator ++ Json),
+                "," % AccSeparator now has a comma
+            end, "", Result),
+            send_chunk(Resp, "]"),
+            chttpd:end_json_response(Resp);
+        Error ->
+            throw(Error)
+    end;
+deleted_dbs_info_req(Req, _DbName) ->
+    send_method_not_allowed(Req, "GET,HEAD").
+
+deleted_dbs_post_req(#httpd{user_ctx=Ctx}=Req) ->
+    couch_httpd:verify_is_server_admin(Req),
+    chttpd:validate_ctype(Req, "application/json"),
+    {JsonProps} = chttpd:json_body_obj(Req),
+    UndeleteJson0 = couch_util:get_value(<<"undelete">>, JsonProps, undefined),
+    DeleteJson0 = couch_util:get_value(<<"delete">>, JsonProps, undefined),
+    case {UndeleteJson0, DeleteJson0}  of
+        {undefined, undefined} ->
+            throw({bad_request, <<"POST body must include `undeleted` "
+                "or `delete` parameter.">>});
+        {UndeleteJson, undefined} ->
+            handle_undelete_db_req(Req, UndeleteJson);
+        {undefined, DeleteJson} ->
+            handle_delete_deleted_req(Req, DeleteJson);
+        {_Else, _Else} ->
+            throw({bad_request,
+                <<"`undeleted` and `delete` are mutually exclusive">>})
+    end.
+
+handle_undelete_db_req(#httpd{user_ctx=Ctx}=Req, {JsonProps}) ->
+    DbName = case couch_util:get_value(<<"source">>, JsonProps) of
+        undefined ->
+            throw({bad_request,
+                <<"POST body must include `source` parameter.">>});
+        DbName0 ->
+            DbName0
+    end,
+    TimeStamp = case couch_util:get_value(<<"source_timestamp">>, JsonProps) of
+        undefined ->
+            throw({bad_request,
+                <<"POST body must include `source_timestamp` parameter.">>});
+        TimeStamp0 ->
+            TimeStamp0
+    end,
+    TgtDbName = case couch_util:get_value(<<"target">>, JsonProps) of
+        undefined ->  DbName;
+        TgtDbName0 -> TgtDbName0
+    end,
+    case fabric2_db:undelete(DbName, TgtDbName, TimeStamp, [{user_ctx, Ctx}]) 
of
+        ok ->
+            send_json(Req, 200, {[{ok, true}]});
+        {error, file_exists} ->
+            chttpd:send_error(Req, file_exists);
 
 Review comment:
   Also now that I think harder, these should be exceptions instead of returned 
values. chttpd will catch them and do the proper send_error logic (assuming 
that we match one of the existing error patterns or add any new ones). So 
something like:
   
   ```erlang
   ok = fabric2_db:undelete(DbName, TgtDbName, TimeStamp, [{user_ctx, Ctx}]),
   send_json(Req, 200, {[{ok, true}]}).
   ```

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to