kvs_feed.erl 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. -module(kvs_feed).
  2. -author('Maxim Sokhatsky').
  3. -author('Andrii Zadorozhnii').
  4. -copyright('Synrc Research Center, s.r.o.').
  5. -compile(export_all).
  6. -include_lib("kvs/include/kvs.hrl").
  7. -include_lib("kvs/include/feeds.hrl").
  8. -include_lib("kvs/include/users.hrl").
  9. -include_lib("kvs/include/groups.hrl").
  10. -include_lib("kvs/include/feed_state.hrl").
  11. -define(CACHED_ENTRIES, 20).
  12. init(Backend) ->
  13. ?CREATE_TAB(feed),
  14. ?CREATE_TAB(entry),
  15. ?CREATE_TAB(comment),
  16. Backend:add_table_index(entry, feed_id),
  17. Backend:add_table_index(entry, entry_id),
  18. Backend:add_table_index(entry, from),
  19. Backend:add_table_index(comment, entry_id),
  20. Backend:add_table_index(comment, author_id),
  21. ok.
  22. create() ->
  23. FId = kvs:next_id("feed", 1),
  24. ok = kvs:put(#feed{id = FId} ),
  25. FId.
  26. comments_count(user, Uid) -> case kvs:get(user_etries_count, Uid) of {error,_} -> 0; {ok, UEC} -> UEC#user_etries_count.comments end;
  27. comments_count(entry, Eid) -> case kvs:get(entry, Eid) of {error,_} -> 0; {ok, E} -> comments_count([E],0) end;
  28. comments_count(product, Pid)->case kvs:get(product, Pid) of {error,_}->0; {ok, P} -> comments_count([P], 0) end;
  29. comments_count([], Acc) -> Acc;
  30. comments_count([E|T], Acc) ->
  31. C = case lists:keyfind(comments, 1, element(#iterator.feeds, E)) of false -> 0;
  32. {_, Fid} -> case kvs:get(feed, Fid) of {error,_} -> 0;
  33. {ok, Feed } -> Feed#feed.entries_count
  34. + comments_count(kvs:entries(Feed, comment, undefined), 0) end end,
  35. comments_count(T, C + Acc).
  36. add_like(Fid, Eid, Uid) ->
  37. Write_one_like = fun(Next) ->
  38. Self_id = kvs:next_id("one_like", 1),
  39. kvs:put(#one_like{ % add one like
  40. id = Self_id,
  41. user_id = Uid,
  42. entry_id = Eid,
  43. feed_id = Fid,
  44. created_time = now(),
  45. next = Next
  46. }),
  47. Self_id
  48. end,
  49. % add entry - like
  50. case kvs:get(entry_likes, Eid) of
  51. {ok, ELikes} ->
  52. kvs:put(ELikes#entry_likes{
  53. one_like_head = Write_one_like(ELikes#entry_likes.one_like_head),
  54. total_count = ELikes#entry_likes.total_count + 1
  55. });
  56. {error, _} ->
  57. kvs:put(#entry_likes{
  58. entry_id = Eid,
  59. one_like_head = Write_one_like(undefined),
  60. total_count = 1
  61. })
  62. end,
  63. % add user - like
  64. case kvs:get(user_likes, Uid) of
  65. {ok, ULikes} ->
  66. kvs:put(ULikes#user_likes{
  67. one_like_head = Write_one_like(ULikes#user_likes.one_like_head),
  68. total_count = ULikes#user_likes.total_count + 1
  69. });
  70. {error, _} ->
  71. kvs:put(#user_likes{
  72. user_id = Uid,
  73. one_like_head = Write_one_like(undefined),
  74. total_count = 1
  75. })
  76. end.
  77. entries_count(Uid) ->
  78. case kvs:get(user_etries_count, Uid) of
  79. {ok, UEC} -> UEC#user_etries_count.entries;
  80. {error, _} -> 0 end.
  81. edit_entry(FeedId, EId, NewDescription) ->
  82. case kvs:get(entry,{EId, FeedId}) of
  83. {ok, OldEntry} ->
  84. NewEntryRaw = OldEntry#entry{description = NewDescription},
  85. NewEntry = feedformat:format(NewEntryRaw),
  86. kvs:put(NewEntry);
  87. {error, Reason}-> {error, Reason} end.
  88. like_list(undefined) -> [];
  89. like_list(Id) -> {ok, OneLike} = kvs:get(one_like, Id), [OneLike] ++ like_list(OneLike#one_like.next).
  90. like_list(undefined, _) -> [];
  91. like_list(_, 0) -> [];
  92. like_list(Id, N) -> {ok, OneLike} = kvs:get(one_like, Id), [OneLike] ++ like_list(OneLike#one_like.next, N-1).
  93. entry_likes(Entry_id) ->
  94. case kvs:get(entry_likes, Entry_id) of
  95. {ok, Likes} -> like_list(Likes#entry_likes.one_like_head);
  96. {error, _} -> [] end.
  97. entry_likes_count(Entry_id) ->
  98. case kvs:get(entry_likes, Entry_id) of
  99. {ok, Likes} -> Likes#entry_likes.total_count;
  100. {error, _} -> 0 end.
  101. user_likes_count(UserId) ->
  102. case kvs:get(user_likes, UserId) of
  103. {ok, Likes} -> Likes#user_likes.total_count;
  104. {error, _} -> 0 end.
  105. user_likes(UserId) ->
  106. case kvs:get(user_likes, UserId) of
  107. {ok, Likes} -> like_list(Likes#user_likes.one_like_head);
  108. {error, _} -> [] end.
  109. user_likes(UserId, {Page, PageAmount}) ->
  110. case kvs:get(user_likes, UserId) of
  111. {ok, Likes} -> lists:nthtail((Page-1)*PageAmount, like_list(Likes#user_likes.one_like_head, PageAmount*Page));
  112. {error, _} -> [] end.
  113. %% MQ API
  114. handle_notice([kvs_feed, _, Owner, entry, Eid, add],
  115. [#entry{feed_id=Fid}=Entry|_],
  116. #state{owner=Owner} = S) ->
  117. case lists:keyfind(Fid,2, S#state.feeds) of false -> skip;
  118. {_,_} ->
  119. error_logger:info_msg("[kvs_feed] => Add entry ~p to feed ~p.", [Eid, Fid]),
  120. E = Entry#entry{id = {Eid, Fid}, entry_id = Eid, feeds=[comments]},
  121. Added = case kvs:add(E) of {error, Err}-> {error,Err}; {ok, En} -> En end,
  122. msg:notify([kvs_feed, entry, {Eid, Fid}, added], [Added]) end,
  123. {noreply, S};
  124. handle_notice([kvs_feed,_, Owner, entry, {Eid, FeedName}, edit],
  125. [#entry{}=Entry],
  126. #state{owner=Owner, feeds=Feeds}=S) ->
  127. case lists:keyfind(FeedName,1,Feeds) of false -> skip;
  128. {_,Fid}-> case kvs:get(entry, {Eid, Fid}) of {error,_}-> skip;
  129. {ok, E} ->
  130. error_logger:info_msg("[kvs_feed] => Update entry ~p in feed ~p", [Eid, Fid]),
  131. Upd = E#entry{description=Entry#entry.description,
  132. title = Entry#entry.title,
  133. media = Entry#entry.media,
  134. etc = Entry#entry.etc,
  135. type = Entry#entry.type},
  136. kvs:put(Upd),
  137. msg:notify([kvs_feed, entry, {Eid, Fid}, updated], [Upd]) end end,
  138. {noreply, S};
  139. handle_notice([kvs_feed,_, Owner, entry, {Eid,Fid}=Id, delete],
  140. [],
  141. #state{owner=Owner, feeds=Feeds} = State) ->
  142. case lists:keyfind(Fid,2,Feeds) of false -> skip;
  143. _ ->
  144. error_logger:info_msg("[kvs_feed] => Remove entry ~p from feed ~p", [Id, Fid]),
  145. kvs:remove(entry, Id),
  146. msg:notify([kvs_feed, entry, Id, deleted], [#entry{id=Id, entry_id=Eid, feed_id=Fid}]) end,
  147. {noreply, State};
  148. handle_notice([kvs_feed, Owner, delete],
  149. [#entry{entry_id=Eid}=E],
  150. #state{owner=Owner}=State) ->
  151. error_logger:info_msg("[kvs_feed] Delete all entries ~p ~p", [E#entry.id, Owner]),
  152. [msg:notify([kvs_feed, RoutingType, To, entry, {Eid,Fid}, delete],[])
  153. || #entry{feed_id=Fid, to={RoutingType, To}} <- kvs:all_by_index(entry, entry_id, Eid)],
  154. Removed = case kvs:remove(entry, {Eid, ?FEED(entry)}) of {error,E} -> {error,E}; ok -> E end,
  155. msg:notify([kvs_feed, entry, {Eid, ?FEED(entry)}, deleted], [Removed]),
  156. {noreply, State};
  157. handle_notice([kvs_feed,_,Owner,comment,_,add],
  158. [#comment{entry_id={_,Fid}}=C],
  159. #state{owner=Owner, feeds=Feeds} = S) ->
  160. case lists:keyfind(Fid,2,Feeds) of false -> skip;
  161. {_,_}->
  162. error_logger:info_msg("[kvs_feed] ~p Add comment ~p", [Owner, C#comment.id]),
  163. Added = case kvs:add(C) of {error, E} -> {error, E}; {ok, Cm} -> Cm end,
  164. msg:notify([kvs_feed, comment, C#comment.id, added], [Added])
  165. end,
  166. {noreply, S};
  167. handle_notice(["kvs_feed","likes", _, _, "add_like"] = Route, % _, _ is here beacause of the same message used for comet update
  168. Message, #state{owner = Owner, type =Type} = State) ->
  169. error_logger:info_msg("queue_action(~p): add_like: Owner=~p, Route=~p, Message=~p", [self(), {Type, Owner}, Route, Message]),
  170. {UId, E} = Message,
  171. {EId, FId} = E#entry.id,
  172. kvs_feed:add_like(FId, EId, UId),
  173. {noreply, State};
  174. handle_notice(_Route, _Message, State) ->
  175. %error_logger:error_msg("~p ===> Unknown FEED notice ~p", [State#state.owner, Route]),
  176. {noreply, State}.