Merge branch 'api-redesign' into client-redesign
This commit is contained in:
commit
cf5153c90b
BIN
db/test/id_counter.DCL
Normal file
BIN
db/test/id_counter.DCL
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
db/test/ts_timeline.DCL
Normal file
BIN
db/test/ts_timeline.DCL
Normal file
Binary file not shown.
Binary file not shown.
@ -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) ->
|
||||||
|
@ -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:
|
||||||
|
@ -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) ->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user