Merge remote-tracking branch 'origin/master' into networks
[shapado:cantonics-shapado.git] / app / controllers / users_controller.rb
1 class UsersController < ApplicationController
2   before_filter :login_required, :only => [:edit, :update,
3                                            :follow, :follow_tags, :leave,
4                                            :unfollow_tags, :connect, :social_connect]
5   skip_before_filter :check_group_access, :only => :auth
6   before_filter :find_user, :only => [:show, :answers, :follows, :activity]
7   tabs :default => :users
8
9   before_filter :check_signup_type, :only => [:new]
10
11   tab_config = [[:newest, [:created_at, Mongo::DESCENDING]],
12                 [:hot, [:hotness, Mongo::DESCENDING]],
13                 [:votes, [:votes_average, Mongo::DESCENDING], [:created_at, Mongo::DESCENDING]],
14                 [:oldest, [:created_at, Mongo::ASCENDING]]]
15
16   subtabs :index => [[:reputation, "reputation"],
17                      [:newest, %w(created_at desc)],
18                      [:oldest, %w(created_at asc)],
19                      [:name, %w(login asc)],
20                      [:near, ""]],
21           :show => [[:votes, [[:votes_average, :desc], [:created_at, :desc]]],
22                     [:views, [:views, :desc]],
23                     [:newest, [:created_at, :desc]],
24                     [:oldest, [:created_at, :asc]]],
25         :answers => [[:votes, [[:votes_average, :desc], [:created_at, :desc]]],
26                     [:views,  [:views, :desc]],
27                     [:newest, [:created_at, :desc]],
28                     [:oldest, [:created_at, :asc]]],
29         :follows => [[:questions, []],
30                      [:following, []],
31                      [:followers, []]],
32         :by_me => tab_config,
33         :preferred => tab_config,
34         :expertise => tab_config,
35         :feed => tab_config,
36         :contributed => tab_config
37
38   def index
39     set_page_title(t("users.index.title"))
40
41     order = current_order
42     conditions = {}
43     conditions = {:display_name => /^#{Regexp.escape(params[:q])}/} if params[:q]
44
45     if order == "reputation"
46       order = %w(reputation desc)
47     end
48
49     @memberships = current_group.memberships.where(conditions).order_by(order).paginate(paginate_opts(params))
50
51     respond_to do |format|
52       format.html
53       format.json {
54         render :json => @memberships.to_json(:only => %w[name login bio website location language])
55       }
56       format.js {
57         html = render_to_string(:partial => "user", :collection  => @users)
58         pagination = render_to_string(:partial => "shared/pagination", :object => @users,
59                                       :format => "html")
60         render :json => {:html => html, :pagination => pagination }
61       }
62     end
63
64   end
65
66   # render new.rhtml
67   def new
68     @user = User.new
69     @user.preferred_languages = current_languages.to_a
70     @user.timezone = AppConfig.default_timezone
71   end
72
73   def create
74     @user = User.new
75     @user.preferred_languages = params[:preferred_languages].split(',') if params[:preferred_languages]
76     @user.safe_update(%w[login email name password_confirmation password  website
77                          language timezone identity_url bio hide_country], params[:user])
78     if params[:user]["birthday(1i)"]
79       @user.birthday = build_date(params[:user], "birthday")
80     end
81     success = @user && @user.save
82     if success && @user.errors.empty?
83       # Protects against session fixation attacks, causes request forgery
84       # protection if visitor resubmits an earlier form using back
85       # button. Uncomment if you understand the tradeoffs.
86       # reset session
87       sweep_new_users(current_group)
88       if !params[:invitation_id].blank?
89         @user.accept_invitation(params[:invitation_id])
90         @invitation = Invitation.find(params[:invitation_id])
91         @invitation.confirm if @invitation
92       end
93       flash[:notice] = t("flash_notice", :scope => "users.create")
94       sign_in_and_redirect(:user, @user) # !! now logged in
95     else
96       flash[:error]  = t("flash_error", :scope => "users.create")
97       render :action => 'new'
98     end
99   end
100
101   def show
102     @resources = @user.questions.where(:group_id => current_group.id,
103                                        :banned => false,
104                                        :anonymous => false).
105                        order_by(current_order).
106                        paginate(paginate_opts(params))
107
108     respond_to do |format|
109       format.html
110       format.atom { @questions = @resources }
111       format.json {
112         render :json => @user.to_json(:only => %w[name login bio website location language])
113       }
114       format.js do
115         html = ""
116         if params[:facebook]
117           html = render_to_string(:partial => "facebook/user", :object => @user)
118         else
119           html = render_to_string(:partial => "users/user", :object => @user)
120         end
121
122         render :json => {:success => true, :html => html}
123       end
124     end
125   end
126
127   def answers
128     @resources = @user.answers.where(:group_id => current_group.id,
129                                      :banned => false,
130                                      :anonymous => false).
131                               order_by(current_order).
132                               paginate(paginate_opts(params))
133     respond_to do |format|
134       format.html{render :show}
135     end
136   end
137
138   def follows
139     case @active_subtab.to_s
140     when "following"
141       @resources = @user.following.paginate(paginate_opts(params))
142     when "followers"
143       @resources = @user.followers.paginate(paginate_opts(params))
144     when "answers"
145       @resources = Answer.where(:favoriter_ids.in => [@user.id],
146                                 :banned => false,
147                                 :group_id => current_group.id,
148                                 :anonymous => false).
149       order_by(current_order).
150       paginate(paginate_opts(params))
151     else
152       @resources = Question.where(:follower_ids.in => [@user.id],
153                                 :banned => false,
154                                 :group_id => current_group.id,
155                                 :anonymous => false).
156                           order_by(current_order).
157                           paginate(paginate_opts(params))
158     end
159     respond_to do |format|
160       format.html{render :show}
161     end
162   end
163
164   def activity
165     @resources = @user.activities.paginate(paginate_opts(params))
166     respond_to do |format|
167       format.html{render :show}
168     end
169   end
170
171   def edit
172     @user = current_user
173     @user.timezone = AppConfig.default_timezone if @user.timezone.blank?
174   end
175
176   def update
177     if params[:id] == 'login' && params[:user].nil? # HACK for facebook-connectable
178       redirect_to root_path
179       return
180     end
181
182     @user = current_user
183
184     if params[:current_password] && @user.valid_password?(params[:current_password])
185       @user.encrypted_password = ""
186       @user.password = params[:user][:password]
187       @user.password_confirmation = params[:user][:password_confirmation]
188     end
189
190     @user.networks = params[:networks]
191     @user.preferred_languages = params[:preferred_languages].split(',') if params[:preferred_languages]
192     @user.safe_update(%w[login email name language timezone notification_opts bio hide_country website avatar use_gravatar], params[:user])
193
194     if params[:user]["birthday(1i)"]
195       @user.birthday = build_date(params[:user], "birthday")
196     end
197
198     Jobs::Users.async.on_update_user(@user.id, current_group.id).commit!
199
200     preferred_tags = params[:user][:preferred_tags]
201
202     if @user.valid? && @user.save
203       if params[:user][:avatar]
204         Jobs::Images.async.generate_user_thumbnails(@user.id).commit!
205       end
206       @user.add_preferred_tags(preferred_tags, current_group) if preferred_tags
207       if params[:next_step]
208         current_user.accept_invitation(params[:invitation_id])
209         @invitation = Invitation.find(params[:invitation_id])
210         @invitation.confirm if @invitation
211         redirect_to accept_invitation_path(:step => params[:next_step], :id => params[:invitation_id])
212       else
213         redirect_to root_path
214       end
215     else
216       render :action => "edit"
217     end
218   end
219
220   # My feed, this returns:
221   # - all the questions I asked
222   # - all the questions I follow
223   # - all the questions followed by people I follow
224   #   (questions followed by people I find interesting must be interesting to me)
225   # - all the questions tagged with one of the tag I follow
226   def feed
227     @user = params[:id] ? current_group.users.where(:login => params[:id]).first : current_user
228     tags = @user.config_for(current_group).preferred_tags
229     user_ids = @user.friend_list.following_ids
230     user_ids << @user.id
231     find_questions({ }, :any_of => [{:follower_ids.in => user_ids},
232                                     {:tags.in => tags},
233                                     {:user_id => user_ids}])
234   end
235
236   def by_me
237     @user = params[:id] ? current_group.users.where(:login => params[:id]).first : current_user
238     find_questions(:user_id => @user.id)
239   end
240
241   def preferred
242     @user = params[:id] ? current_group.users.where(:login => params[:id]).first : current_user
243     @current_tags = tags = @user.config_for(current_group).preferred_tags
244
245     find_questions(:tags.in => tags)
246   end
247
248   def expertise
249     @user = params[:id] ? current_group.users.where(:login => params[:id]).first : current_user
250     @current_tags = tags = @user.stats(:expert_tags).expert_tags # TODO: optimize
251
252     find_questions(:tags.in => tags)
253   end
254
255   def contributed
256     @user = params[:id] ? current_group.users.where(:login => params[:id]).first : current_user
257
258     find_questions(:contributor_ids.in => [@user.id])
259   end
260
261   def connect
262     authenticate_user!
263     warden.authenticate!(:scope => :openid_identity, :recall => "show")
264     current_openid_identity.user = current_user
265     current_openid_identity.save!
266     sign_out :openid_identity
267
268     redirect_to settings_path
269   end
270
271   def follow_tags
272     @user = current_user
273     if tags = params[:tags]
274       @user.add_preferred_tags(tags, current_group) if tags
275     end
276     flash[:notice] = t("users.update_followed_tags.followed.flash_notice",
277                        :tag => params[:tags])
278     respond_to do |format|
279       format.html {redirect_to questions_path}
280       format.js {
281         render(:json => {:success => true,
282                  :message => flash[:notice] }.to_json)
283       }
284     end
285   end
286
287   def unfollow_tags
288     @user = current_user
289     if tags = params[:tags]
290       @user.remove_preferred_tags(tags, current_group)
291     end
292     flash[:notice] = t("users.update_followed_tags.unfollowed.flash_notice",
293                        :tag => params[:tags])
294     respond_to do |format|
295       format.html {redirect_to questions_path}
296       format.js {
297         render(:json => {:success => true,
298                  :message => flash[:notice] }.to_json)
299       }
300     end
301   end
302
303   def follow
304     @user = User.find_by_login_or_id(params[:id])
305     current_user.add_friend(@user)
306
307     flash[:notice] = t("flash_notice", :scope => "users.follow", :user => @user.login)
308
309     Jobs::Activities.async.on_follow(current_user.id, @user.id, current_group.id).commit!
310     Jobs::Mailer.async.on_follow(current_user.id, @user.id, current_group.id).commit!
311
312     respond_to do |format|
313       format.html do
314         redirect_to user_path(@user)
315       end
316       format.js {
317         render(:json => {:success => true,
318                  :message => flash[:notice] }.to_json)
319       }
320     end
321   end
322
323   def unfollow
324     @user = User.find_by_login_or_id(params[:id])
325     current_user.remove_friend(@user)
326
327     flash[:notice] = t("flash_notice", :scope => "users.unfollow", :user => @user.login)
328
329     Jobs::Activities.async.on_unfollow(current_user.id, @user.id, current_group.id).commit!
330
331     respond_to do |format|
332       format.html do
333         redirect_to user_path(@user)
334       end
335       format.js {
336         render(:json => {:success => true,
337                  :message => flash[:notice] }.to_json)
338       }
339     end
340   end
341
342   def autocomplete_for_user_login
343     @users = User.only(:login).
344                   where(:login =>  /^#{Regexp.escape(params[:term].to_s.downcase)}.*/).
345                   limit(20).
346                   order_by(:login.desc).
347                   all
348
349     respond_to do |format|
350       format.json {render :json=>@users}
351     end
352   end
353
354   def destroy
355     if false && current_user.delete # FIXME We need a better way to delete users
356       flash[:notice] = t("destroyed", :scope => "devise.registrations")
357     else
358       flash[:notice] = t("destroy_failed", :scope => "devise.registrations")
359     end
360     return redirect_to(:root)
361   end
362
363   def suggestions
364   end
365
366   def leave
367     current_user.leave(current_group)
368     return redirect_to :root
369   end
370
371   def join
372     current_user.join(current_group)
373     return redirect_to :root
374   end
375
376   def auth
377     if params["pp"]
378       cookies["pp"] = 1
379     end
380     head :status => 404
381   end
382
383   def social_connect
384   end
385
386   protected
387   def check_signup_type
388     if current_group.is_social_only_signup? ||
389         current_group.is_email_only_signup?
390       redirect_to '/'
391     end
392   end
393
394   def active_subtab(param)
395     key = params.fetch(param, "votes")
396     order = "votes_average desc, created_at desc"
397     case key
398       when "votes"
399         order = "votes_average desc, created_at desc"
400       when "views"
401         order = "views desc, created_at desc"
402       when "newest"
403         order = "created_at desc"
404       when "oldest"
405         order = "created_at asc"
406     end
407     [key, order]
408   end
409
410   def find_user
411     conds = {}
412     conds[:se_id] = params[:se_id] if params[:se_id]
413     @user = User.find_by_login_or_id(params[:id], conds)
414     raise Goalie::NotFound unless @user
415     set_page_title(t("users.show.title", :user => @user.login))
416     @badges = @user.badges.where(:group_id => current_group.id).
417                            paginate(paginate_opts(params))
418     add_feeds_url(url_for(:format => "atom"), t("feeds.user"))
419     @user.viewed_on!(current_group) if @user != current_user && !is_bot?
420   end
421 end
422
423