You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

watchers_controller.rb 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. # frozen_string_literal: true
  2. # Redmine - project management software
  3. # Copyright (C) 2006-2023 Jean-Philippe Lang
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. class WatchersController < ApplicationController
  19. before_action :require_login, :find_watchables, :only => [:watch, :unwatch]
  20. def watch
  21. set_watcher(@watchables, User.current, true)
  22. end
  23. def unwatch
  24. set_watcher(@watchables, User.current, false)
  25. end
  26. before_action :find_project, :authorize, :only => [:new, :create, :append, :destroy, :autocomplete_for_user, :autocomplete_for_mention]
  27. accept_api_auth :create, :destroy
  28. def new
  29. respond_to do |format|
  30. format.html { render_404 }
  31. format.js do
  32. @users = users_for_new_watcher
  33. end
  34. end
  35. end
  36. def create
  37. user_ids = []
  38. if params[:watcher]
  39. user_ids << (params[:watcher][:user_ids] || params[:watcher][:user_id])
  40. else
  41. user_ids << params[:user_id]
  42. end
  43. user_ids = user_ids.flatten.compact.uniq
  44. users = Principal.assignable_watchers.where(:id => user_ids).to_a
  45. users.each do |user|
  46. @watchables.each do |watchable|
  47. Watcher.create(:watchable => watchable, :user => user)
  48. end
  49. end
  50. respond_to do |format|
  51. format.html do
  52. redirect_to_referer_or do
  53. render(:html => 'Watcher added.', :status => 200, :layout => true)
  54. end
  55. end
  56. format.js {@users = users_for_new_watcher}
  57. format.api {render_api_ok}
  58. end
  59. end
  60. def append
  61. if params[:watcher]
  62. user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
  63. @users = Principal.assignable_watchers.where(:id => user_ids).to_a
  64. end
  65. if @users.blank?
  66. head 200
  67. end
  68. end
  69. def destroy
  70. user = Principal.find(params[:user_id])
  71. @watchables.each do |watchable|
  72. watchable.set_watcher(user, false)
  73. end
  74. respond_to do |format|
  75. format.html do
  76. redirect_to_referer_or do
  77. render(:html => 'Watcher removed.', :status => 200, :layout => true)
  78. end
  79. end
  80. format.js
  81. format.api {render_api_ok}
  82. end
  83. rescue ActiveRecord::RecordNotFound
  84. render_404
  85. end
  86. def autocomplete_for_user
  87. @users = users_for_new_watcher
  88. render :layout => false
  89. end
  90. def autocomplete_for_mention
  91. users = users_for_mention
  92. render :json => format_users_json(users)
  93. end
  94. private
  95. def find_project
  96. if params[:object_type] && params[:object_id]
  97. @watchables = find_objects_from_params
  98. @projects = @watchables.map(&:project).uniq
  99. if @projects.size == 1
  100. @project = @projects.first
  101. end
  102. elsif params[:project_id]
  103. @project = Project.visible.find_by_param(params[:project_id])
  104. end
  105. end
  106. def find_watchables
  107. @watchables = find_objects_from_params
  108. unless @watchables.present?
  109. render_404
  110. end
  111. end
  112. def set_watcher(watchables, user, watching)
  113. watchables.each do |watchable|
  114. watchable.set_watcher(user, watching)
  115. end
  116. respond_to do |format|
  117. format.html do
  118. text = watching ? 'Watcher added.' : 'Watcher removed.'
  119. redirect_to_referer_or do
  120. render(:html => text, :status => 200, :layout => true)
  121. end
  122. end
  123. format.js do
  124. render(:partial => 'set_watcher',
  125. :locals => {:user => user, :watched => watchables})
  126. end
  127. end
  128. end
  129. def users_for_new_watcher
  130. scope = nil
  131. if params[:q].blank?
  132. if @project.present?
  133. scope = @project.principals.assignable_watchers
  134. elsif @projects.present? && @projects.size > 1
  135. scope = Principal.joins(:members).where(:members => { :project_id => @projects }).assignable_watchers.distinct
  136. end
  137. else
  138. scope = Principal.assignable_watchers.limit(100)
  139. end
  140. users = scope.sorted.like(params[:q]).to_a
  141. if @watchables && @watchables.size == 1
  142. watchable_object = @watchables.first
  143. users -= watchable_object.watcher_users
  144. if watchable_object.respond_to?(:visible?)
  145. users.reject! {|user| user.is_a?(User) && !watchable_object.visible?(user)}
  146. end
  147. end
  148. users
  149. end
  150. def users_for_mention
  151. users = []
  152. q = params[:q].to_s.strip
  153. scope = nil
  154. if params[:q].blank? && @project.present?
  155. scope = @project.principals.assignable_watchers
  156. else
  157. scope = Principal.assignable_watchers.limit(10)
  158. end
  159. # Exclude Group principal for now
  160. scope = scope.where(:type => ['User'])
  161. users = scope.sorted.like(params[:q]).to_a
  162. if @watchables && @watchables.size == 1
  163. object = @watchables.first
  164. if object.respond_to?(:visible?)
  165. users.reject! {|user| user.is_a?(User) && !object.visible?(user)}
  166. end
  167. end
  168. users
  169. end
  170. def format_users_json(users)
  171. users.map do |user|
  172. {
  173. 'firstname' => user.firstname,
  174. 'lastname' => user.lastname,
  175. 'name' => user.name,
  176. 'login' => user.login
  177. }
  178. end
  179. end
  180. def find_objects_from_params
  181. klass =
  182. begin
  183. Object.const_get(params[:object_type].camelcase)
  184. rescue
  185. nil
  186. end
  187. return unless klass && Class === klass # rubocop:disable Style/CaseEquality
  188. return unless klass < ApplicationRecord
  189. return unless klass < Redmine::Acts::Watchable::InstanceMethods
  190. scope = klass.where(:id => Array.wrap(params[:object_id]))
  191. if klass.reflect_on_association(:project)
  192. scope = scope.preload(:project => :enabled_modules)
  193. end
  194. objects = scope.to_a
  195. raise Unauthorized if objects.any? do |w|
  196. if w.respond_to?(:visible?)
  197. !w.visible?
  198. elsif w.respond_to?(:project) && w.project
  199. !w.project.visible?
  200. end
  201. end
  202. objects
  203. end
  204. end