PageRenderTime 25ms CodeModel.GetById 2ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/mod_comment/mod_comment.erl

http://github.com/zotonic/zotonic
Erlang | 215 lines | 166 code | 22 blank | 27 comment | 2 complexity | 01de173975342003a5db59a8e054c40c MD5 | raw file
  1%% @author Marc Worrell <marc@worrell.nl>
  2%% @copyright 2010 Marc Worrell
  3%% Date: 2010-01-15
  4%% @doc Simple comment module. Adds comments to any rsc.
  5
  6%% Copyright 2010 Marc Worrell
  7%%
  8%% Licensed under the Apache License, Version 2.0 (the "License");
  9%% you may not use this file except in compliance with the License.
 10%% You may obtain a copy of the License at
 11%% 
 12%%     http://www.apache.org/licenses/LICENSE-2.0
 13%% 
 14%% Unless required by applicable law or agreed to in writing, software
 15%% distributed under the License is distributed on an "AS IS" BASIS,
 16%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 17%% See the License for the specific language governing permissions and
 18%% limitations under the License.
 19
 20-module(mod_comment).
 21-author("Marc Worrell <marc@worrell.nl>").
 22
 23-mod_title("Comments").
 24-mod_description("Comments for pages. Implements a simple comment system with comments stored locally.").
 25-mod_depends([admin, base]).
 26-mod_provides([comment]).
 27
 28%% gen_server exports
 29-export([init/1]).
 30
 31%% interface functions
 32-export([
 33    event/2,
 34    observe_search_query/2,
 35    observe_rsc_merge/2,
 36    observe_admin_menu/3
 37]).
 38
 39-include_lib("zotonic.hrl").
 40-include_lib("modules/mod_admin/include/admin_menu.hrl").
 41
 42
 43%% @doc Handle the submit event of a new comment
 44event(#submit{message={newcomment, Args}, form=FormId}, Context) ->
 45    {id, Id} = proplists:lookup(id, Args),
 46    case z_auth:is_auth(Context) of
 47        false ->
 48            Name = z_context:get_q_validated("name", Context),
 49            Email = z_context:get_q_validated("mail", Context);
 50        true ->
 51            Name = "",
 52            Email = ""
 53    end,
 54    Message = z_context:get_q_validated("message", Context),
 55    Is_visible = case m_config:get_value(comments, moderate, Context) of <<"1">> -> false; _Else -> true end,
 56    case m_comment:insert(Id, Name, Email, Message, Is_visible, Context) of
 57        {ok, CommentId} ->
 58            CommentsListElt = proplists:get_value(comments_list, Args, "comments-list"),
 59            CommentTemplate = proplists:get_value(comment_template, Args, "_comments_comment.tpl"),
 60            Comment = m_comment:get(CommentId, Context),
 61            Props = [
 62                {id, Id},
 63                {comment, Comment},
 64                {creator, m_rsc:p(Id, creator_id, Context)},
 65                {hidden, true}
 66            ],
 67            Html = z_template:render(CommentTemplate, Props, Context),
 68            Context1 = z_render:insert_bottom(CommentsListElt, Html, Context),
 69            Context2 = case Is_visible of
 70			   true ->
 71			       z_render:wire([
 72					      {set_value, [{selector, "#"++FormId++" textarea[name=\"message\"]"}, {value, ""}]},
 73					      {set_value, [{selector, "#"++FormId++" input[name=\"message\"]"}, {value, ""}]},
 74					      {fade_in, [{target, "comment-"++integer_to_list(CommentId)}]}
 75					     ], Context1);
 76			   false ->
 77			       Context1
 78		       end,
 79            case z_convert:to_bool(proplists:get_value(do_redirect, Args, true)) of
 80                true -> z_render:wire({redirect, [{location, "#comment-"++integer_to_list(CommentId)}]}, Context2);
 81                false -> Context2
 82            end;
 83        {error, _} ->
 84            Context
 85    end.
 86
 87
 88%% @doc Return the list of recent comments.  Returned values are the complete records.
 89observe_search_query(#search_query{search={recent_comments, []}, offsetlimit=OffsetLimit}, Context) ->
 90    m_comment:search({recent_comments, []}, OffsetLimit, Context);
 91observe_search_query(_, _Context) ->
 92    undefined.
 93
 94%% @doc Move all comments from one resource to another
 95observe_rsc_merge(#rsc_merge{looser_id=LooserId, winner_id=WinnerId}, Context) ->
 96    m_comment:merge(WinnerId, LooserId, Context).
 97
 98%% @doc Check the installation of the comment table. A bit more complicated because 0.1 and 0.2 had a table
 99%% in the default installer, this module installs a different table.
100init(Context) ->
101    ok = z_db:transaction(fun install1/1, Context),
102    z_depcache:flush(Context),
103    ok.
104    
105    install1(Context) ->
106        ok = remove_old_comment_rsc_fields(Context),
107        ok = remove_old_rating_table(Context),
108        ok = install_comment_table(z_db:table_exists(comment, Context), Context),
109        ok.
110
111
112remove_old_rating_table(Context) ->
113    case z_db:table_exists(rating, Context) of
114        false ->
115            ok;
116        true ->
117            case z_db:column_names(rating, Context) of
118                [comment_id,created,id,ip_address,rsc_id,visitor_id] ->
119                    z_db:q("drop table rating", Context),
120                    ok;
121                _ ->
122                    ok
123            end
124    end.
125
126install_comment_table(true, Context) ->
127    % Check for old table
128    case z_db:column_names(comment, Context) of
129        [created,creator_id,id,ip_address,notify_id,props,rating,rsc_id] ->
130            z_db:q("drop table comment", Context),
131            install_comment_table(false, Context);
132        [created,id,email,gravatar_code,ip_address,is_visible,keep_informed,
133         name,props,rsc_id,user_agent,user_id,visitor_id] ->
134            z_db:q("alter table comment drop column visitor_id cascade, "
135                   "add column persistent_id character varying (32), "
136                   "add constraint fk_comment_persistent_id foreign key (persistent_id) "
137                   "  references persistent(id) on delete set null on update cascade", Context),
138            z_db:q("create index fki_comment_persistent_id on comment(persistent_id)", Context),
139            ok;
140        _ ->
141            % todo: add list of current fields here
142            ok
143    end;
144install_comment_table(false, Context) ->
145    z_db:q("
146        create table comment (
147            id serial not null,
148            is_visible boolean not null default true,
149            rsc_id int not null,
150            user_id int,
151            persistent_id character varying(32),
152            gravatar_code character varying(40) not null default ''::character varying,
153            email character varying(80) not null default ''::character varying,
154            name character varying(80) not null default ''::character varying,
155            user_agent character varying(250) not null default ''::character varying,
156            ip_address character varying(40) not null default ''::character varying,
157            keep_informed boolean not null default false,
158            props bytea,
159            created timestamp with time zone not null default now(),
160            
161            constraint comment_pkey primary key (id),
162            constraint fk_comment_rsc_id foreign key (rsc_id)
163                references rsc(id)
164                on delete cascade on update cascade,
165            constraint fk_comment_user_id foreign key (user_id)
166                references rsc(id)
167                on delete set null on update cascade,
168            constraint fk_comment_persistent_id foreign key (persistent_id)
169                references persistent(id)
170                on delete set null on update cascade
171        )
172    ", Context),
173    Indices = [
174        {"fki_comment_rsc_id", "rsc_id"},
175        {"fki_comment_user_id", "user_id"},
176        {"fki_comment_persistent_id", "persistent_id"},
177        {"fki_comment_ip_address", "ip_address"},
178        {"comment_rsc_created_key", "rsc_id, created"},
179        {"comment_created_key", "created"}
180    ],
181    [ z_db:q("create index "++Name++" on comment ("++Cols++")", Context) || {Name, Cols} <- Indices ],
182    ok.
183
184
185%% @doc In the 0.1.0 and 0.2.0 releases we had some pivot information in the rsc table. Remove this.
186remove_old_comment_rsc_fields(Context) ->
187    Cols = z_db:column_names(rsc, Context),
188    R = [],
189    R1 = case lists:member(comment_by, Cols) of true -> ["drop column comment_by"|R]; false -> R end,
190    R2 = case lists:member(comments, Cols) of true -> ["drop column comments"|R1]; false -> R1 end,
191    R3 = case lists:member(rating, Cols) of true -> ["drop column rating"|R2]; false -> R2 end,
192    R4 = case lists:member(rating_count, Cols) of true -> ["drop column rating_count"|R3]; false -> R3 end,
193    case R4 of
194        [] ->
195            ok;
196        L -> 
197            z_db:q("alter table rsc " ++ string:join(L, ", "), Context),
198            ok
199    end.
200
201
202observe_admin_menu(admin_menu, Acc, Context) ->
203    [
204     #menu_item{id=admin_comments,
205                parent=admin_content,
206                label=?__("Comments", Context),
207                url={admin_comments},
208                visiblecheck={acl, use, ?MODULE}},
209     #menu_item{id=admin_comments_settings,
210		parent=admin_modules,
211		label=?__("Comment settings", Context),
212		url={admin_comments_settings},
213		visiblecheck={acl, use, ?MODULE}}     
214     |Acc].
215