Fixing problems introduced by the model change.

* Many calls to ``ts_ext_data:get_properties/1`` from ``ts_api`` were passing
  the record reference, not the record itself. Fixed.
* Created ``ts_api:put_user/2`` which updates a ``ts_user`` record. This is
  needed specifically for updating the ``liat_timeline`` extended data property.
* Removed unreachable code in ``ts_api:post_entry/3``
* Fixed return value of some ``ts_user`` functions to use the
  ``{Status, Value}`` convention. TODO: make sure all calls are using the same
  convention.
* Fixed error message formatting in ``ts_ext_data:set_property/3``.
* Added clauses to ``ts_json:ejson_to_record/2``,
  ``ts_json:ejson_to_record_strict/2`` and ``ts_json:construct_record/3`` to
  handle the ``ts_user`` record type.
* Added code to ``AppView.loadInitialData`` and ``AppView.selectTimeline`` to
  support the ``last_timeline`` extended data property.
This commit is contained in:
Jonathan Bernard 2011-06-15 16:50:38 -05:00
parent 3999e736be
commit cd182d54c3
16 changed files with 297 additions and 79 deletions

View File

@ -1,6 +1,6 @@
let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0 let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0
argglobal argglobal
edit ~/projects/jdb-labs/timestamper/web-app/www/js/ts.js edit /mnt/secure/projects/jdb-labs/timestamper/web-app/www/index.yaws
setlocal keymap= setlocal keymap=
setlocal noarabic setlocal noarabic
setlocal autoindent setlocal autoindent
@ -26,8 +26,8 @@ setlocal nodiff
setlocal equalprg= setlocal equalprg=
setlocal errorformat= setlocal errorformat=
setlocal expandtab setlocal expandtab
if &filetype != 'javascript' if &filetype != 'erlang'
setlocal filetype=javascript setlocal filetype=erlang
endif endif
setlocal foldcolumn=0 setlocal foldcolumn=0
setlocal foldenable setlocal foldenable
@ -83,8 +83,8 @@ setlocal statusline=
setlocal suffixesadd= setlocal suffixesadd=
setlocal swapfile setlocal swapfile
setlocal synmaxcol=3000 setlocal synmaxcol=3000
if &syntax != 'javascript' if &syntax != 'erlang'
setlocal syntax=javascript setlocal syntax=erlang
endif endif
setlocal tabstop=4 setlocal tabstop=4
setlocal tags= setlocal tags=
@ -95,48 +95,13 @@ setlocal nowinfixwidth
setlocal wrap setlocal wrap
setlocal wrapmargin=0 setlocal wrapmargin=0
silent! normal! zE silent! normal! zE
9,18fold let s:l = 1 - ((0 * winheight(0) + 36) / 72)
20,28fold
30,43fold
45,61fold
63,81fold
86,288fold
290,348fold
350,418fold
420,457fold
459,557fold
559,618fold
620,656fold
9
normal zc
20
normal zc
30
normal zc
45
normal zc
63
normal zc
86
normal zc
290
normal zc
350
normal zc
420
normal zc
459
normal zc
559
normal zc
620
normal zc
let s:l = 3 - ((2 * winheight(0) + 23) / 47)
if s:l < 1 | let s:l = 1 | endif if s:l < 1 | let s:l = 1 | endif
exe s:l exe s:l
normal! zt normal! zt
3 1
normal! 0 normal! 0
lcd /mnt/secure/projects/jdb-labs/timestamper/web-app/www
let &so = s:so_save | let &siso = s:siso_save let &so = s:so_save | let &siso = s:siso_save
doautoall SessionLoadPost doautoall SessionLoadPost
" vim: set ft=vim : " vim: set ft=vim :

View File

@ -0,0 +1,185 @@
let s:so_save = &so | let s:siso_save = &siso | set so=0 siso=0
argglobal
edit /mnt/secure/projects/jdb-labs/timestamper/web-app/src/ts_api.erl
setlocal keymap=
setlocal noarabic
setlocal autoindent
setlocal balloonexpr=
setlocal nobinary
setlocal bufhidden=
setlocal buflisted
setlocal buftype=
setlocal nocindent
setlocal cinkeys=0{,0},0),:,0#,!^F,o,O,e
setlocal cinoptions=
setlocal cinwords=if,else,while,do,for,switch
setlocal comments=s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-
setlocal commentstring=/*%s*/
setlocal complete=.,w,b,u,t,i
setlocal completefunc=
setlocal nocopyindent
setlocal nocursorcolumn
setlocal nocursorline
setlocal define=
setlocal dictionary=
setlocal nodiff
setlocal equalprg=
setlocal errorformat=
setlocal expandtab
if &filetype != 'erlang'
setlocal filetype=erlang
endif
setlocal foldcolumn=0
setlocal foldenable
setlocal foldexpr=0
setlocal foldignore=#
setlocal foldlevel=0
setlocal foldmarker={{{,}}}
setlocal foldmethod=manual
setlocal foldminlines=1
setlocal foldnestmax=20
setlocal foldtext=foldtext()
setlocal formatexpr=
setlocal formatoptions=tcq
setlocal formatlistpat=^\\s*\\d\\+[\\]:.)}\\t\ ]\\s*
setlocal grepprg=
setlocal iminsert=2
setlocal imsearch=2
setlocal include=
setlocal includeexpr=
setlocal indentexpr=
setlocal indentkeys=0{,0},:,0#,!^F,o,O,e
setlocal noinfercase
setlocal iskeyword=@,48-57,_,192-255
setlocal keywordprg=
setlocal nolinebreak
setlocal nolisp
setlocal nolist
setlocal makeprg=
setlocal matchpairs=(:),{:},[:]
setlocal nomodeline
setlocal modifiable
setlocal nrformats=octal,hex
setlocal number
setlocal numberwidth=4
setlocal omnifunc=
setlocal path=
setlocal nopreserveindent
setlocal nopreviewwindow
setlocal quoteescape=\\
setlocal noreadonly
setlocal norightleft
setlocal rightleftcmd=search
setlocal noscrollbind
setlocal shiftwidth=4
setlocal noshortname
setlocal nosmartindent
setlocal softtabstop=0
setlocal nospell
setlocal spellcapcheck=[.?!]\\_[\\])'\"\ \ ]\\+
setlocal spellfile=
setlocal spelllang=en
setlocal statusline=
setlocal suffixesadd=
setlocal swapfile
setlocal synmaxcol=3000
if &syntax != 'erlang'
setlocal syntax=erlang
endif
setlocal tabstop=4
setlocal tags=
setlocal textwidth=80
setlocal thesaurus=
setlocal nowinfixheight
setlocal nowinfixwidth
setlocal wrap
setlocal wrapmargin=0
silent! normal! zE
7,28fold
35,51fold
55,73fold
77,92fold
96,126fold
130,161fold
167,196fold
198,202fold
204,239fold
241,248fold
250,267fold
269,301fold
303,310fold
312,331fold
335,421fold
423,429fold
431,453fold
455,469fold
471,486fold
492,499fold
502,506fold
508,515fold
517,525fold
528,539fold
541,552fold
554,563fold
7
normal zc
35
normal zc
55
normal zc
77
normal zc
96
normal zc
130
normal zc
167
normal zc
198
normal zc
204
normal zo
241
normal zc
250
normal zc
269
normal zc
303
normal zc
312
normal zo
335
normal zc
423
normal zc
431
normal zc
455
normal zc
471
normal zc
492
normal zc
502
normal zc
508
normal zc
517
normal zc
528
normal zc
541
normal zc
554
normal zc
let s:l = 250 - ((25 * winheight(0) + 35) / 71)
if s:l < 1 | let s:l = 1 | endif
exe s:l
normal! zt
250
normal! 0
let &so = s:so_save | let &siso = s:siso_save
doautoall SessionLoadPost
" vim: set ft=vim :
syntax on

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -22,6 +22,7 @@ out(YArg) ->
{'EXIT', Err} -> {'EXIT', Err} ->
% TODO: log error internally % TODO: log error internally
error_logger:error_report("TimeStamper: ~p", [Err]), error_logger:error_report("TimeStamper: ~p", [Err]),
io:format("Error: ~n~p", [Err]),
make_json_500(YArg, Err); make_json_500(YArg, Err);
Other -> Other Other -> Other
end. end.
@ -211,7 +212,7 @@ get_user_summary(YArg, Username) ->
User -> User ->
% get user extended data properties % get user extended data properties
UserExtData = ts_ext_data:get_properties(Username), UserExtData = ts_ext_data:get_properties(User),
% convert to intermediate JSON form % convert to intermediate JSON form
EJSONUser = ts_json:record_to_ejson(User, UserExtData), EJSONUser = ts_json:record_to_ejson(User, UserExtData),
@ -223,7 +224,7 @@ get_user_summary(YArg, Username) ->
lists:map( lists:map(
fun(Timeline) -> fun(Timeline) ->
ts_json:record_to_ejson(Timeline, ts_json:record_to_ejson(Timeline,
ts_ext_data:get_properties(Timeline#ts_timeline.ref)) ts_ext_data:get_properties(Timeline))
end, end,
Timelines)}, Timelines)},
@ -246,6 +247,25 @@ get_user(YArg, Username) ->
User -> make_json_200(YArg, User) User -> make_json_200(YArg, User)
end. end.
put_user(YArg, Username) ->
% parse the POST data
EJSON = parse_json_body(YArg),
{UR, ExtData} =
try ts_user:ejson_to_record_strict(#ts_user{username=Username}, EJSON)
catch throw:{InputError, StackTrace} ->
error_logger:error_report("Bad input in put_user/2: ~p",
[InputError]),
throw(make_json_400(YArg, [{request_error, InputError}]))
end,
% update the record (we do not support creating users via the API right now
{ok, UpdatedRec} = ts_user:update(UR, ExtData),
% return a 200
make_json_200(YArg, UpdatedRec).
list_timelines(YArg, Username) -> list_timelines(YArg, Username) ->
% pull out the POST data % pull out the POST data
QueryData = yaws_api:parse_query(YArg), QueryData = yaws_api:parse_query(YArg),
@ -270,7 +290,7 @@ list_timelines(YArg, Username) ->
EJSONTimelines = {array, lists:map( EJSONTimelines = {array, lists:map(
fun (Timeline) -> fun (Timeline) ->
ts_json:record_to_ejson(Timeline, ts_json:record_to_ejson(Timeline,
ts_ext_data:get_properties(Timeline#ts_timeline.ref)) ts_ext_data:get_properties(Timeline))
end, end,
Timelines)}, Timelines)},
@ -301,7 +321,7 @@ put_timeline(YArg, Username, TimelineId) ->
% we can not parse it, tell the user % we can not parse it, tell the user
catch throw:{InputError, _StackTrace} -> catch throw:{InputError, _StackTrace} ->
error_logger:error_report("Bad input: ~p", [InputError]), error_logger:error_report("Bad input: ~p", [InputError]),
throw(make_json_400(YArg, {request_error, InputError})) throw(make_json_400(YArg, [{request_error, InputError}]))
end, end,
% write the changes. % write the changes.
@ -355,7 +375,7 @@ list_entries(YArg, Username, TimelineId) ->
EJSONEntries = {array, lists:map( EJSONEntries = {array, lists:map(
fun (Entry) -> fun (Entry) ->
ts_json:record_to_ejson(Entry, ts_json:record_to_ejson(Entry,
ts_ext_data:get_properties(Entry#ts_entry.ref)) ts_ext_data:get_properties(Entry))
end, end,
Entries)}, Entries)},
@ -391,7 +411,7 @@ list_entries(YArg, Username, TimelineId) ->
EJSONEntries = {array, lists:map( EJSONEntries = {array, lists:map(
fun (Entry) -> fun (Entry) ->
ts_json:record_to_ejson(Entry, ts_json:record_to_ejson(Entry,
ts_ext_data:get_properties(Entry#ts_entry.ref)) ts_ext_data:get_properties(Entry))
end, end,
Entries)}, Entries)},
@ -418,7 +438,7 @@ post_entry(YArg, Username, TimelineId) ->
#ts_entry{ref = {Username, TimelineId, undefined}}, EJSON) #ts_entry{ref = {Username, TimelineId, undefined}}, EJSON)
catch _:InputError -> catch _:InputError ->
error_logger:error_report("Bad input: ~p", [InputError]), error_logger:error_report("Bad input: ~p", [InputError]),
throw(make_json_400(YArg, {request_error, InputError})) throw(make_json_400(YArg, [{request_error, InputError}]))
end, end,
case ts_entry:new(ER, ExtData) of case ts_entry:new(ER, ExtData) of
@ -427,14 +447,8 @@ post_entry(YArg, Username, TimelineId) ->
[{status, 201}, make_json_200(YArg, CreatedRecord)]; [{status, 201}, make_json_200(YArg, CreatedRecord)];
% will not create, record exists
{error, {record_exists, ExistingRecord}} ->
JSONResponse = json:encode(ts_json:record_to_ejson(ExistingRecord)),
{content, "application/json", JSONResponse};
OtherError -> OtherError ->
error_logger:error_report("TimeStamper: Could not create entry: ~p", [OtherError]), error_logger:error_report("Could not create entry: ~p", [OtherError]),
make_json_500(YArg, OtherError) make_json_500(YArg, OtherError)
end. end.
@ -486,8 +500,9 @@ parse_json_body(YArg) ->
%% Create a JSON 200 response. %% Create a JSON 200 response.
make_json_200(_YArg, Record) -> make_json_200(_YArg, Record) ->
RecordExtData = ts_ext_data:get_properties(element(2, Record)), RecordExtData = ts_ext_data:get_properties(Record),
JSONResponse = json:encode(ts_json:record_to_ejson(Record, RecordExtData)), EJSON = ts_json:record_to_ejson(Record, RecordExtData),
JSONResponse = json:encode(EJSON),
{content, "application/json", JSONResponse}. {content, "application/json", JSONResponse}.
make_json_400(YArg) -> make_json_400(YArg, []). make_json_400(YArg) -> make_json_400(YArg, []).
@ -532,14 +547,14 @@ make_json_405(_YArg, Fields) ->
end, end,
% add the path they requested % add the path they requested
% F2 = F1 ++ [{path, io_lib:format("~s", [(YArg#arg.req)#http_request.path])}], % F2 = F1 ++ [{path, io_lib:format("~p", [(YArg#arg.req)#http_request.path])}],
[{status, 405}, {content, "application/json", json:encode({struct, F1})}]. [{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("~s", [Error])}]}, {error, lists:flatten(io_lib:format("~p", [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) ->

View File

@ -100,10 +100,9 @@ list(Query, Start, Length) ->
% should be wrapped in a transaction % should be wrapped in a transaction
do_set_ext_data(Record, ExtData) when is_list(ExtData) -> do_set_ext_data(Record, ExtData) when is_list(ExtData) ->
Ref = element(2, Record),
lists:foreach( lists:foreach(
fun({Key, Val}) -> fun({Key, Val}) ->
{atomic, ok} = ts_ext_data:set_property(Ref, Key, Val) {atomic, ok} = ts_ext_data:set_property(Record, Key, Val)
end, end,
ExtData), ExtData),
ok. ok.

View File

@ -19,7 +19,7 @@ new(ER = #ts_entry{}, ExtData) when is_list(ExtData) ->
NewRow = do_new(ER), NewRow = do_new(ER),
ts_common:do_set_ext_data(ER, ExtData), ts_common:do_set_ext_data(ER, ExtData),
NewRow end), NewRow end),
NewRow. {ok, NewRow}.
do_new(ER = #ts_entry{}) -> do_new(ER = #ts_entry{}) ->
{Username, TimelineId, _} = ER#ts_entry.ref, {Username, TimelineId, _} = ER#ts_entry.ref,

View File

@ -21,8 +21,8 @@ set_property(Rec=#ts_timeline{}, entry_exclusions, ExclusionList) ->
do_set_property(Rec#ts_timeline.ref, entry_exclusions, ExclusionList); do_set_property(Rec#ts_timeline.ref, entry_exclusions, ExclusionList);
set_property(Rec, Key, _Value) -> set_property(Rec, Key, _Value) ->
throw(io_lib:format("Property '~s' not available for a ~s record.", throw(lists:flatten(io_lib:format("Property '~s' not available for a ~s record.",
[Key, element(1, Rec)])). [Key, element(1, Rec)]))).
get_property(Ref, PropKey) -> get_property(Ref, PropKey) ->
{atomic, Result} = mnesia:transaction(fun() -> {atomic, Result} = mnesia:transaction(fun() ->

View File

@ -81,6 +81,16 @@ ejson_to_record(Empty, Ref, EJSON) ->
Constructed = ejson_to_record(Empty, EJSON), Constructed = ejson_to_record(Empty, EJSON),
setelement(2, Constructed, Ref). setelement(2, Constructed, Ref).
ejson_to_record_strict(Empty=#ts_user{}, EJSON) ->
Constructed = ejson_to_record(Empty, EJSON),
case Constructed of
#ts_user{name = undefined} -> throw("Missing user 'name' field.");
#ts_user{email = undefined} -> throw("Missing user 'email' field.");
#ts_user{join_date = undefined} ->
throw("Missing user 'join_date' field.");
_Other -> Constructed
end;
ejson_to_record_strict(Empty=#ts_timeline{}, EJSON) -> ejson_to_record_strict(Empty=#ts_timeline{}, EJSON) ->
Constructed = ejson_to_record(Empty, EJSON), Constructed = ejson_to_record(Empty, EJSON),
case Constructed of case Constructed of
@ -107,22 +117,55 @@ ejson_to_record_strict(Empty, Ref, EJSON) ->
Constructed = ejson_to_record_strict(Empty, EJSON), Constructed = ejson_to_record_strict(Empty, EJSON),
setelement(2, Constructed, Ref). setelement(2, Constructed, Ref).
construct_record(Timeline=#ts_timeline{}, [{Key, Val}|Fields], ExtData) -> construct_record(User=#ts_user{}, [{Key, Value}|Fields], ExtData) ->
case Key of case Key of
created -> construct_record( id -> construct_record(User#ts_user{username = Value},
Timeline#ts_timeline{created = decode_datetime(Val)},
Fields, ExtData); Fields, ExtData);
description -> construct_record(Timeline#ts_timeline{desc = Val}, name -> construct_record(User#ts_user{name = Value}, Fields, ExtData);
join_date -> construct_record(
User#ts_user{join_date = decode_datetime(Value)},
Fields, ExtData); Fields, ExtData);
_Other -> _Other ->
ExtDataProp = ejson_to_ext_data({Key, Val}), ExtDataProp = ejson_to_ext_data({Key, Value}),
construct_record(User, Fields, [ExtDataProp|ExtData])
end;
construct_record(Timeline=#ts_timeline{}, [{Key, Value}|Fields], ExtData) ->
case Key of
user_id ->
{_, TimelineId} = Timeline#ts_timeline.ref,
construct_record(Timeline#ts_timeline{ref = {Value, TimelineId}},
Fields, ExtData);
id ->
{Username, _} = Timeline#ts_timeline.ref,
construct_record(Timeline#ts_timeline{ref = {Username, Value}},
Fields, ExtData);
created -> construct_record(
Timeline#ts_timeline{created = decode_datetime(Value)},
Fields, ExtData);
description -> construct_record(Timeline#ts_timeline{desc = Value},
Fields, ExtData);
_Other ->
ExtDataProp = ejson_to_ext_data({Key, Value}),
construct_record(Timeline, Fields, [ExtDataProp|ExtData]) construct_record(Timeline, Fields, [ExtDataProp|ExtData])
end; end;
construct_record(Entry=#ts_entry{}, [{Key, Value}|Fields], ExtData) -> construct_record(Entry=#ts_entry{}, [{Key, Value}|Fields], ExtData) ->
case Key of case Key of
user_id ->
{_, TimelineId, EntryId} = Entry#ts_entry.ref,
construct_record(Entry#ts_entry{ref = {Value, TimelineId, EntryId}},
Fields, ExtData);
timeline_id ->
{Username, _, EntryId} = Entry#ts_entry.ref,
construct_record(Entry#ts_entry{ref = {Username, Value, EntryId}},
Fields, ExtData);
id ->
{Username, TimelineId, _} = Entry#ts_entry.ref,
construct_record(Entry#ts_entry{ref = {Username, TimelineId, Value}},
Fields, ExtData);
timestamp -> construct_record( timestamp -> construct_record(
Entry#ts_entry{timestamp = calendar:datetime_to_gregoraian_seconds( Entry#ts_entry{timestamp = calendar:datetime_to_gregorian_seconds(
decode_datetime(Value))}, decode_datetime(Value))},
Fields, ExtData); Fields, ExtData);
mark -> construct_record(Entry#ts_entry{mark=Value}, Fields, ExtData); mark -> construct_record(Entry#ts_entry{mark=Value}, Fields, ExtData);

View File

@ -13,31 +13,34 @@ create_table(TableOpts) ->
% expects the password in clear % expects the password in clear
new(UR = #ts_user{}) -> new(UR = #ts_user{}) ->
{atomic, Result} = mnesia:transaction(fun() -> do_new(UR) end), {atomic, Result} = mnesia:transaction(fun() -> do_new(UR) end),
Result. {ok, Result}.
new(UR = #ts_user{}, ExtData) -> new(UR = #ts_user{}, ExtData) ->
{atomic, Result} = mnesia:transaction(fun() -> {atomic, Result} = mnesia:transaction(fun() ->
NewUser = do_new(UR), NewUser = do_new(UR),
ts_common:do_set_ext_data(UR, ExtData), ts_common:do_set_ext_data(UR, ExtData),
NewUser end), NewUser end),
Result. {ok, Result}.
do_new(UR = #ts_user{}) -> do_new(UR = #ts_user{}) ->
case mnesia:read(ts_user, UR#ts_user.username) of case mnesia:read(ts_user, UR#ts_user.username) of
[ExistingRecord] -> {error, {record_exists, ExistingRecord}}; [ExistingRecord] -> {error, {record_exists, ExistingRecord}};
[] -> mnesia:write(hash_input_record(UR)) [] ->
NewRec = hash_input_record(UR),
mnesia:write(NewRec),
NewRec
end. end.
update(UR = #ts_user{}) -> update(UR = #ts_user{}) ->
{atomic, Result} = mnesia:transaction(fun() -> do_update(UR) end), {atomic, Result} = mnesia:transaction(fun() -> do_update(UR) end),
Result. {ok, Result}.
update(UR = #ts_user{}, ExtData) -> update(UR = #ts_user{}, ExtData) ->
{atomic, Result} = mnesia:transaction(fun() -> {atomic, Result} = mnesia:transaction(fun() ->
UpdatedUser = do_update(UR), UpdatedUser = do_update(UR),
ts_common:do_set_ext_data(UR, ExtData), ts_common:do_set_ext_data(UR, ExtData),
UpdatedUser end), UpdatedUser end),
Result. {ok, Result}.
do_update(UR = #ts_user{}) -> do_update(UR = #ts_user{}) ->
case mnesia:read(ts_user, UR#ts_user.username) of case mnesia:read(ts_user, UR#ts_user.username) of
@ -48,7 +51,8 @@ do_update(UR = #ts_user{}) ->
undefined -> UpdatedRecord; undefined -> UpdatedRecord;
_Password -> hash_input_record(UpdatedRecord) _Password -> hash_input_record(UpdatedRecord)
end, end,
mnesia:write(HashedRecord) mnesia:write(HashedRecord),
HashedRecord
end. end.
lookup(Username) -> lookup(Username) ->

View File

@ -535,7 +535,10 @@ $(document).ready(function(){
url: '/ts_api/app/user_summary/' + username, url: '/ts_api/app/user_summary/' + username,
async: false}).responseText); async: false}).responseText);
data.initialTimelineId = data.timelines[0].id; // look for the last used timeline, default to first timeline
data.initialTimelineId =
data.user.last_timeline || data.timelines[0].id
data.entries = jQuery.parseJSON($.ajax({ data.entries = jQuery.parseJSON($.ajax({
url: '/ts_api/entries/' + username + '/' + url: '/ts_api/entries/' + username + '/' +
data.initialTimelineId, data.initialTimelineId,
@ -555,6 +558,10 @@ $(document).ready(function(){
// set the timeline on the EntryList // set the timeline on the EntryList
this.entries.collection.timeline = tl; this.entries.collection.timeline = tl;
// update the last_timeline field of the user model
this.user.model.set('last_timeline', tl.get('id');
this.user.model.save();
// refresh TimelineListView // refresh TimelineListView
this.timelines.view.render(); this.timelines.view.render();