%% @author Marc Worrell %% @copyright 2010 Marc Worrell %% Date: 2010-01-15 %% @doc Simple comment module. Adds comments to any rsc. %% Copyright 2010 Marc Worrell %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -module(mod_comment). -author("Marc Worrell "). -mod_title("Comments"). -mod_description("Comments for pages. Implements a simple comment system with comments stored locally."). -mod_depends([admin, base]). -mod_provides([comment]). %% gen_server exports -export([init/1]). %% interface functions -export([ event/2, observe_search_query/2, observe_rsc_merge/2, observe_admin_menu/3 ]). -include_lib("zotonic_core/include/zotonic.hrl"). -include_lib("zotonic_mod_admin/include/admin_menu.hrl"). %% @doc Handle the submit event of a new comment event(#submit{message={newcomment, Args}, form=FormId}, Context) -> {id, Id} = proplists:lookup(id, Args), case z_auth:is_auth(Context) of false -> Name = z_context:get_q_validated(<<"name">>, Context), Email = z_context:get_q_validated(<<"mail">>, Context); true -> Name = <<"">>, Email = <<"">> end, Message = z_context:get_q_validated(<<"message">>, Context), Is_visible = case m_config:get_value(?MODULE, moderate, Context) of <<"1">> -> false; _Else -> true end, case m_comment:insert(Id, Name, Email, Message, Is_visible, Context) of {ok, CommentId} -> CommentsListElt = proplists:get_value(comments_list, Args, "comments-list"), CommentTemplate = proplists:get_value(comment_template, Args, "_comments_comment.tpl"), Comment = m_comment:get(CommentId, Context), Props = [ {id, Id}, {comment, Comment}, {creator, m_rsc:p(Id, creator_id, Context)}, {hidden, true} ], Html = z_template:render(CommentTemplate, Props, Context), Context1 = z_render:insert_bottom(CommentsListElt, Html, Context), Context2 = case Is_visible of true -> z_render:wire([ {set_value, [{selector, <<"#", FormId/binary, " textarea[name=\"message\"]">>}, {value, <<>>}]}, {set_value, [{selector, <<"#", FormId/binary, " input[name=\"message\"]">>}, {value, <<>>}]}, {fade_in, [{target, "comment-"++integer_to_list(CommentId)}]} ], Context1); false -> Context1 end, case z_convert:to_bool(proplists:get_value(do_redirect, Args, true)) of true -> z_render:wire({redirect, [{location, "#comment-"++integer_to_list(CommentId)}]}, Context2); false -> Context2 end; {error, _} -> Context end. %% @doc Return the list of recent comments. Returned values are the complete records. observe_search_query(#search_query{search={recent_comments, []}, offsetlimit=OffsetLimit}, Context) -> m_comment:search({recent_comments, []}, OffsetLimit, Context); observe_search_query(_, _Context) -> undefined. %% @doc Move all comments from one resource to another observe_rsc_merge(#rsc_merge{loser_id=LoserId, winner_id=WinnerId}, Context) -> m_comment:merge(WinnerId, LoserId, Context). %% @doc Check the installation of the comment table. A bit more complicated because 0.1 and 0.2 had a table %% in the default installer, this module installs a different table. init(Context) -> ok = z_db:transaction(fun install1/1, Context), z_depcache:flush(Context), ok. install1(Context) -> ok = remove_old_comment_rsc_fields(Context), ok = remove_old_rating_table(Context), ok = install_comment_table(z_db:table_exists(comment, Context), Context), ok. remove_old_rating_table(Context) -> case z_db:table_exists(rating, Context) of false -> ok; true -> case z_db:column_names(rating, Context) of [comment_id,created,id,ip_address,rsc_id,visitor_id] -> z_db:q("drop table rating", Context), ok; _ -> ok end end. install_comment_table(true, Context) -> % Check for old table case z_db:column_names(comment, Context) of [created,creator_id,id,ip_address,notify_id,props,rating,rsc_id] -> z_db:q("drop table comment", Context), install_comment_table(false, Context); [created,id,email,gravatar_code,ip_address,is_visible,keep_informed, name,props,rsc_id,user_agent,user_id,visitor_id] -> z_db:q("alter table comment drop column visitor_id cascade, " "add column persistent_id character varying (32) ", Context), z_db:q("create index comment_persistent_id_key on comment(persistent_id)", Context), ok; _ -> ok end; install_comment_table(false, Context) -> z_db:q(" create table comment ( id serial not null, is_visible boolean not null default true, rsc_id int not null, user_id int, persistent_id character varying(32), gravatar_code character varying(40) not null default ''::character varying, email character varying(80) not null default ''::character varying, name character varying(80) not null default ''::character varying, user_agent character varying(250) not null default ''::character varying, ip_address character varying(40) not null default ''::character varying, keep_informed boolean not null default false, props bytea, created timestamp with time zone not null default now(), constraint comment_pkey primary key (id), constraint fk_comment_rsc_id foreign key (rsc_id) references rsc(id) on delete cascade on update cascade, constraint fk_comment_user_id foreign key (user_id) references rsc(id) on delete set null on update cascade ) ", Context), Indices = [ {"fki_comment_rsc_id", "rsc_id"}, {"fki_comment_user_id", "user_id"}, {"fki_comment_ip_address", "ip_address"}, {"comment_persistent_id_key", "persistent_id"}, {"comment_rsc_created_key", "rsc_id, created"}, {"comment_created_key", "created"} ], [ z_db:q("create index "++Name++" on comment ("++Cols++")", Context) || {Name, Cols} <- Indices ], ok. %% @doc In the 0.1.0 and 0.2.0 releases we had some pivot information in the rsc table. Remove this. remove_old_comment_rsc_fields(Context) -> Cols = z_db:column_names(rsc, Context), R = [], R1 = case lists:member(comment_by, Cols) of true -> ["drop column comment_by"|R]; false -> R end, R2 = case lists:member(comments, Cols) of true -> ["drop column comments"|R1]; false -> R1 end, R3 = case lists:member(rating, Cols) of true -> ["drop column rating"|R2]; false -> R2 end, R4 = case lists:member(rating_count, Cols) of true -> ["drop column rating_count"|R3]; false -> R3 end, case R4 of [] -> ok; L -> z_db:q("alter table rsc " ++ string:join(L, ", "), Context), ok end. observe_admin_menu(#admin_menu{}, Acc, Context) -> [ #menu_item{id=admin_comments, parent=admin_content, label=?__("Comments", Context), url={admin_comments}, visiblecheck={acl, use, ?MODULE}}, #menu_item{id=admin_comments_settings, parent=admin_modules, label=?__("Comment settings", Context), url={admin_comments_settings}, visiblecheck={acl, use, ?MODULE}} |Acc].