Commits

Anonymous committed 3d604ed Merge

merge

Comments (0)

Files changed (3)

+%% This file is provided to you under the Apache License,
+%% Version 2.0 (the "License"); you may not use this file
+%% except in compliance with the License.  You may obtain
+%% a copy of the License at
+
+%%   http://www.apache.org/licenses/LICENSE-2.0
+
+%% Unless required by applicable law or agreed to in writing,
+%% software distributed under the License is distributed on an
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+%% KIND, either express or implied.  See the License for the
+%% specific language governing permissions and limitations
+%% under the License.    
+
+%% wildcard for specifying "any field" in
+%% allowed_fields, read_mask, and write_mask
+%% of Jiak bucket schema
+-define(JIAK_SCHEMA_WILDCARD, <<"*">>).

src/jiak_resource.erl

 
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("webmachine/include/webmachine.hrl").
+-include("jiak.hrl").
 
 %% @type key() = container|schema|riak_object:key()
 
                 Mod = jiak_default:new([]),
                 {true, Context#ctx{module=Mod, key=schema}};
             _ ->
-                case jiak_util:get_jiak_module(ReqData) of
-                    undefined -> {false, Context#ctx{module=no_module_found}};
-                    Module -> {true, Context#ctx{module=Module}}
-                end
+                Mod = jiak_util:get_jiak_module(ReqData),
+                {true, Context#ctx{module=Mod}}
         end,
     {ServiceAvailable, ReqData, NewCtx};
 service_available(ReqData, Context) ->
-    {ServiceAvailable, NewCtx} = 
-        case jiak_util:get_jiak_module(ReqData) of
-            undefined -> {false, Context#ctx{module=no_module_found}};
-            Module -> {true, Context#ctx{module=Module}}
-        end,
-    {ServiceAvailable, ReqData, NewCtx}.
+    Mod = jiak_util:get_jiak_module(ReqData),
+    {true, ReqData, Context#ctx{module=Mod}}.
 
 %% @spec allowed_methods(webmachine:wrq(), context()) ->
 %%          {[http_method()], webmachine:wrq(), context()}
 malformed_request(ReqData, Context=#ctx{key=schema}) ->
     case decode_object(wrq:req_body(ReqData)) of
         {ok, _SchemaObj={struct, SchemaPL0}} ->
-            ReqProps = [list_to_binary(atom_to_list(P)) || 
-                           P <- jiak_util:jiak_required_props()],
             case proplists:get_value(<<"schema">>,SchemaPL0) of
                 {struct, SchemaPL} ->
-                    case lists:filter(
-                           fun(I) -> 
-                                   proplists:get_value(I, SchemaPL) =:= undefined
-                           end, 
-                           ReqProps) of
-                        [] ->
-                            {false, ReqData, Context#ctx{incoming=SchemaPL}};
-                        L ->
-                            {true, 
+                    try
+                        AllProps = [{list_to_existing_atom(
+                                       binary_to_list(Prop)), Value}
+                                    || {Prop, Value} <- SchemaPL],
+                        SchemaProps = jiak_util:extract_bucket_props(AllProps),
+                        {false, ReqData, Context#ctx{incoming=SchemaProps}}
+                    catch
+                        error:badarg ->
+                            {true,
                              wrq:append_to_response_body(
-                               io_lib:format("missing required schema fields: ~p~n",[L]),
+                               io_lib:format("some of ~p are not acceptable schema parameters",
+                                             [ K || {K,_} <- SchemaPL ]),
                                ReqData),
                              Context}
                     end;
                                      Context}
                             end;
                         undefined ->
-                            {true, 
-                             wrq:append_to_response_body(
-                               io_lib:format("missing required schema fields: ~p~n",
-                                             [ReqProps]),
+                            {true,
+                             wrq:append_to_respons_body(
+                               "JSON object must contain either"
+                               " a 'schema' field or a 'bucket_mod' field",
                                ReqData),
                              Context}
                     end
 %%      Fields parameter.  Returns 'true' if Obj contains only
 %%      fields named by Fields, 'false' if Obj contains any fields
 %%      not named in Fields.
+check_allowed(_Obj, ?JIAK_SCHEMA_WILDCARD) -> true;
 check_allowed(Obj, Fields) ->
     Allowed = sets:from_list(Fields),
     Has = sets:from_list(jiak_object:props(Obj)),
 %%      bucket have been modified.  Returns 'true' if only fields in
 %%      the bucket's write mask were modified, 'false' otherwise.
 check_write_mask(Mod, {PropDiffs,_}) ->
-    WriteMask = Mod:write_mask(),
-    %% XXX should probably use a special atom like 'JAPI_UNDEFINED' for
-    %% non-existant keys produced by the diff.
-    [{Key, OldVal} || {Key, OldVal, _NewVal} <- PropDiffs,
-		      lists:member(Key, WriteMask) =:= false] =:= [].
+    case Mod:write_mask() of
+        ?JIAK_SCHEMA_WILDCARD -> true;
+        WriteMask ->
+            [{Key, OldVal} || {Key, OldVal, _NewVal} <- PropDiffs,
+                              lists:member(Key, WriteMask) =:= false]
+                =:= []
+    end.
 
 %% @spec is_authorized(webmachine:wrq(), context()) ->
 %%          {true|string(), webmachine:wrq(), context()}
 %% @doc Determine whether the request is authorized.  This function
 %%      calls through to the bucket's auth_ok/3 function.
-is_authorized(ReqData, Context=#ctx{bucket={error, no_such_bucket}}) ->
-    {{halt, 404},
-     wrq:append_to_response_body("Unknown bucket.", ReqData),
-     Context};
 is_authorized(ReqData, Context=#ctx{key=Key,jiak_context=JC,module=Mod}) ->
     {Result, RD1, JC1} = Mod:auth_ok(Key, ReqData, JC),
     {Result, RD1, Context#ctx{jiak_context=JC1}}.
 handle_incoming(ReqData, Context=#ctx{key=schema, 
                                       bucket=Bucket,
                                       incoming=SchemaPL}) ->
-    SchemaProps = [{list_to_atom(binary_to_list(K)), V} || {K,V} <- SchemaPL],
-    ok = riak_bucket:set_bucket(Bucket, SchemaProps),
-    {<<>>, ReqData, Context};
+    ok = riak_bucket:set_bucket(Bucket, SchemaPL),
+    {true, ReqData, Context};
 handle_incoming(ReqData, Context=#ctx{bucket=Bucket,key=Key,
                                       jiak_context=JCTX,jiak_name=JiakName,
                                       jiak_client=JiakClient,
     jiak_object:set_object(JiakObject, {struct, NewData}).
 
 %% @private
+apply_read_mask1(Props, ?JIAK_SCHEMA_WILDCARD, []) ->
+    Props;
 apply_read_mask1([], _ReadMask, Acc) ->
     lists:reverse(Acc);
 apply_read_mask1([{K,_V}=H|T], ReadMask, Acc) ->
 %%      read mask, it can't preserve their values, so we have to do it
 %%      for them.
 copy_unreadable_props(Mod, OldObj, NewObj) ->
-    Allowed = Mod:allowed_fields(),
-    ReadMask = Mod:read_mask(),
-    Unreadable = sets:to_list(sets:subtract(
-				sets:from_list(Allowed),
-				sets:from_list(ReadMask))),
-    {struct, OldData} = jiak_object:object(OldObj),
-    {struct, NewData} = jiak_object:object(NewObj),
-    UnreadableData = copy_unreadable1(Unreadable, OldData, NewData),
-    jiak_object:set_object(NewObj, {struct, UnreadableData}).
+    case Mod:read_mask() of
+        ?JIAK_SCHEMA_WILDCARD ->
+            NewObj; %% nothing is unreadable
+        ReadMask ->
+            Allowed = case Mod:allowed_fields() of
+                          ?JIAK_SCHEMA_WILDCARD ->
+                              %% anything might be unreadable
+                              jiak_object:props(OldObj);
+                          AllowedFields ->
+                              AllowedFields
+                      end,
+            Unreadable = sets:to_list(sets:subtract(
+                                        sets:from_list(Allowed),
+                                        sets:from_list(ReadMask))),
+            {struct, OldData} = jiak_object:object(OldObj),
+            {struct, NewData} = jiak_object:object(NewObj),
+            UnreadableData = copy_unreadable1(Unreadable, OldData, NewData),
+            jiak_object:set_object(NewObj, {struct, UnreadableData})
+    end.
 
 %% @private    
 copy_unreadable1([], _OldObj, NewObj) ->

src/jiak_util.erl

 
 %% @doc Utilities for jiak_resource and jiak_object.
 -module(jiak_util).
--export([jiak_required_props/0,
+-export([jiak_default_props/0,
          jiak_module_for_bucket/1, 
+         extract_bucket_props/1,
          get_jiak_module/1, 
          bucket_from_reqdata/1]).
 
 -include_lib("eunit/include/eunit.hrl").
+-include("jiak.hrl").
 
 %% @private
-jiak_required_props() -> [allowed_fields,required_fields,read_mask,write_mask].
+jiak_default_props() ->
+    [{allowed_fields, ?JIAK_SCHEMA_WILDCARD},
+     {required_fields, []},
+     {read_mask, ?JIAK_SCHEMA_WILDCARD},
+     {write_mask, ?JIAK_SCHEMA_WILDCARD}].
 
 %% @private
 jiak_module_for_bucket(BucketName) when is_binary(BucketName) ->
         {bucket_mod, Module} when Module /= undefined ->
             Module;
         _ ->
-            case bucket_props_defined(BucketProps) of
-                true ->
-                    jiak_default:new(BucketProps);
-                false ->
-                    undefined
-            end
+            jiak_default:new(
+              extract_bucket_props(BucketProps))
     end.
 
-bucket_props_defined(BucketProps) ->
-    [] == lists:filter(
-            fun(I) -> 
-                    proplists:get_value(I, BucketProps) =:= undefined
-            end, 
-            jiak_required_props()).
+extract_bucket_props(BucketProps) ->
+    [ {Prop, proplists:get_value(Prop, BucketProps, Default)}
+      || {Prop, Default} <- jiak_default_props() ].
 
 %% @private
 get_jiak_module(ReqData) ->