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) ->