<commit_before>%% 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.    

%% @doc jiak_resource provides access to Jiak objects over HTTP.
%%      Resources are provided at URIs shaped like:
%%        ```http://host/JiakBase/Bucket/Key'''
%%      That is, an object stored in the Riak bucket "Bucket" at key
%%      "Key" would be available at the path Bucket/Key, relative to
%%      jiak_resource's base path.
%%
%%      jiak_resource should be added to a Webmachine dispatch with
%%      two lines, one for bucket-targetted requests, the other for
%%      item-targetted requests:
%%<pre>
%%      {[JiakBase,bucket], jiak_resource,
%%       [{key_type, container}|Options]}.
%%      {[JiakBase,bucket,key], jiak_resource,
%%       [{key_type, item}|Options]}.
%%</pre>
%%
%%      Dispatch Configuration Options:
%%<dl><dt>  {jiak_name, string()}: (Required)
%%</dt><dd>   base path for jiak_resource
%%</dd><dt> {key_type, item|container}: (Required)
%%</dt><dd>   set to 'item' when the request path targets a specific
%%            object, or to 'container' when it targets a whole bucket
%%</dd><dt> {riak_local, boolean()}: (Optional)
%%</dt><dd>   set to 'true' to use jiak:local_client/0, otherwise
%%            jiak:client_connect/3 will be used
%%</dd><dt> {riak_ip, string()}: (Required if riak_local = false)
%%</dt><dd>   IP of the riak cluster, passed to jiak:client_connect/3
%%</dd><dt> {riak_port, integer()}: (Required if riak_local = false)
%%</dt><dd>   Port of the riak cluster, passed to jiak:client_connect/3
%%</dd><dt> {riak_cookie, atom()}: (Required if riak_local = false)
%%</dt><dd>   Cookie of the riak cluster, passd to jiak:client_connect/3
%%</dd></dl>
%%
%%      HTTP Query Parameters:
%%<dl><dt>  schema
%%</dt><dd>   allowed values: true (default), false
%%            when GETting a bucket, set schema=false if you do not
%%            want the schema included in the response
%%</dd><dt> keys
%%</dt><dd>   allowed values: true (default), false
%%            when GETting a bucket, set keys=false if you do not want
%%            the keylist included in the response
%%</dd><dt> returnbody
%%</dt><dd>   allowed values: true, false (default)
%%            when PUTting or POSTing an object, set returnbody=true
%%            if you want the response to included the updated object
%%            (saves the roundtrip for a subsequent GET), the response
%%            will be 204 No Content, otherwise
%%</dd><dt> r
%%</dt><dd>   specify the Riak R value for get operations
%%</dd><dt> w
%%</dt><dd>   specify the Riak W value for put operations
%%</dd><dt> dw
%%</dt><dd>   specify the Riak DW value for put operations
%%</dd><dt> rw
%%</dt><dd>   specify the Riak RW value for delete operations
%%</dd></dl>
%%
%%      HTTP Usage:
%%<dl><dt> GET /JiakBase/Bucket
%%</dt><dd>  If the bucket is listable, returns a JSON object
%%           of the form:
%%           {
%%            "schema":{
%%                      "allowed_fields":["FieldName1","FieldName2",...],
%%                      "required_fields":["FieldName1",...],
%%                      "write_mask":["FieldName1",...],
%%                      "read_mask":["FieldName1",...]
%%                     },
%%            "keys":["Key1","Key2",...]
%%           }
%%           Each element of the "schema" lists some fo the field names
%%           defined for objects of the requested bucket.
%%<dl><dt>     allowed_fields
%%</dt><dd>      Objects may only include the fields listed here
%%</dd><dt>    required_fields
%%</dt><dd>      Objects must have fields listed here
%%</dd><dt>    write_mask
%%</dt><dd>      Clients may change only the fields listed here
%%</dd><dt>    read_mask
%%</dt><dd>      Clients will see only the contents of fields listed here
%%</dd></dl>
%%
%%</dd><dt> GET /JiakBase/Bucket/Key
%%</dt><dd>   If the object exists, and access is permitted, returns
%%            the object JSON-encoded
%%
%%</dd><dt> PUT /JiakBase/Bucket/Key
%%</dt><dd>   Store the object in the request body in the given Bucket at
%%            the given Key.  The "bucket" and "key" fields in the object
%%            must match the Bucket and Key components of the URI.
%%
%%</dd><dt> POST /JiakBase/Bucket
%%</dt><dd>   Store the object in the request body in the given Bucket at
%%            a new, server-generated key.  Response will be empty (unless
%%            returnbody=true is specified in the query parameters) with
%%            the Location header set to the new object's URI.
%%
%%</dd><dt> PUT /JiakBase/Bucket
%%</dt><dd>   Create or update the schema for a bucket.  The request body 
%%            must be a JSON object of the form:
%%            {"schema":{
%%                      "allowed_fields":["FieldName1","FieldName2",...],
%%                      "required_fields":["FieldName1",...],
%%                      "write_mask":["FieldName1",...],
%%                      "read_mask":["FieldName1",...]
%%                     }
%%            }
%%</dd></dl>
-module(jiak_resource).

-export([init/1,
         service_available/2,
         allowed_methods/2,
         resource_exists/2,
         is_authorized/2,
         content_types_provided/2,
         content_types_accepted/2,
         encodings_provided/2,
         post_is_create/2,
         create_path/2,
         handle_incoming/2,
         produce_body/2,
         delete_resource/2,
         malformed_request/2,
         forbidden/2,
	 last_modified/2,
	 generate_etag/2,
	 expires/2,
         apply_read_mask/1,
         pretty_print/2]).

%% @type context() = term()
%% @type jiak_module() = atom()|{jiak_default, list()}
-record(ctx, {bucket,       %% binary() - Bucket name (from uri)
              key,          %% binary()|container|schema - Key (or sentinal
                            %%   meaning "no key provided")
              module,       %% atom()
              jiak_context, %% jiak_context() - context for the request
              jiak_name,    %% string() - prefix for jiak uris
              jiak_client,  %% jiak_client() - the store client
              etag,         %% string() - ETag header
              bucketkeys,   %% [binary()] - keys in the bucket
              diffs,        %% {[object_diff()],{AddedLinks::[jiak_link()],
                            %%                   RemovedLinks::[jiak_link()]}
              incoming,     %% jiak_object() - object the client is storing
              storedobj}).  %% jiak_object() - object stored in Riak

-include_lib("eunit/include/eunit.hrl").
-include_lib("webmachine/include/webmachine.hrl").

%% @type key() = container|schema|riak_object:key()

%% @spec init(proplist()) -> {ok, context()}
%% @doc Initialize this webmachine resource.  This function will
%%      attempt to open a client to Riak, and will fail if it is
%%      unable to do so.
init(Props) ->
    {ok, JiakClient} = 
        case proplists:get_value(riak_local, Props) of
            true ->
                jiak:local_client();
            _ ->
                Node = proplists:get_value(riak_node),
                Cookie = proplists:get_value(riak_cookie),<commit_msg>typo: pull props from proplist<commit_after>%% 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.    

%% @doc jiak_resource provides access to Jiak objects over HTTP.
%%      Resources are provided at URIs shaped like:
%%        ```http://host/JiakBase/Bucket/Key'''
%%      That is, an object stored in the Riak bucket "Bucket" at key
%%      "Key" would be available at the path Bucket/Key, relative to
%%      jiak_resource's base path.
%%
%%      jiak_resource should be added to a Webmachine dispatch with
%%      two lines, one for bucket-targetted requests, the other for
%%      item-targetted requests:
%%<pre>
%%      {[JiakBase,bucket], jiak_resource,
%%       [{key_type, container}|Options]}.
%%      {[JiakBase,bucket,key], jiak_resource,
%%       [{key_type, item}|Options]}.
%%</pre>
%%
%%      Dispatch Configuration Options:
%%<dl><dt>  {jiak_name, string()}: (Required)
%%</dt><dd>   base path for jiak_resource
%%</dd><dt> {key_type, item|container}: (Required)
%%</dt><dd>   set to 'item' when the request path targets a specific
%%            object, or to 'container' when it targets a whole bucket
%%</dd><dt> {riak_local, boolean()}: (Optional)
%%</dt><dd>   set to 'true' to use jiak:local_client/0, otherwise
%%            jiak:client_connect/3 will be used
%%</dd><dt> {riak_ip, string()}: (Required if riak_local = false)
%%</dt><dd>   IP of the riak cluster, passed to jiak:client_connect/3
%%</dd><dt> {riak_port, integer()}: (Required if riak_local = false)
%%</dt><dd>   Port of the riak cluster, passed to jiak:client_connect/3
%%</dd><dt> {riak_cookie, atom()}: (Required if riak_local = false)
%%</dt><dd>   Cookie of the riak cluster, passd to jiak:client_connect/3
%%</dd></dl>
%%
%%      HTTP Query Parameters:
%%<dl><dt>  schema
%%</dt><dd>   allowed values: true (default), false
%%            when GETting a bucket, set schema=false if you do not
%%            want the schema included in the response
%%</dd><dt> keys
%%</dt><dd>   allowed values: true (default), false
%%            when GETting a bucket, set keys=false if you do not want
%%            the keylist included in the response
%%</dd><dt> returnbody
%%</dt><dd>   allowed values: true, false (default)
%%            when PUTting or POSTing an object, set returnbody=true
%%            if you want the response to included the updated object
%%            (saves the roundtrip for a subsequent GET), the response
%%            will be 204 No Content, otherwise
%%</dd><dt> r
%%</dt><dd>   specify the Riak R value for get operations
%%</dd><dt> w
%%</dt><dd>   specify the Riak W value for put operations
%%</dd><dt> dw
%%</dt><dd>   specify the Riak DW value for put operations
%%</dd><dt> rw
%%</dt><dd>   specify the Riak RW value for delete operations
%%</dd></dl>
%%
%%      HTTP Usage:
%%<dl><dt> GET /JiakBase/Bucket
%%</dt><dd>  If the bucket is listable, returns a JSON object
%%           of the form:
%%           {
%%            "schema":{
%%                      "allowed_fields":["FieldName1","FieldName2",...],
%%                      "required_fields":["FieldName1",...],
%%                      "write_mask":["FieldName1",...],
%%                      "read_mask":["FieldName1",...]
%%                     },
%%            "keys":["Key1","Key2",...]
%%           }
%%           Each element of the "schema" lists some fo the field names
%%           defined for objects of the requested bucket.
%%<dl><dt>     allowed_fields
%%</dt><dd>      Objects may only include the fields listed here
%%</dd><dt>    required_fields
%%</dt><dd>      Objects must have fields listed here
%%</dd><dt>    write_mask
%%</dt><dd>      Clients may change only the fields listed here
%%</dd><dt>    read_mask
%%</dt><dd>      Clients will see only the contents of fields listed here
%%</dd></dl>
%%
%%</dd><dt> GET /JiakBase/Bucket/Key
%%</dt><dd>   If the object exists, and access is permitted, returns
%%            the object JSON-encoded
%%
%%</dd><dt> PUT /JiakBase/Bucket/Key
%%</dt><dd>   Store the object in the request body in the given Bucket at
%%            the given Key.  The "bucket" and "key" fields in the object
%%            must match the Bucket and Key components of the URI.
%%
%%</dd><dt> POST /JiakBase/Bucket
%%</dt><dd>   Store the object in the request body in the given Bucket at
%%            a new, server-generated key.  Response will be empty (unless
%%            returnbody=true is specified in the query parameters) with
%%            the Location header set to the new object's URI.
%%
%%</dd><dt> PUT /JiakBase/Bucket
%%</dt><dd>   Create or update the schema for a bucket.  The request body 
%%            must be a JSON object of the form:
%%            {"schema":{
%%                      "allowed_fields":["FieldName1","FieldName2",...],
%%                      "required_fields":["FieldName1",...],
%%                      "write_mask":["FieldName1",...],
%%                      "read_mask":["FieldName1",...]
%%                     }
%%            }
%%</dd></dl>
-module(jiak_resource).

-export([init/1,
         service_available/2,
         allowed_methods/2,
         resource_exists/2,
         is_authorized/2,
         content_types_provided/2,
         content_types_accepted/2,
         encodings_provided/2,
         post_is_create/2,
         create_path/2,
         handle_incoming/2,
         produce_body/2,
         delete_resource/2,
         malformed_request/2,
         forbidden/2,
	 last_modified/2,
	 generate_etag/2,
	 expires/2,
         apply_read_mask/1,
         pretty_print/2]).

%% @type context() = term()
%% @type jiak_module() = atom()|{jiak_default, list()}
-record(ctx, {bucket,       %% binary() - Bucket name (from uri)
              key,          %% binary()|container|schema - Key (or sentinal
                            %%   meaning "no key provided")
              module,       %% atom()
              jiak_context, %% jiak_context() - context for the request
              jiak_name,    %% string() - prefix for jiak uris
              jiak_client,  %% jiak_client() - the store client
              etag,         %% string() - ETag header
              bucketkeys,   %% [binary()] - keys in the bucket
              diffs,        %% {[object_diff()],{AddedLinks::[jiak_link()],
                            %%                   RemovedLinks::[jiak_link()]}
              incoming,     %% jiak_object() - object the client is storing
              storedobj}).  %% jiak_object() - object stored in Riak

-include_lib("eunit/include/eunit.hrl").
-include_lib("webmachine/include/webmachine.hrl").

%% @type key() = container|schema|riak_object:key()

%% @spec init(proplist()) -> {ok, context()}
%% @doc Initialize this webmachine resource.  This function will
%%      attempt to open a client to Riak, and will fail if it is
%%      unable to do so.
init(Props) ->
    {ok, JiakClient} = 
        case proplists:get_value(riak_local, Props) of
            true ->
                jiak:local_client();
            _ ->
                Node = proplists:get_value(riak_node, Props),
                Cookie = proplists:get_value(riak_cookie, Props),
{'fraction_non_alphanumeric': 0.1427450467534166, 'fraction_numerical': 0.005754266657948081, 'mean_word_length': 2.4640996602491505, 'pattern_counts': {'":': 22, '<': 199, '<?xml version=': 0, '>': 207, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3789011', 'n_tokens_mistral': 4615, 'n_tokens_neox': 4519, 'n_words': 1493}