Merge branch 'api-redesign' into client-redesign

This commit is contained in:
Jonathan Bernard
2011-05-03 12:40:06 -05:00
9 changed files with 54 additions and 53 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+44 -44
View File
@@ -34,19 +34,18 @@ out(YArg) ->
dispatch_request(YArg, _Session, []) -> make_json_404(YArg, [{see_docs, "/ts_api_doc"}]); dispatch_request(YArg, _Session, []) -> make_json_404(YArg, [{see_docs, "/ts_api_doc"}]);
dispatch_request(YArg, Session, [H|T]) -> dispatch_request(YArg, Session, [H|T]) ->
Param = path_element_to_atom(H),
case {Session, Param} of case {Session, H} of
{_, login} -> do_login(YArg); {_, "login"} -> do_login(YArg);
{_, logout} -> do_logout(YArg); {_, "logout"} -> do_logout(YArg);
{not_logged_in, _} -> make_json_401(YArg); {"not_logged_in", _} -> make_json_401(YArg);
{session_expired, _} -> make_json_401(YArg, [{error, "session expired"}]); {"session_expired", _} -> make_json_401(YArg, [{error, "session expired"}]);
{_S, app} -> dispatch_app(YArg, Session, T); {_S, "app"} -> dispatch_app(YArg, Session, T);
{_S, users} -> dispatch_user(YArg, Session, T); {_S, "users"} -> dispatch_user(YArg, Session, T);
{_S, timelines} -> dispatch_timeline(YArg, Session, T); {_S, "timelines"} -> dispatch_timeline(YArg, Session, T);
{_S, entries} -> dispatch_entry(YArg, Session, T); {_S, "entries"} -> dispatch_entry(YArg, Session, T);
{_S, _Other} -> make_json_404(YArg, [{see_docs, "/ts_api_doc/"}]) {_S, _Other} -> make_json_404(YArg, [{see_docs, "/ts_api_doc/"}])
end. end.
@@ -59,7 +58,7 @@ dispatch_app(YArg, Session, Params) ->
{'GET', ["user_summary", UsernameStr]} -> {'GET', ["user_summary", UsernameStr]} ->
case {Session#ts_api_session.username, case {Session#ts_api_session.username,
path_element_to_atom(UsernameStr)} of UsernameStr} of
{Username, Username} -> get_user_summary(YArg, Username); {Username, Username} -> get_user_summary(YArg, Username);
_ -> make_json_401(YArg) _ -> make_json_401(YArg)
@@ -75,10 +74,9 @@ dispatch_app(YArg, Session, Params) ->
% -------- Dispatch for /user -------- % % -------- Dispatch for /user -------- %
dispatch_user(YArg, Session, []) -> dispatch_user(YArg, Session, []) ->
dispatch_user(YArg, Session, [atom_to_list(Session#ts_api_session.username)]); dispatch_user(YArg, Session, [Session#ts_api_session.username]);
dispatch_user(YArg, Session, [H]) -> dispatch_user(YArg, Session, [Username]) ->
Username = path_element_to_atom(H),
HTTPMethod = (YArg#arg.req)#http_request.method, HTTPMethod = (YArg#arg.req)#http_request.method,
% compare to the logged-in user % compare to the logged-in user
@@ -97,8 +95,7 @@ dispatch_user(YArg, Session, [H]) ->
dispatch_timeline(YArg, _Session, []) -> dispatch_timeline(YArg, _Session, []) ->
make_json_404(YArg, [{see_docs, "/ts_api_doc/timelines.html"}]); make_json_404(YArg, [{see_docs, "/ts_api_doc/timelines.html"}]);
dispatch_timeline(YArg, Session, [UrlUsername|_T] = PathElements) -> dispatch_timeline(YArg, Session, [Username|_T] = PathElements) ->
Username = path_element_to_atom(UrlUsername),
case Session#ts_api_session.username of case Session#ts_api_session.username of
Username -> dispatch_timeline(YArg, PathElements); Username -> dispatch_timeline(YArg, PathElements);
@@ -106,8 +103,7 @@ dispatch_timeline(YArg, Session, [UrlUsername|_T] = PathElements) ->
end. end.
% just username, list timelines % just username, list timelines
dispatch_timeline(YArg, [UrlUsername]) -> dispatch_timeline(YArg, [Username]) ->
Username = path_element_to_atom(UrlUsername),
HTTPMethod = (YArg#arg.req)#http_request.method, HTTPMethod = (YArg#arg.req)#http_request.method,
case HTTPMethod of case HTTPMethod of
@@ -115,9 +111,7 @@ dispatch_timeline(YArg, [UrlUsername]) ->
_Other -> make_json_405(YArg, [{see_docs, "/ts_api_doc/timelines.html"}]) _Other -> make_json_405(YArg, [{see_docs, "/ts_api_doc/timelines.html"}])
end; end;
dispatch_timeline(YArg, [UrlUsername, UrlTimelineId]) -> dispatch_timeline(YArg, [Username, TimelineId]) ->
Username = path_element_to_atom(UrlUsername),
TimelineId = path_element_to_atom(UrlTimelineId),
HTTPMethod = (YArg#arg.req)#http_request.method, HTTPMethod = (YArg#arg.req)#http_request.method,
case HTTPMethod of case HTTPMethod of
@@ -136,17 +130,14 @@ dispatch_timeline(YArg, _Other) ->
dispatch_entry(YArg, _Session, []) -> dispatch_entry(YArg, _Session, []) ->
make_json_404(YArg, [{see_docs, "/ts_aip_doc/entries.html"}]); make_json_404(YArg, [{see_docs, "/ts_aip_doc/entries.html"}]);
dispatch_entry(YArg, Session, [UrlUsername|_T] = PathElements) -> dispatch_entry(YArg, Session, [Username|_T] = PathElements) ->
Username = path_element_to_atom(UrlUsername),
case Session#ts_api_session.username of case Session#ts_api_session.username of
Username -> dispatch_entry(YArg, PathElements); Username -> dispatch_entry(YArg, PathElements);
_Other -> make_json_404(YArg, [{see_docs, "/ts_api_doc/entries.html"}]) _Other -> make_json_404(YArg, [{see_docs, "/ts_api_doc/entries.html"}])
end. end.
dispatch_entry(YArg, [UrlUsername, UrlTimelineId]) -> dispatch_entry(YArg, [Username, TimelineId]) ->
Username = path_element_to_atom(UrlUsername),
TimelineId = path_element_to_atom(UrlTimelineId),
HTTPMethod = (YArg#arg.req)#http_request.method, HTTPMethod = (YArg#arg.req)#http_request.method,
case HTTPMethod of case HTTPMethod of
@@ -155,9 +146,7 @@ dispatch_entry(YArg, [UrlUsername, UrlTimelineId]) ->
_Other -> make_json_405(YArg, [{see_docs, "/ts_api_doc/entries.html"}]) _Other -> make_json_405(YArg, [{see_docs, "/ts_api_doc/entries.html"}])
end; end;
dispatch_entry(YArg, [UrlUsername, UrlTimelineId, UrlEntryId]) -> dispatch_entry(YArg, [Username, TimelineId, UrlEntryId]) ->
Username = path_element_to_atom(UrlUsername),
TimelineId = path_element_to_atom(UrlTimelineId),
EntryId = list_to_integer(UrlEntryId), % TODO: catch non-numbers EntryId = list_to_integer(UrlEntryId), % TODO: catch non-numbers
HTTPMethod = (YArg#arg.req)#http_request.method, HTTPMethod = (YArg#arg.req)#http_request.method,
@@ -184,8 +173,7 @@ do_login(YArg) ->
lists:keyfind(password, 1, Fields)} of lists:keyfind(password, 1, Fields)} of
% username and password found % username and password found
{{username, UnameField}, {password, Password}} -> {{username, Username}, {password, Password}} ->
Username = list_to_atom(UnameField),
% check the uname, password % check the uname, password
case ts_user:check_credentials(Username, Password) of case ts_user:check_credentials(Username, Password) of
@@ -281,7 +269,11 @@ post_timeline(YArg, Username, TimelineId) ->
EJSON = parse_json_body(YArg), EJSON = parse_json_body(YArg),
% parse into a Timeline record % parse into a Timeline record
TR = ts_json:ejson_to_record(#ts_timeline{}, EJSON), TR = try ts_json:ejson_to_record(#ts_timeline{}, EJSON)
catch _:InputError ->
error_logger:error_report("Bad input: ~p", [InputError]),
throw(make_json_400(YArg))
end,
% set username and timeline id % set username and timeline id
NewRecord = TR#ts_timeline{ref = {Username, TimelineId}}, NewRecord = TR#ts_timeline{ref = {Username, TimelineId}},
@@ -309,12 +301,16 @@ put_timeline(YArg, Username, TimelineId) ->
%{struct, Fields} = EJSON, %{struct, Fields} = EJSON,
% parse into a timeline record % parse into a timeline record
TR = ts_json:ejson_to_record(#ts_timeline{}, EJSON), TR = try ts_json:ejson_to_record(#ts_timeline{}, EJSON)
catch _:InputError ->
error_logger:error_report("Bad input: ~p", [InputError]),
throw(make_json_400(YArg))
end,
% not supported right now, would require changing all the entry keys % not supported right now, would require changing all the entry keys
% check to see if they are changing the timeline id % check to see if they are changing the timeline id
%NewTimelineId = case lists:keyfind(1, timeline_id, Fields) of %NewTimelineId = case lists:keyfind(1, timeline_id, Fields) of
% {timeline_id, Field} -> list_to_atom(Field); % {timeline_id, Field} -> Field;
% false -> TimelineId end, % false -> TimelineId end,
% set username and timeline id % set username and timeline id
@@ -428,7 +424,11 @@ post_entry(YArg, Username, TimelineId) ->
EJSON = parse_json_body(YArg), EJSON = parse_json_body(YArg),
% parse into ts_entry record % parse into ts_entry record
ER = ts_json:ejson_to_record(#ts_entry{}, EJSON), ER = try ts_json:ejson_to_record(#ts_entry{}, EJSON)
catch _:InputError ->
error_logger:error_report("Bad input: ~p", [InputError]),
throw(make_json_400(YArg))
end,
% set username and timeline id % set username and timeline id
NewRecord = ER#ts_entry{ref = {Username, TimelineId, undef}}, NewRecord = ER#ts_entry{ref = {Username, TimelineId, undef}},
@@ -455,7 +455,11 @@ put_entry(YArg, Username, TimelineId, EntryId) ->
EJSON = parse_json_body(YArg), EJSON = parse_json_body(YArg),
% parse into ts_entry record % parse into ts_entry record
ER = ts_json:ejson_to_record(#ts_entry{}, EJSON), ER = try ts_json:ejson_to_record(#ts_entry{}, EJSON)
catch _:InputError ->
error_logger:error_report("Bad input: ~p", [InputError]),
throw(make_json_400(YArg))
end,
% set uername, timeline id, and entry id % set uername, timeline id, and entry id
NewRecord = ER#ts_entry{ref = {Username, TimelineId, EntryId}}, NewRecord = ER#ts_entry{ref = {Username, TimelineId, EntryId}},
@@ -492,10 +496,6 @@ delete_entry(YArg, Username, TimelineId, EntryId) ->
% ======== UTIL METHODS ======== % % ======== UTIL METHODS ======== %
% ============================== % % ============================== %
%% Convert one path element to an atom.
path_element_to_atom(PE) ->
list_to_atom(re:replace(PE, "\\s", "_", [{return, list}])).
parse_json_body(YArg) -> parse_json_body(YArg) ->
case catch json:decode([], binary_to_list(YArg#arg.clidata)) of case catch json:decode([], binary_to_list(YArg#arg.clidata)) of
{done, {ok, EJSON}, _} -> EJSON; {done, {ok, EJSON}, _} -> EJSON;
@@ -547,19 +547,19 @@ make_json_405(YArg) -> make_json_405(YArg, []).
make_json_405(YArg, Fields) -> make_json_405(YArg, Fields) ->
% add default status if not provided % add default status if not provided
F1 = case lists:keyfind(status, 1, Fields) of F1 = case lists:keyfind(status, 1, Fields) of
false -> Fields ++ [{status, method_not_allowed}]; false -> Fields ++ [{status, "method not allowed"}];
_Else -> Fields _Else -> Fields
end, end,
% add the path they requested % add the path they requested
F2 = F1 ++ [{path, (YArg#arg.req)#http_request.path}], % F2 = F1 ++ [{path, io_lib:format("~s", [(YArg#arg.req)#http_request.path])}],
[{status, 405}, {content, "application/json", json:encode({struct, F2})}]. [{status, 405}, {content, "application/json", json:encode({struct, F1})}].
make_json_500(_YArg, Error) -> make_json_500(_YArg, Error) ->
EJSON = {struct, [ EJSON = {struct, [
{status, "internal server error"}, {status, "internal server error"},
{error, io_lib:format("~p", [Error])}]}, {error, io_lib:format("~s", [Error])}]},
[{status, 500}, {content, "application/json", json:encode(EJSON)}]. [{status, 500}, {content, "application/json", json:encode(EJSON)}].
make_json_500(_YArg) -> make_json_500(_YArg) ->
+2 -2
View File
@@ -4,8 +4,8 @@
pwd_salt, pwd_salt,
name, name,
email, email,
join_date%, join_date,
% ext_data % other extensible data ext_data = [] % other extensible data
}). }).
% ts_user.ext_data can be: % ts_user.ext_data can be:
+8 -7
View File
@@ -7,10 +7,11 @@ encode_record(Record) -> lists:flatten(json:encode(record_to_ejson(Record))).
record_to_ejson(Record=#ts_user{}) -> record_to_ejson(Record=#ts_user{}) ->
{struct, [ {struct, [
{id, atom_to_list(Record#ts_user.username)}, {id, Record#ts_user.username},
{name, Record#ts_user.name}, {name, Record#ts_user.name},
{email, Record#ts_user.email}, {email, Record#ts_user.email},
{join_date, encode_datetime(Record#ts_user.join_date)}]}; {join_date, encode_datetime(Record#ts_user.join_date)},
{ext_data, Record#ts_user.ext_data}]};
record_to_ejson(Record=#ts_timeline{}) -> record_to_ejson(Record=#ts_timeline{}) ->
% pull out the username and timeline id % pull out the username and timeline id
@@ -18,8 +19,8 @@ record_to_ejson(Record=#ts_timeline{}) ->
% create the EJSON struct % create the EJSON struct
{struct, [ {struct, [
{user_id, atom_to_list(Username)}, {user_id, Username},
{id, atom_to_list(TimelineId)}, {id, TimelineId},
{created, encode_datetime(Record#ts_timeline.created)}, {created, encode_datetime(Record#ts_timeline.created)},
{description, Record#ts_timeline.desc}]}; {description, Record#ts_timeline.desc}]};
@@ -32,15 +33,15 @@ record_to_ejson(Record=#ts_entry{}) ->
% create the EJSON struct % create the EJSON struct
{struct, [ {struct, [
{user_id, atom_to_list(Username)}, {user_id, Username},
{timeline_id, atom_to_list(TimelineId)}, {timeline_id, TimelineId},
{id, EntryId}, {id, EntryId},
{timestamp, encode_datetime(DateTime)}, {timestamp, encode_datetime(DateTime)},
{mark, Record#ts_entry.mark}, {mark, Record#ts_entry.mark},
{notes, Record#ts_entry.notes}]}. {notes, Record#ts_entry.notes}]}.
encode_datetime({{Year, Month, Day}, {Hour, Minute, Second}}) -> encode_datetime({{Year, Month, Day}, {Hour, Minute, Second}}) ->
lists:flatten(io_lib:format("~4.10.0B-~2.10.0B-~2.10.0BT~2.10.0B:~2.10.0B:~2.10.0B~3.10.0BZ", lists:flatten(io_lib:format("~4.10.0B-~2.10.0B-~2.10.0BT~2.10.0B:~2.10.0B:~2.10.0B.~3.10.0BZ",
[Year, Month, Day, Hour, Minute, Second, 000])). [Year, Month, Day, Hour, Minute, Second, 000])).
ejson_to_record(_Empty=#ts_timeline{}, EJSON) -> ejson_to_record(_Empty=#ts_timeline{}, EJSON) ->