1 # Copyright (C) 2007, 2008, 2009, 2010 Heiko Bernloehr (FreeIT.de).
3 # This file is part of ECS.
5 # ECS is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation, either version 3 of
8 # the License, or (at your option) any later version.
10 # ECS is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Affero General Public License for more details.
15 # You should have received a copy of the GNU Affero General Public
16 # License along with ECS. If not, see <http://www.gnu.org/licenses/>.
19 class MessagesController < ApplicationController
21 before_filter :late_initialize
22 before_filter :authentication
23 before_filter :add_cookie_header
24 before_filter :get_record, :only => [:show, :update, :destroy]
25 after_filter :touch_participant_ttl
33 index_querystring_list
35 @body << @ressource_name << "/" << li.id.to_s << "\n"
36 end unless @list.empty?
41 # TODO Webcache via stale? and fresh_when
42 @memberships = Membership.receiver(@participant.id, @record.id)
44 when @record.outtimed_auths_resource_by_non_owner?(@app_namespace, @resource_name, @participant)
45 raise Ecs::OuttimedAuthsException, 'Authorization token outtimed'
46 when (!@memberships.empty? or @participant.sender?(@record))
47 @record.filter(__method__, @app_namespace, @ressource_name, params)
50 eval(@render_cmd) unless @render_cmd.blank?
52 raise Ecs::AuthorizationException,
53 "You are not allowed to access this resource, " +
54 "because you are not the original sender or a receiver."
59 # Create and save a new message. Then render "Created 201" response.
60 # TODO exceptions for: create, constantize
62 @record= Message.create__(request, @app_namespace, @ressource_name, @participant)
68 @record.update__(request, @app_namespace, @ressource_name, @participant)
74 @memberships = Membership.receiver(@participant.id, @record.id)
77 when @record.outtimed_auths_resource_by_non_owner?(@app_namespace, @resource_name, @participant)
78 @record.destroy_as_receiver(@participant)
79 raise Ecs::OuttimedAuthsException, 'Authorization token outtimed'
80 when (@participant.sender?(@record) and not @participant.receiver?(@record))
81 @record.destroy_as_sender
83 @record.destroy_as_receiver(@participant)
85 eval(@render_cmd) unless @render_cmd.blank?
89 queue(:queue_type => :fifo)
93 queue(:queue_type => :lifo)
98 no_data_to_render = false
101 details = member_subresource_details(params["id"])
102 if !details[:receivers] then no_data_to_render = true end
104 index_querystring_list
105 # collection subresource
108 details << member_subresource_details(li.id)
109 end unless @list.empty?
110 if details.empty? then no_data_to_render = true end
113 render :text => "", :content_type => "application/json", :layout => false
115 respond_to do |format|
116 format.json { render :json => JSON.pretty_generate(details) }
117 format.xml { render :xml => details }
124 def member_subresource_details(record_id)
125 get_record(record_id)
126 if @participant.sender?(@record) or @participant.receiver?(@record)
129 Membership.receivers(@record.id).each do |recv|
130 receivers << { :pid => recv.participant.id, :mid => recv.id, :cid => recv.community_id,
131 :itsyou => recv.participant_id == @participant.id }
132 senders << { :mid => Membership.find_by_participant_id_and_community_id(@record.sender, recv.community_id).id }
134 content_type = @record.content_type
135 url = @ressource_name + "/" + record_id.to_s
136 { :receivers => receivers,
138 :content_type => content_type,
140 :owner => { :itsyou => @participant.id == @record.sender,
141 :pid => @record.sender }
144 raise Ecs::AuthorizationException,
145 "You are not allowed to access this resource, " +
146 "because you are not the original sender or a receiver."
150 def index_querystring_list
151 header_querystrings = request.headers["X-EcsQueryStrings"]
152 if header_querystrings
153 hqs = header_querystrings.split(",").map{|s| s.strip}.map{|s| s.split("=").map{|s| s.strip}}
154 sender = (m=hqs.assoc("sender")) ? m[1] : nil
155 receiver = (m=hqs.assoc("receiver")) ? m[1] : nil
156 all = (m=hqs.assoc("all")) ? m[1] : nil
158 sender ||= params["sender"] ? params["sender"] : nil
159 receiver ||= params["receiver"] ? params["receiver"] : nil
160 all ||= params["all"] ? params["all"] : nil
162 when sender == "true"
163 @list = Message.for_participant_sender(@participant).for_resource(@app_namespace,@ressource_name).for_not_removed.uniq
164 when receiver == "true"
165 @list = Message.for_participant_receiver(@participant).for_resource(@app_namespace,@ressource_name).for_not_removed.uniq
167 list1 = Message.for_participant_sender(@participant).for_resource(@app_namespace,@ressource_name).for_not_removed
168 list2 = Message.for_participant_receiver(@participant).for_resource(@app_namespace,@ressource_name).for_not_removed
169 @list = list1.concat(list2).uniq
171 @list = Message.for_participant_receiver(@participant).for_resource(@app_namespace,@ressource_name).for_not_removed.uniq
175 def queue(queue_options = {:queue_type => :fifo})
177 Message.transaction do
178 # returned record holds a lock (pessimistic locking)
179 @record = Message.fifo_lifo_rest(@app_namespace, @ressource_name,@participant.id, queue_options)
181 @memberships = Membership.receiver(@participant.id, @record.id)
186 @record.destroy_as_receiver(@participant)
187 eval(@render_cmd) unless @render_cmd.blank?
189 raise ActiveRecord::RecordNotFound
193 eval(@render_cmd) unless @render_cmd.blank?
199 rescue ActiveRecord::StaleObjectError, ActiveRecord::RecordNotFound => error
200 logger.info "Concurrent access at queue resource"
205 # inititialize instance variables dependent from request object
207 @app_namespace= request.path.sub(/^\//,'').sub(/\/.*/,'')
208 @ressource_name= $&.sub(/\//,'').sub(/\/.*/,'')
209 #@ar_model_name= "#{@app_namespace}_#{@ressource_name}".pluralize.classify
210 #@ar_model= @ar_model_name.constantize
213 # get a record out of the message table
214 def get_record(record_id = params["id"], app_namespace=@app_namespace, ressource_name=@ressource_name)
215 @record, @outdated_auth_token = Message.get_record(record_id, app_namespace, ressource_name)
219 render :text => "", :content_type => "application/json"
223 render :text => @body, :content_type => "text/uri-list"
227 #expires_in 3.hours, 'max-stale' => 5.hours, :public => true
228 headers["Cache-Control"] = "private, max-age=5"
229 x_ecs_receiver_communities= ""
231 @memberships.each do |memb|
232 x_ecs_receiver_communities << memb.community.id.to_s
233 x_ecs_sender << Membership.find_by_participant_id_and_community_id(Participant.find(@record.sender).id, memb.community.id).id.to_s
234 unless @memberships.last == memb
235 x_ecs_receiver_communities << ","
238 end unless @memberships.blank?
239 headers["X-EcsReceiverCommunities"]= x_ecs_receiver_communities unless x_ecs_receiver_communities.blank?
240 headers["X-EcsSender"]= x_ecs_sender unless x_ecs_sender.blank?
241 @render_cmd='render :text => @body, :layout => false, :status => 200, :content_type => Mime::Type.lookup(@record.content_type)'
245 location = request.protocol + request.host
246 # FIXME request.headers["SERVER_PORT"] is a string compared to integers.
247 location += ":" + request.headers["SERVER_PORT"] unless [80,443].include? request.headers["SERVER_PORT"]
248 location += request.headers["SCRIPT_NAME"] if request.headers["SCRIPT_NAME"]
249 location += request.path.gsub(/\/*$/,'') + "/" + @record.id.to_s
250 if @app_namespace == 'sys' and @ressource_name == 'auths'
251 render :text => @body, :layout => false, :status => 201, :location => location, :content_type => Mime::Type.lookup_by_extension("json")
253 render :text => "", :layout => false, :status => 201, :location => location, :content_type => Mime::Type.lookup(@record.content_type)
258 location = request.protocol + request.host
259 location += request.headers["SCRIPT_NAME"] if request.headers["SCRIPT_NAME"]
260 location += request.path.gsub(/\/*$/,'')
261 render :text => "", :layout => false, :status => 200,
262 :location => location
266 render :nothing => true, :layout => false, :status => 200,
267 :content_type => "application/json"