SourceForge: erlangweb/erlangweb: changeset 239:ad5a3ba97850
merged branches default tip
authorXingdong Bian <xingdong.bian@erlang-consulting.com>
Mon Apr 27 17:25:01 2009 +0100 (7 months ago)
changeset 239ad5a3ba97850
parent 226dddbd72fc1c9
parent 238063aaa724b8d
merged branches
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgtags	Mon Apr 27 17:25:01 2009 +0100
     1.3 @@ -0,0 +1,1 @@
     1.4 +d93c728f66523b2eb7b58299130d26d7698caea3 1.3rc1
     2.1 --- a/INSTALL	Wed Apr 22 15:55:32 2009 +0100
     2.2 +++ b/INSTALL	Mon Apr 27 17:25:01 2009 +0100
     2.3 @@ -1,9 +1,9 @@
     2.4 -ErlangWeb 1.2 Installation Guide
     2.5 +ErlangWeb 1.3RC1 Installation Guide
     2.6  ================================
     2.7  
     2.8  1. Requirements
     2.9  -Erlang/OTP R12B-5 or later
    2.10 --Yaws 1.73 or later (included in the package)
    2.11 +-Yaws 1.80 or later (included in the package)
    2.12  
    2.13  2. Start
    2.14  To start working with ErlangWeb you should compile the three main applications:
    2.15 @@ -11,7 +11,7 @@
    2.16         bin/compile.erl
    2.17  in the root directory of the framework.
    2.18  You will also need one of the supported HTTP servers. To make your life easier,
    2.19 -Yaws server is included in version 1.73 together with pre-compiled beams.
    2.20 +Yaws server is included in version 1.80 together with pre-compiled beams.
    2.21  
    2.22  After that you can either use generic directory builder:
    2.23        bin/start.erl
    2.24 @@ -24,5 +24,5 @@
    2.25      http://localhost:8080/
    2.26  
    2.27  3. Details
    2.28 -More details can be found in doc/tutorial.pdf file.
    2.29 +More details can be found on http://wiki.erlang-web.org/
    2.30  
     3.1 --- a/bin/compile.erl	Wed Apr 22 15:55:32 2009 +0100
     3.2 +++ b/bin/compile.erl	Mon Apr 27 17:25:01 2009 +0100
     3.3 @@ -75,7 +75,10 @@
     3.4  			       [Name | _] = string:tokens(AppName, "-"),
     3.5  			       list_to_atom(Name)
     3.6  		       end, Dir),
     3.7 -    [application:load(App) || App <- ToLoad],
     3.8 +    [application:load(App) || App <- if 
     3.9 +					 Server == inets -> [inets | ToLoad];
    3.10 +					 true -> ToLoad
    3.11 +				     end],
    3.12      
    3.13      Loaded = lists:map(fun({Name, _, Vsn}) ->
    3.14  			       {Name, Vsn}
     4.1 --- a/bin/start.erl	Wed Apr 22 15:55:32 2009 +0100
     4.2 +++ b/bin/start.erl	Mon Apr 27 17:25:01 2009 +0100
     4.3 @@ -521,6 +521,15 @@
     4.4  	false ->
     4.5  	    file:copy(code:priv_dir(eptic) ++ "/inets.conf", InetsConfig),
     4.6  	    confirm_created(InetsConfig)
     4.7 +    end,
     4.8 +    
     4.9 +    ErrorsConfig = "config/errors_description.conf",
    4.10 +    case filelib:is_file(ErrorsConfig) of
    4.11 +	true ->
    4.12 +	    inform_exists(ErrorsConfig);
    4.13 +	false ->
    4.14 +	    file:copy(code:priv_dir(eptic) ++ "/errors.conf", ErrorsConfig),
    4.15 +	    confirm_created(ErrorsConfig)
    4.16      end.
    4.17  
    4.18  create_sys_config_file(yaws) ->
     5.1 --- a/lib/eptic-1.3/priv/errors.conf	Wed Apr 22 15:55:32 2009 +0100
     5.2 +++ b/lib/eptic-1.3/priv/errors.conf	Mon Apr 27 17:25:01 2009 +0100
     5.3 @@ -19,4 +19,7 @@
     5.4  {bad_time_format, "The time is badly formatted"}.
     5.5  {bad_separator_in_time_form, "Bad separator in time form"}.
     5.6  {bad_extension, "The file has bad extension"}.
     5.7 -{too_big, "The file is too big"}.
     5.8 \ No newline at end of file
     5.9 +{too_big, "The file is too big"}.
    5.10 +{empty_input, "The input could not be empty"}.
    5.11 +{not_all_mandatory_fields_checked, "Not all mandatory fields checked"}.
    5.12 +{bad_format, "Bad format"}.
    5.13 \ No newline at end of file
     6.1 --- a/lib/eptic-1.3/priv/inets.conf	Wed Apr 22 15:55:32 2009 +0100
     6.2 +++ b/lib/eptic-1.3/priv/inets.conf	Mon Apr 27 17:25:01 2009 +0100
     6.3 @@ -2,5 +2,6 @@
     6.4  ServerRoot docroot
     6.5  DocumentRoot docroot
     6.6  BindAddress 0.0.0.0 
     6.7 +# change to e_fe_mod_inets in case of running in frontend or single_node_with_cache mode
     6.8  Modules e_mod_inets mod_get mod_head mod_log 
     6.9  Port 8080
     7.1 --- a/lib/eptic-1.3/priv/yaws.conf	Wed Apr 22 15:55:32 2009 +0100
     7.2 +++ b/lib/eptic-1.3/priv/yaws.conf	Mon Apr 27 17:25:01 2009 +0100
     7.3 @@ -15,13 +15,13 @@
     7.4  # beam code can be placed. The daemon will add this
     7.5  # directory to its search path
     7.6  
     7.7 -ebin_dir = lib/yaws/ebin
     7.8 +ebin_dir = lib/yaws-1.80/ebin
     7.9  
    7.10  # This is a directory where application specific .hrl
    7.11  # files can be placed. application specifig .yaws code can
    7.12  # then include these .hrl files
    7.13  
    7.14 -include_dir = lib/yaws/include
    7.15 +include_dir = lib/yaws-1.80/include
    7.16  
    7.17  # This is a debug variable, possible values are http | traffic | false
    7.18  # It is also possible to set the trace (possibly to the tty) while
    7.19 @@ -105,10 +105,8 @@
    7.20          port = 8080
    7.21          listen = 0.0.0.0
    7.22          docroot = docroot
    7.23 +# change to e_fe_mod_yaws in case of running in frontend or single_node_with_cache mode
    7.24  	arg_rewrite_mod = e_mod_yaws
    7.25 +# change to <app, e_fe_mod_yaws> in case of running in frontend or single_node_with_cache mode
    7.26          appmods = <app, e_mod_yaws>
    7.27 -</server>
    7.28 -
    7.29 -
    7.30 -
    7.31 -
    7.32 +</server>
    7.33 \ No newline at end of file
     8.1 --- a/lib/eptic-1.3/src/e_cluster.erl	Wed Apr 22 15:55:32 2009 +0100
     8.2 +++ b/lib/eptic-1.3/src/e_cluster.erl	Mon Apr 27 17:25:01 2009 +0100
     8.3 @@ -159,7 +159,7 @@
     8.4  	    Pid = connect_to_fe(Node, State#state.ping_timeout),
     8.5  	    {noreply, State#state{workers = [{Pid, Node} | lists:keydelete(Worker, 1, State#state.workers)]}};
     8.6  	true ->
     8.7 -	    {e_fe_proxy, Node} ! {be, node()},
     8.8 +	    timer:send_after(1000, {e_fe_proxy, Node}, {be, node()}),
     8.9  	    {noreply, State#state{workers = lists:keydelete(Worker, 1, State#state.workers)}}
    8.10      end;
    8.11  
    8.12 @@ -223,6 +223,9 @@
    8.13  
    8.14      {noreply, State};
    8.15  
    8.16 +handle_info({'EXIT', From, normal}, State) ->
    8.17 +    {noreply, State#state{workers = proplists:delete(From, State#state.workers)}};
    8.18 +
    8.19  handle_info({'EXIT', From, _}, State) ->
    8.20      Node = proplists:get_value(From, State#state.workers),
    8.21      Pid = connect_to_fe(Node, State#state.ping_timeout),
     9.1 --- a/lib/eptic-1.3/src/e_logger.erl	Wed Apr 22 15:55:32 2009 +0100
     9.2 +++ b/lib/eptic-1.3/src/e_logger.erl	Mon Apr 27 17:25:01 2009 +0100
     9.3 @@ -31,8 +31,7 @@
     9.4  -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
     9.5  	 terminate/2, code_change/3]).
     9.6  
     9.7 --record(state, {enabled,
     9.8 -		log_dir, 
     9.9 +-record(state, {log_dir, 
    9.10  		max_files,
    9.11  		current_file = 1,
    9.12  		fd,
    9.13 @@ -94,30 +93,33 @@
    9.14      
    9.15      MaxLogs = e_conf:get_conf({logger, max_files}, 5),
    9.16      MaxSize = e_conf:get_conf({logger, max_entries}, 1 bsl 10),
    9.17 -    Enabled = e_conf:get_conf({logger, enabled}, true),
    9.18  
    9.19 -    if
    9.20 -	LogRes == ok ->
    9.21 -	    Filename = filename:join([LogDir, ?FILENAME ++ "1"]),
    9.22 -	    case file:open(Filename, [write, delayed_write]) of
    9.23 -		{ok, Fd} ->
    9.24 -		    ets:new(?ETS, [named_table]),
    9.25 -
    9.26 -		    timer:apply_after(?GC_TIMEOUT, gen_server, call, 
    9.27 -				      [?SERVER, garbage_collect]),
    9.28 -
    9.29 -		    {ok, #state{max_files = MaxLogs,
    9.30 -				max_entries = MaxSize,
    9.31 -				log_dir = LogDir,
    9.32 -				enabled = Enabled,
    9.33 -				fd = Fd}};
    9.34 -		Error ->
    9.35 -		    error_logger:error_msg("~p module, error during creating the log file (~p), "
    9.36 -					   "reason: ~p~n", [?MODULE, Filename, Error]),
    9.37 -		    {stop, {could_not_open_log_file, Error}}
    9.38 +    case e_conf:get_conf({logger, enabled}, true) of
    9.39 +	true ->
    9.40 +	    if
    9.41 +		LogRes == ok ->
    9.42 +		    Filename = filename:join([LogDir, ?FILENAME ++ "1"]),
    9.43 +		    case file:open(Filename, [write, delayed_write]) of
    9.44 +			{ok, Fd} ->
    9.45 +			    ets:new(?ETS, [named_table]),
    9.46 +			    
    9.47 +			    timer:apply_after(?GC_TIMEOUT, gen_server, call, 
    9.48 +					      [?SERVER, garbage_collect]),
    9.49 +			    
    9.50 +			    {ok, #state{max_files = MaxLogs,
    9.51 +					max_entries = MaxSize,
    9.52 +					log_dir = LogDir,
    9.53 +					fd = Fd}};
    9.54 +			Error ->
    9.55 +			    error_logger:error_msg("~p module, error during creating the log file (~p), "
    9.56 +						   "reason: ~p~n", [?MODULE, Filename, Error]),
    9.57 +			    {stop, {could_not_open_log_file, Error}}
    9.58 +		    end;
    9.59 +		true ->
    9.60 +		    {stop, {could_not_create_log_dir, LogRes}}
    9.61  	    end;
    9.62 -	true ->
    9.63 -	    {stop, {could_not_create_log_dir, LogRes}}
    9.64 +	false ->
    9.65 +	    ignore
    9.66      end.
    9.67  
    9.68  %%--------------------------------------------------------------------
    9.69 @@ -143,9 +145,6 @@
    9.70  %%                                      {stop, Reason, State}
    9.71  %% Description: Handling cast messages
    9.72  %%--------------------------------------------------------------------
    9.73 -handle_cast(_, #state{enabled = false} = State) ->
    9.74 -    {noreply, State};
    9.75 -
    9.76  handle_cast({register_pid, Pid}, #state{next_id = Id} = State) ->
    9.77      ets:insert(?ETS, {Pid, now(), Id}),
    9.78  
    10.1 --- a/lib/eptic-1.3/src/e_logger_viewer.erl	Wed Apr 22 15:55:32 2009 +0100
    10.2 +++ b/lib/eptic-1.3/src/e_logger_viewer.erl	Mon Apr 27 17:25:01 2009 +0100
    10.3 @@ -15,9 +15,9 @@
    10.4  
    10.5  %%%-------------------------------------------------------------------
    10.6  %%% File    : e_logger_viewer.erl
    10.7 -%%% Author  : Michal Ptaszek <michal.ptaszek@erlang-consulting.com>
    10.8 -%%% Description : Viewer for the logs recorded by the e_logger facility.
    10.9 -%%%
   10.10 +%%% @author Michal Ptaszek <michal.ptaszek@erlang-consulting.com>
   10.11 +%%% @doc Viewer for the logs recorded by the e_logger facility.
   10.12 +%%% @end
   10.13  %%% Created : 14 Apr 2009 by Michal Ptaszek <michal.ptaszek@erlang-consulting.com>
   10.14  %%%-------------------------------------------------------------------
   10.15  -module(e_logger_viewer).
    11.1 --- a/lib/eptic-1.3/src/e_mod_gen.erl	Wed Apr 22 15:55:32 2009 +0100
    11.2 +++ b/lib/eptic-1.3/src/e_mod_gen.erl	Mon Apr 27 17:25:01 2009 +0100
    11.3 @@ -232,12 +232,22 @@
    11.4  	    e_logger:log({?MODULE, {entering_dataflow_for, {Mod, Fun}}}),
    11.5  	    Answ = apply(Mod, dataflow, [Fun]),
    11.6  	    controller_handler(Answ, {Mod,Fun,View});
    11.7 -	_ ->
    11.8 -	    e_logger:log({?MODULE, {skipping_dataflow, entering_validate, {Mod, Fun}}}),
    11.9 -	    {ok, ValidArgs} = apply(Mod, validate, [Fun]),
   11.10 -	    Ret = apply(Mod, Fun, ValidArgs),
   11.11 -	    e_logger:log({?MODULE, {controller_response, Ret}}),
   11.12 -	    {ret_view, Ret, View}
   11.13 +	false ->
   11.14 +	    case lists:member({validate, 1}, Funs) of
   11.15 +		true ->
   11.16 +		    e_logger:log({?MODULE, {skipping_dataflow, entering_validate, {Mod, Fun}}}),
   11.17 +		    {ok, ValidArgs} = apply(Mod, validate, [Fun]),
   11.18 +		    Ret = apply(Mod, Fun, ValidArgs),
   11.19 +		    e_logger:log({?MODULE, {controller_response, Ret}}),
   11.20 +
   11.21 +		    {ret_view, Ret, View};
   11.22 +		false ->
   11.23 +		    e_logger:log({?MODULE, {skipping_dataflow_and_validate, entering_directly, {Mod, Fun}}}),
   11.24 +		    Ret = apply(Mod, Fun, [get_dataflow_initial_args()]),
   11.25 +		    e_logger:log({?MODULE, {controller_response, Ret}}),
   11.26 +		    
   11.27 +		    {ret_view, Ret, View}
   11.28 +	    end
   11.29      end.
   11.30  
   11.31  -spec(controller_handler/2 :: ({list(atom()), list(atom())} | list(atom()), {atom(), atom(), string()}) ->
    12.1 --- a/lib/eptic_fe-1.0/src/e_fe_mod_yaws.erl	Wed Apr 22 15:55:32 2009 +0100
    12.2 +++ b/lib/eptic_fe-1.0/src/e_fe_mod_yaws.erl	Mon Apr 27 17:25:01 2009 +0100
    12.3 @@ -49,14 +49,14 @@
    12.4  	    e_dict:fset("__cacheable", is_cacheable()),
    12.5  
    12.6  	    ControllerFun = fun() -> 
    12.7 -				    URL = [$/ | URL],
    12.8 -				    case e_fe_mod_gen:handle_request(URL) of
    12.9 +				    PURL = [$/ | URL],
   12.10 +				    case e_fe_mod_gen:handle_request(PURL) of
   12.11  					enoent ->
   12.12  					    enoent;
   12.13  					{ready, Ready} ->
   12.14  					    Ready;
   12.15  					{not_ready, NotReady, View} ->
   12.16 -					    controller_exec(NotReady, View, URL)
   12.17 +					    controller_exec(NotReady, View, PURL)
   12.18  				    end
   12.19  			    end,
   12.20  
    13.1 --- a/lib/wpart-1.3/ebin/wpart.app	Wed Apr 22 15:55:32 2009 +0100
    13.2 +++ b/lib/wpart-1.3/ebin/wpart.app	Mon Apr 27 17:25:01 2009 +0100
    13.3 @@ -1,10 +1,3 @@
    13.4 -% This is an -*- erlang -*- file.
    13.5 -%%% ===================================================================
    13.6 -%%% @author  Jon Doe <jondoe@erlang-consulting.com>
    13.7 -%%% @copyright (C) 2006 Erlang Training & Consulting Ltd.
    13.8 -%%% @doc
    13.9 -%%% @end 
   13.10 -%%% ===================================================================
   13.11  {application, wpart, [
   13.12  	{description, "Wpart"},
   13.13  	{vsn, "1.3"},
    14.1 --- a/lib/wpart-1.3/src/validate_tool.erl	Wed Apr 22 15:55:32 2009 +0100
    14.2 +++ b/lib/wpart-1.3/src/validate_tool.erl	Mon Apr 27 17:25:01 2009 +0100
    14.3 @@ -56,26 +56,7 @@
    14.4      {Result, _Bad} = get_values(Type, Fields, List),
    14.5  
    14.6      %% special case of primary key, if it's not in post - it's creating not editing
    14.7 -    Pr = case eptic:fget("post", "__primary_key") of
    14.8 -	     undefined -> 
    14.9 -		 undefined;
   14.10 -	     PK ->
   14.11 -		 TypeOpts = tl(tuple_to_list(Mod:get_record_info(
   14.12 -					       list_to_atom(atom_to_list(Type) ++ "_types")))),
   14.13 -		 {PKPos, {PKType, PKOpts}} = case wpart_utils:find_pk(TypeOpts) of
   14.14 -						 no_pk ->
   14.15 -						     {1, hd(TypeOpts)};
   14.16 -						 Else ->
   14.17 -						     Else
   14.18 -					     end,
   14.19 -
   14.20 -		 case wpart_utils:string2term(PKType, PK, PKOpts) of
   14.21 -		     {ok, PKTerm} ->
   14.22 -			 {PKPos, PKTerm};
   14.23 -		     _ ->
   14.24 -			 undefined
   14.25 -		 end
   14.26 -	 end,
   14.27 +    Pr = get_primary_key(Mod, Type),
   14.28      Final = replace_primary(Result, Pr),
   14.29  
   14.30      {ok, list_to_tuple([ParentType | Final])}.
   14.31 @@ -97,9 +78,9 @@
   14.32      
   14.33      %% special case of primary key - if error on edit returns {ok,[]} to get original 
   14.34      %% values from DB or set special initial values.
   14.35 -    case eptic:fget("post", "__primary_key") of
   14.36 +    case get_primary_key(Mod, Type)  of
   14.37  	undefined -> {error, not_valid};
   14.38 -	P -> {error, {Fun, list_to_integer(P)}}
   14.39 +	{_, Term} -> {error, {Fun, Term}}
   14.40      end.
   14.41  
   14.42  -spec(replace_primary/2 :: (list(), undefined | {integer(), term()}) -> list()).
   14.43 @@ -138,3 +119,27 @@
   14.44  			   Reason_list ++ [io_lib:format("~p", [Reason])])
   14.45  	    end
   14.46     end.
   14.47 +
   14.48 +-spec(get_primary_key/2 :: (atom(), atom()) -> undefined | {integer(), term()}). 
   14.49 +get_primary_key(Mod, Type) ->
   14.50 +    case eptic:fget("post", "__primary_key") of
   14.51 +	undefined -> 
   14.52 +	    undefined;
   14.53 +	PK ->
   14.54 +	    TypeOpts = tl(tuple_to_list(Mod:get_record_info(
   14.55 +					  list_to_atom(atom_to_list(Type) ++ "_types")))),
   14.56 +	    {PKPos, {PKType, PKOpts}} = case wpart_utils:find_pk(TypeOpts) of
   14.57 +					    no_pk ->
   14.58 +						{1, hd(TypeOpts)};
   14.59 +					    Else ->
   14.60 +						Else
   14.61 +					end,
   14.62 +
   14.63 +	    case wpart_utils:string2term(PKType, PK, PKOpts) of
   14.64 +		{ok, PKTerm} ->
   14.65 +		    {PKPos, PKTerm};
   14.66 +		_ ->
   14.67 +		    undefined
   14.68 +		 end
   14.69 +    end.
   14.70 +    
    15.1 --- a/lib/wpart-1.3/src/wpart_db.erl	Wed Apr 22 15:55:32 2009 +0100
    15.2 +++ b/lib/wpart-1.3/src/wpart_db.erl	Mon Apr 27 17:25:01 2009 +0100
    15.3 @@ -15,8 +15,8 @@
    15.4  
    15.5  %%%-------------------------------------------------------------------
    15.6  %%% File    : wpart_db.erl
    15.7 -%%% Author  : Michal Ptaszek <michal.ptaszek@erlang-consulting.com>
    15.8 -%%% Description : 
    15.9 +%%% @author Michal Ptaszek <michal.ptaszek@erlang-consulting.com>
   15.10 +%%% @end
   15.11  %%%
   15.12  %%%-------------------------------------------------------------------
   15.13  -module(wpart_db).
   15.14 @@ -51,7 +51,7 @@
   15.15  					      [{Prefix ++ atom_to_list(Name), Val} | Acc];
   15.16  					  false ->
   15.17  					      [build_record_structure(Type, Val, 
   15.18 -								      Prefix ++ atom_to_list(Type) ++ "_") |
   15.19 +								      Prefix ++ atom_to_list(Name) ++ "_") |
   15.20  					       Acc]
   15.21  				      end
   15.22  			      end,
    16.1 --- a/lib/wpart-1.3/src/wpart_valid.erl	Wed Apr 22 15:55:32 2009 +0100
    16.2 +++ b/lib/wpart-1.3/src/wpart_valid.erl	Mon Apr 27 17:25:01 2009 +0100
    16.3 @@ -16,100 +16,141 @@
    16.4  %%%-------------------------------------------------------------------
    16.5  %%% File    : wpart_valid.erl
    16.6  %%% Author  : Michal Zajda <michal.zajda@erlang-consulting.com>
    16.7 -%%% Description : 
    16.8 -%%%
    16.9 +%%% Description : Validation of custom types by dividing them into basic types 
   16.10 +%%%               and routing to the validate function in proper wtypes
   16.11  %%%-------------------------------------------------------------------
   16.12 +
   16.13  -module(wpart_valid).
   16.14 --export([validate/1, validate/2, validate/3, is_private/1]).
   16.15 +-export([validate/1, validate/3, is_private/1]).
   16.16  
   16.17 -part(0,_,_,_,BasicFields,ComplexTypes, BasicTypes) ->
   16.18 -    {BasicFields, ComplexTypes, BasicTypes};
   16.19 -part(N, Fields, TypesList, BTList, BasicFields, ComplexTypes, BasicTypes) -> 
   16.20 -    [H1|T1] = TypesList,
   16.21 -    [H2|T2] = Fields,
   16.22 -    {X,_} = H1,
   16.23 -    Res = lists:member(X, BTList),
   16.24 -    if Res -> part(N-1,T2,T1,BTList,
   16.25 -		   [H2 | BasicFields],
   16.26 -		   ComplexTypes, [H1 | BasicTypes]);
   16.27 -       true -> part(N-1,T2,T1,BTList,BasicFields,[H1 | ComplexTypes], BasicTypes)
   16.28 +
   16.29 +%% @doc the initial call from a controller
   16.30 +-spec(validate/1 :: (atom()) -> {ok, list()} | {error, list()}).
   16.31 +validate(TypeName) ->
   16.32 +    POST = eptic:fget("post"),
   16.33 +    Primitives =  e_conf:primitive_types(),
   16.34 +
   16.35 +    {ErrorCount, V_Result} = validate(POST, Primitives, 
   16.36 +				      [{atom_to_list(TypeName), TypeName}], [], 0),
   16.37 +     
   16.38 +    if   
   16.39 +	ErrorCount > 0 -> {error,V_Result};
   16.40 +	true -> {ok, V_Result}
   16.41      end.
   16.42  
   16.43 -%% From : ["news","person"]
   16.44 -validate(Fields, Types, From) ->
   16.45 -    TypesList = tuple_to_list(Types),
   16.46 -    [_ | TypesListTail] = TypesList,
   16.47 +%% @doc Function validates field by field from a record definition, when field aprears 
   16.48 +%% to be nested type its predessor is formed and passed with TypeName
   16.49 +-spec(validate/5 ::  (undefined|list(), list(), list(tuple()), list(), integer()) ->
   16.50 +	     {integer(),list(tuple())}).
   16.51 +validate(_, _, [[]], Acc, ErrorCount) ->
   16.52 +    {ErrorCount,Acc};
   16.53 +%% clause to match call when POST is empty (form building)
   16.54 +validate(undefined, Primitives, [{Predessor, TypeName} | MoreTypes], Acc, ErrorCount) ->
   16.55 +    validate([], Primitives, [{Predessor, TypeName} | MoreTypes], Acc, ErrorCount);
   16.56 +validate(POST, Primitives, [{Predessor, TypeName} | MoreTypes], Acc, ErrorCount) ->
   16.57  
   16.58 -    {BasicFields, Complex, Basic} = part(length(TypesList)-1, Fields, 
   16.59 -					 TypesListTail, e_conf:primitive_types(),[],[],[]),
   16.60 -    LongBasicFields = lists:map(fun(X)-> string:join(From, "_") ++ 
   16.61 -					     "_" ++ atom_to_list(X) end, 
   16.62 -				BasicFields),
   16.63 +    %% {[atom()],tuple()}
   16.64 +    {RecInfo, TypeRecInstance} = get_record_info(TypeName),
   16.65  
   16.66 -    LeafResult = if 
   16.67 -		     Complex =/= [] -> 
   16.68 -			 [[_ | Val]] = lists:map(fun({X,_}) -> 
   16.69 -							 validate(X, From) 
   16.70 -						 end,
   16.71 -						 Complex),
   16.72 -			 Val;
   16.73 -		     true -> []
   16.74 -		 end,
   16.75 +    [_ | Types] = tuple_to_list(TypeRecInstance),
   16.76  
   16.77 -    Fun = fun({{collection, _}, X}) -> 
   16.78 -		  get_collection_fields(X);
   16.79 -	     ({_, X}) ->
   16.80 -		  eptic:fget("post", X)
   16.81 -	  end,
   16.82 -    PostInput = lists:map(Fun, lists:zip(Basic, LongBasicFields)),
   16.83 +    {groups, PostNames, BasicTypes, ComplexFields} = 
   16.84 +	sort_out(RecInfo,Types, Primitives, Predessor),
   16.85 +    
   16.86 +    Input = zip_get(BasicTypes, PostNames, POST, []),
   16.87 +    
   16.88 +    Result = validate_local(Input, BasicTypes),
   16.89 +    %% posible to optimize and combine with validate_local
   16.90 +    Errors = save_errors(PostNames, Result),
   16.91 +    ResultExt = lists:zip(Result,PostNames),
   16.92  
   16.93 -    Final = tuple_to_list(pusher(PostInput, Basic, LongBasicFields)),
   16.94 +    validate(POST, Primitives, [ComplexFields|MoreTypes], 
   16.95 +	     ResultExt ++ Acc, ErrorCount + Errors).
   16.96  
   16.97 -    Final ++ LeafResult.
   16.98 +-spec(validate_local/2 :: (list(),list()) -> list(tuple())).
   16.99 +validate_local(L1,L2) ->
  16.100 +    validate_local(L1,L2,[]).
  16.101  
  16.102 -validate(Name) when is_atom(Name) ->
  16.103 -    [_ | R] = apply(list_to_atom("wtype_" ++ atom_to_list(Name)), 
  16.104 -			 validate, [[]]),
  16.105 -    Result = lists:flatten(R),
  16.106 -    Temp = lists:map(fun({{X,_},_})-> X end, Result),
  16.107 -    
  16.108 -    Bad = lists:member(error, Temp),
  16.109 -    if not Bad -> {ok, Result};
  16.110 -       Bad -> {error, Result}
  16.111 -    end.
  16.112 - 
  16.113 -validate(Name, From) when is_atom(Name) ->
  16.114 -    apply(list_to_atom("wtype_" ++ atom_to_list(Name)), validate, [From]). 
  16.115 +-spec(validate_local/3 :: (list(),list(),list()) -> list(tuple())).
  16.116 +validate_local([],[],Acc) ->
  16.117 +    lists:reverse(Acc);
  16.118 +validate_local([In|InputTail], [{Name,Attr} | BasicTypesTail], Acc) ->
  16.119 +    Result = apply(list_to_atom("wtype_" ++ atom_to_list(Name)),validate,[{Attr,In}]),
  16.120 +    validate_local(InputTail,BasicTypesTail,[Result|Acc]).
  16.121  
  16.122 -%% BasicType - {date, [{format, YYYY-MM-DD}]}
  16.123 -pusher(Input, BasicTypes, LongBasicFields) ->
  16.124 -    Pairs = lists:zip(BasicTypes, Input),
  16.125 -    Result = lists:map(fun check/1, Pairs),
  16.126 -    save_errors(LongBasicFields, Result),
  16.127 -    Bad = lists:keymember(error,1,Result),
  16.128 -    if   
  16.129 -	not Bad -> {ok, show_output(Result,LongBasicFields,[])};
  16.130 -	true -> {error, show_output(Result,LongBasicFields,[])}
  16.131 +%% @doc function retrieves form post single value or set of values.
  16.132 +%% It should not be unified because only collection fields could have multipule vals under one key;
  16.133 +%% more than one val in one-POST-er field is hack or bug and should not be propagated.
  16.134 +-spec(zip_get/4 :: (list(tuple()), list(string()), 
  16.135 +		    list(tuple()), list(tuple())) -> list(tuple())).
  16.136 +zip_get([],[],_,Acc)->
  16.137 +    lists:reverse(Acc);
  16.138 +zip_get([{collection,_}|T1],[H2|T2], POST, Acc) ->    
  16.139 +    In = proplists:get_all_values(H2,POST),
  16.140 +    zip_get(T1,T2,POST,[In|Acc]);
  16.141 +zip_get([_|T1],[H2|T2], POST, Acc) ->
  16.142 +    In = proplists:get_value(H2,POST),
  16.143 +    zip_get(T1,T2,POST,[In|Acc]).
  16.144 +
  16.145 +%% @doc divides fields into groups to discover which fields' names are ready to retrieve from POST.
  16.146 +%% It is not obvious, because types can be nested and have hierarchical names.
  16.147 +%% Basic types fields are resolved to proper names (predessor name added with '_').
  16.148 +%% To complex type current type is passed to become predessor.
  16.149 +-spec(sort_out/4 :: (list(atom()), list(tuple()), list(), string()) ->
  16.150 +	    	    {groups, list(string()), list(tuple()), list(tuple())}).
  16.151 +sort_out(RecInfo, Types, Primitives, Before) ->
  16.152 +    sort_out(RecInfo, Types, Primitives, Before,[],[],[]).
  16.153 +
  16.154 +-spec(sort_out/7 :: (list(atom()), list(tuple()), list(), string(), list(), list(), list()) ->
  16.155 +	    	    {groups, list(string()), list(tuple()), list(tuple())}).
  16.156 +sort_out([], _, _, _,
  16.157 +	 BasicFields, BasicTypes, ComplexFields) ->
  16.158 +    {groups,  BasicFields, BasicTypes, ComplexFields};
  16.159 +sort_out([H1|T1], [H2={Type, _AttrList}|T2], Primitives, Before,
  16.160 +	 BasicFields, BasicTypes, ComplexFields) ->
  16.161 +    case lists:member(Type, Primitives) of
  16.162 +	true ->
  16.163 +	    sort_out(T1,T2,Primitives,Before,
  16.164 +		     [string:join([Before,atom_to_list(H1)],"_")|BasicFields],
  16.165 +		     [H2|BasicTypes],ComplexFields);
  16.166 +	false ->
  16.167 +	    sort_out(T1,T2,Primitives,Before,
  16.168 +		     BasicFields,BasicTypes,
  16.169 +		     [{string:join([Before,atom_to_list(H1)],"_"), H1}|ComplexFields])
  16.170      end.
  16.171  
  16.172 -show_output([],_,R) ->
  16.173 -    R;
  16.174 -show_output(Result,LongBasicFields, Output) ->
  16.175 -   [H|T] = Result,
  16.176 -   [HH|TT] = LongBasicFields,  
  16.177 -   show_output(T,TT, Output ++ [{H, HH}]).
  16.178 +%% @doc calls a custom wtype modules to get a custom type definition
  16.179  
  16.180 -%% helper function to check if input has good type (using called wtype_ )
  16.181 -%% takes structure eqivalent to types record and input string 
  16.182 -%% check ( { {date, [{format, YYYY-MM-DD}]} , input_string } )
  16.183 -%% returns proper input (if oryginal one was not complete) {ok, StrOk} or {error, Msg}
  16.184 -check({Type, Input}) ->
  16.185 -    {H,T} = Type, 
  16.186 -    apply(list_to_atom("wtype_" ++ atom_to_list(H)),validate,[{T,Input}]).
  16.187 +-spec(get_record_info/1 :: (atom()) -> {list(atom()), list(tuple())}).
  16.188 +get_record_info(TypeName) ->
  16.189 +    %% TypeNameStr can be different from Predessor
  16.190 +    TypeNameStr = atom_to_list(TypeName),
  16.191 +    Module = list_to_atom("wtype_" ++ TypeNameStr),
  16.192 +    RecordInfo = apply(Module,
  16.193 +		       get_record_info,
  16.194 +		       [TypeName]),
  16.195 +    RecName = list_to_atom(TypeNameStr ++ "_types"),
  16.196 +    TypeRecordInstance = apply(Module,
  16.197 +			       get_record_info,
  16.198 +			       [RecName]),
  16.199 +    {RecordInfo, TypeRecordInstance}.
  16.200  
  16.201 -%% function which checks if the field should be validated
  16.202 -%% if it is a private field - not shown on forms - it will be skipped
  16.203 -%% beacuse it will be set by some default value later (e.g. ID)
  16.204 +
  16.205 +-spec(save_errors/2 :: (list(string()), list()) -> integer()).	     
  16.206 +save_errors(L1,L2) ->
  16.207 +    save_errors(L1,L2,0).
  16.208 +
  16.209 +-spec(save_errors/3 :: (list(string()), list(), integer()) -> integer()).	
  16.210 +save_errors([], [], Err) ->
  16.211 +    Err;
  16.212 +save_errors([FieldName | RestFields], [{error, Reason} | RestResults], Err) ->
  16.213 +    e_error:save(FieldName, Reason),
  16.214 +    save_errors(RestFields, RestResults, Err+1);
  16.215 +save_errors([_ | RestFields], [_ | RestResults], Err) ->
  16.216 +    save_errors(RestFields, RestResults, Err).
  16.217 +
  16.218 +%% Private fields are not displayed and validated
  16.219 +-spec(is_private/1 :: (list(tuple())) -> ( term() | false )).
  16.220  is_private(Params) ->
  16.221      case lists:keysearch(private, 1, Params) of
  16.222  	{value, {private, Val}} ->
  16.223 @@ -118,21 +159,7 @@
  16.224  	    false
  16.225      end.
  16.226  
  16.227 -get_collection_fields(Name) ->
  16.228 -    lists:foldl(fun({Key, Val}, Acc) ->
  16.229 -			case string:str(Key, Name) of
  16.230 -			    0 ->
  16.231 -				Acc;
  16.232 -			    _ ->
  16.233 -				[{Key, Val} | Acc]
  16.234 -			end
  16.235 -		end, [], eptic:fget("post")).
  16.236  
  16.237 --spec(save_errors/2 :: (list(string()), list()) -> ok).	     
  16.238 -save_errors([], []) ->
  16.239 -    ok;
  16.240 -save_errors([FieldName | RestFields], [{error, Reason} | RestResults]) ->
  16.241 -    e_error:save(FieldName, Reason),
  16.242 -    save_errors(RestFields, RestResults);
  16.243 -save_errors([_ | RestFields], [_ | RestResults]) ->
  16.244 -    save_errors(RestFields, RestResults).
  16.245 +%% @doc back compatibility function.
  16.246 +validate(_,_,_) ->
  16.247 +    depricated.
    17.1 --- a/lib/wpart-1.3/src/wpartlib.erl	Wed Apr 22 15:55:32 2009 +0100
    17.2 +++ b/lib/wpart-1.3/src/wpartlib.erl	Mon Apr 27 17:25:01 2009 +0100
    17.3 @@ -137,7 +137,6 @@
    17.4  		    [Token|Tokens] = string:tokens(Key,":"),
    17.5  		    case search(wpart:fget(Token), Tokens) of
    17.6  			[] -> "[]";
    17.7 -			V when is_list(V) -> V;
    17.8  			V -> io_lib:format("~p",[V])
    17.9  		    end
   17.10  	    end,
    18.1 --- a/lib/wparts-1.3/ebin/wparts.app	Wed Apr 22 15:55:32 2009 +0100
    18.2 +++ b/lib/wparts-1.3/ebin/wparts.app	Mon Apr 27 17:25:01 2009 +0100
    18.3 @@ -1,10 +1,3 @@
    18.4 -% This is an -*- erlang -*- file.
    18.5 -%%% ===================================================================
    18.6 -%%% @author  Jon Doe <jondoe@erlang-consulting.com>
    18.7 -%%% @copyright (C) 2006 Erlang Training & Consulting Ltd.
    18.8 -%%% @doc
    18.9 -%%% @end 
   18.10 -%%% ===================================================================
   18.11  {application, wparts,
   18.12   [{description, "Wpart Components"},
   18.13    {vsn, "1.3"},
    19.1 --- a/lib/wparts-1.3/priv/html/div_item.tpl	Wed Apr 22 15:55:32 2009 +0100
    19.2 +++ b/lib/wparts-1.3/priv/html/div_item.tpl	Mon Apr 27 17:25:01 2009 +0100
    19.3 @@ -1,7 +1,7 @@
    19.4  <div id="<% id %>" class="form_entry">
    19.5       <label for="<% id %>"><% description %>
    19.6 -     	    <span class="form_error" id="<% id %>_error"><% error %></span>
    19.7 -	    <span class="form_comment" id="<% id %>_comment"><% comment %></span>
    19.8 +     	    <% error %>
    19.9 +	    <% comment %>
   19.10       </label>
   19.11       <span class="form_input"><% input %></span>
   19.12  </div>
   19.13 \ No newline at end of file
    20.1 --- a/lib/wparts-1.3/priv/html/list_item.tpl	Wed Apr 22 15:55:32 2009 +0100
    20.2 +++ b/lib/wparts-1.3/priv/html/list_item.tpl	Mon Apr 27 17:25:01 2009 +0100
    20.3 @@ -1,7 +1,7 @@
    20.4  <li id="<% id %>" class="form_entry">
    20.5       <label for="<% id %>"><% description %>
    20.6 -     	    <span class="form_error" id="<% id %>_error"><% error %></span>
    20.7 -	    <span class="form_comment" id="<% id %>_comment"><% comment %></span>
    20.8 +     	    <% error %>
    20.9 +	    <% comment %>
   20.10       </label>
   20.11       <span class="form_input"><% input %></span>
   20.12  </li>
   20.13 \ No newline at end of file
    21.1 --- a/lib/wparts-1.3/priv/html/paragraph_item.tpl	Wed Apr 22 15:55:32 2009 +0100
    21.2 +++ b/lib/wparts-1.3/priv/html/paragraph_item.tpl	Mon Apr 27 17:25:01 2009 +0100
    21.3 @@ -1,7 +1,7 @@
    21.4  <p id="<% id %>" class="form_entry">
    21.5       <label for="<% id %>"><% description %>
    21.6 -     	    <span class="form_error" id="<% id %>_error"><% error %></span>
    21.7 -	    <span class="form_comment" id="<% id %>_comment"><% comment %></span>
    21.8 +     	    <% error %>
    21.9 +	    <% comment %>
   21.10       </label>
   21.11       <span class="form_input"><% input %></span>
   21.12  </p>
   21.13 \ No newline at end of file
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/lib/wparts-1.3/priv/html/span.tpl	Mon Apr 27 17:25:01 2009 +0100
    22.3 @@ -0,0 +1,1 @@
    22.4 +<span <% html %>> <% content %> </span>
    22.5 \ No newline at end of file
    23.1 --- a/lib/wparts-1.3/priv/html/table_item.tpl	Wed Apr 22 15:55:32 2009 +0100
    23.2 +++ b/lib/wparts-1.3/priv/html/table_item.tpl	Mon Apr 27 17:25:01 2009 +0100
    23.3 @@ -8,7 +8,7 @@
    23.4  </tr>
    23.5  <tr>
    23.6  	<td>
    23.7 -		<span class="form_comment" id="<% id %>_comment"> <% comment %></span>
    23.8 -		<span class="form_error" id="<% id %>_error"> <% error %></span>
    23.9 +		<% comment %>
   23.10 +		<% error %>
   23.11  	</td>
   23.12  </tr>
   23.13 \ No newline at end of file
    24.1 --- a/lib/wparts-1.3/src/wpart_collection.erl	Wed Apr 22 15:55:32 2009 +0100
    24.2 +++ b/lib/wparts-1.3/src/wpart_collection.erl	Mon Apr 27 17:25:01 2009 +0100
    24.3 @@ -20,7 +20,7 @@
    24.4  %%% @end
    24.5  %%%-------------------------------------------------------------------
    24.6  -module(wpart_collection).
    24.7 --behaviour(wpart).
    24.8 +%-behaviour(wpart).
    24.9  
   24.10  -export([handle_call/1, build_html_tag/4, load_tpl/0]).
   24.11  
    25.1 --- a/lib/wparts-1.3/src/wpart_derived.erl	Wed Apr 22 15:55:32 2009 +0100
    25.2 +++ b/lib/wparts-1.3/src/wpart_derived.erl	Mon Apr 27 17:25:01 2009 +0100
    25.3 @@ -30,7 +30,8 @@
    25.4      case wpartlib:has_attribute("attribute::type", E) of
    25.5  	false -> 
    25.6  	    error_logger:error_msg("~p module, error during processing the handle_call/1 function.~n"
    25.7 -				   "wpart:derived tag must have the type attribute~n~n"),
    25.8 +				   "wpart:derived tag must have the type attribute~n~n",
    25.9 +				   [?MODULE]),
   25.10  	    #xmlText{value=""};
   25.11  	Type -> 
   25.12  	    FormType = case wpartlib:has_attribute("attribute::form_type", E) of
   25.13 @@ -132,13 +133,30 @@
   25.14      Module = list_to_atom("wpart_" ++ atom_to_list(Type)),
   25.15      LName = generate_long_name(Prefix, Name),
   25.16      Input = Module:build_html_tag(LName, Params, find(LName, Defaults)),
   25.17 +    Span = wpart_gen:tpl_get(span),
   25.18 +
   25.19 +    Proplist0 = [{"id", LName}, {"input", Input}, {"description", get_description(Params)}],
   25.20 +    Proplist1 = case e_error:description(LName) of
   25.21 +		    [] ->
   25.22 +			Proplist0;
   25.23 +		    ErrorDesc ->
   25.24 +			[{"error", wpart_gen:build_html(Span, [{"content", ErrorDesc},
   25.25 +							       {"id", LName ++ "_error"},
   25.26 +							       {"class", "form_error"}])}
   25.27 +			 | Proplist0]
   25.28 +		end,
   25.29 +    Proplist = case get_comment(Params) of
   25.30 +		   [] ->
   25.31 +		       Proplist1;
   25.32 +		   CommentDesc ->
   25.33 +		       [{"comment", wpart_gen:build_html(Span, [{"content", CommentDesc},
   25.34 +								{"id", LName ++ "_comment"},
   25.35 +								{"class", "form_comment"}])}
   25.36 +			| Proplist1]
   25.37 +	       end,
   25.38  
   25.39      wpart_gen:build_html(wpart_gen:tpl_get(form_type(FormType)), 
   25.40 -			 [{"id", LName},
   25.41 -			  {"error", e_error:description(LName)},
   25.42 -			  {"description", get_description(Params)},
   25.43 -			  {"comment", get_comment(Params)},
   25.44 -			  {"input", Input}]).
   25.45 +			 Proplist).
   25.46  
   25.47  -spec(build_html_tag/4 :: (atom(), atom(), string(), list()) -> string()).	     
   25.48  build_html_tag(Type, _Name, Prefix, _Params) ->
   25.49 @@ -219,4 +237,7 @@
   25.50  		       filename:join([code:priv_dir(wparts),"html","list_item.tpl"])),
   25.51      
   25.52      wpart_gen:load_tpl(div_item, 
   25.53 -		       filename:join([code:priv_dir(wparts),"html","div_item.tpl"])).
   25.54 +		       filename:join([code:priv_dir(wparts),"html","div_item.tpl"])),
   25.55 +    
   25.56 +    wpart_gen:load_tpl(span, 
   25.57 +		       filename:join([code:priv_dir(wparts),"html","span.tpl"])).
    26.1 --- a/lib/wparts-1.3/src/wtype_multilist.erl	Wed Apr 22 15:55:32 2009 +0100
    26.2 +++ b/lib/wparts-1.3/src/wtype_multilist.erl	Mon Apr 27 17:25:01 2009 +0100
    26.3 @@ -58,4 +58,6 @@
    26.4  one_element_check([T | _] = Input) when is_list(T) ->
    26.5      {ok, Input};
    26.6  one_element_check([T | _] = Input) when is_integer(T) ->
    26.7 -    {ok, [Input]}.
    26.8 +    {ok, [Input]};
    26.9 +one_element_check([]) ->
   26.10 +    {error, {empty, []}}.
    27.1 --- a/lib/wparts-1.3/src/wtype_string.erl	Wed Apr 22 15:55:32 2009 +0100
    27.2 +++ b/lib/wparts-1.3/src/wtype_string.erl	Mon Apr 27 17:25:01 2009 +0100
    27.3 @@ -28,7 +28,9 @@
    27.4  handle_call(_Format, #xmlText{value=String}) ->
    27.5      #xmlText{value=String};
    27.6  handle_call(_Format, String) when is_list(String) ->
    27.7 -    String.
    27.8 +    String;
    27.9 +handle_call(_Format, undefined) ->
   27.10 +    [].
   27.11  
   27.12  validate({Types,undefined}) -> 
   27.13      case wpart_valid:is_private(Types) of
    28.1 --- a/lib/wparts-1.3/src/wtype_time.erl	Wed Apr 22 15:55:32 2009 +0100
    28.2 +++ b/lib/wparts-1.3/src/wtype_time.erl	Mon Apr 27 17:25:01 2009 +0100
    28.3 @@ -24,7 +24,7 @@
    28.4  -include_lib("xmerl/include/xmerl.hrl").
    28.5  
    28.6  -export([handle_call/2, validate/1]).
    28.7 --export([get_time/2, is_valid_time/1]).
    28.8 +-export([get_time/2, format/2, is_valid_time/1]).
    28.9  -export([check_min/2, check_max/2]).
   28.10  
   28.11  handle_call(Format, #xmlText{value = Time}) -> 
   28.12 @@ -143,6 +143,9 @@
   28.13  get_time(Format, Time) ->
   28.14      format(Format, Time, []).
   28.15  
   28.16 +format(Format, Time) ->
   28.17 +    format(Format, Time, []).
   28.18 +
   28.19  format("HH" ++ R, {Hour, _, _} = T, Acc) ->
   28.20      format(R, T, Acc ++ convert(Hour));
   28.21  format("MM" ++ R, {_, Min, _} = T, Acc) ->