gb_mapfish_appserver 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -29,7 +29,7 @@ Mapfish Appserver comes with the following out-of-the box features:
29
29
  Documentation
30
30
  -------------
31
31
 
32
- For more documentation see the [github.io/gb_mapfish_appserver](http://pka.github.io/gb_mapfish_appserver/)
32
+ For more documentation see the [mapfish-appserver.github.io](http://mapfish-appserver.github.io/)
33
33
 
34
34
  Authors and License
35
35
  -------------------
@@ -52,7 +52,7 @@ class AppsController < ApplicationController
52
52
 
53
53
  session[:map_ts] = Time.now # Used for checking access to non-public WMS
54
54
 
55
- render :layout => false
55
+ render :action => @app, :layout => false
56
56
  end
57
57
 
58
58
  end
@@ -177,7 +177,7 @@ class PrintController < ApplicationController
177
177
  end
178
178
 
179
179
  def baseCmd
180
- "java -cp #{File.dirname(__FILE__)}/../../lib/print/print-standalone.jar org.mapfish.print.ShellMapPrinter --config=#{@configFile}"
180
+ "java -cp #{GbMapfishPrint::PRINT_JAR} org.mapfish.print.ShellMapPrinter --config=#{@configFile}"
181
181
  end
182
182
 
183
183
  def cleanupTempFiles
@@ -0,0 +1,243 @@
1
+ #Mapfish print controller with access control and servlet call
2
+
3
+ class PrintController < ApplicationController
4
+ require 'popen4'
5
+ begin
6
+ require 'RMagick'
7
+ rescue LoadError
8
+ ActionController::Base.logger.info "Couldn't find RMagick. Image export not supported"
9
+ end
10
+
11
+ skip_before_filter :verify_authenticity_token, :only => :create # allow /print/create with POST
12
+
13
+ caches_action :info
14
+
15
+ class JavaError < Exception
16
+ def initialize(cmd, message)
17
+ super(cmd+"\n"+message)
18
+ end
19
+ end
20
+
21
+ def initialize
22
+ @configFile = "#{Rails.root}/config/print.yml"
23
+ end
24
+
25
+ TMP_PREFIX = "/opt/geodata/tmp/mfPrintTempFile" #WARNING: use NFS for multi-node setups! TODO: external config
26
+ TMP_SUFFIX = ".pdf"
27
+ TMP_PURGE_SECONDS = 600
28
+
29
+ OUTPUT_FORMATS = ["pdf", "png", "jpg", "tif", "gif"]
30
+
31
+ def info
32
+ #if PRINT_URL.present?
33
+ #TODO: call_servlet(request)
34
+ cmd = baseCmd + " --clientConfig"
35
+ result = ""
36
+ errors = ""
37
+ status = POpen4::popen4(cmd) do |stdout, stderr, stdin, pid|
38
+
39
+ result = stdout.readlines.join("\n")
40
+ errors = stderr.readlines.join("\n")
41
+ end
42
+ if status.nil? || status.exitstatus != 0
43
+ raise JavaError.new(cmd, errors)
44
+ else
45
+ info = ActiveSupport::JSON.decode(result)
46
+ info['createURL'] = url_for(:protocol => request.protocol, :action=>'create') + '.json'
47
+ # add output formats
48
+ info['outputFormats'] = []
49
+ OUTPUT_FORMATS.each do |output_format|
50
+ info['outputFormats'] << {:name => output_format}
51
+ end
52
+
53
+ respond_to do |format|
54
+ format.json do
55
+ if params[:var]
56
+ render :text=>"var "+params[:var]+"="+result+";"
57
+ else
58
+ render :json=>info
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def create
66
+ cleanupTempFiles
67
+
68
+ accessible_topics = Topic.accessible_by(current_ability).collect{ |topic| topic.name }
69
+ layers_to_delete = []
70
+ request.parameters["layers"].each do |layer|
71
+ if layer["baseURL"] # WMS layers
72
+ topic = File.basename(URI.parse(layer["baseURL"]).path)
73
+ if accessible_topics.include?(topic)
74
+ # rewrite URL for local WMS, use CGI if layer filter is used
75
+ use_cgi = !layer["customParams"].nil? && layer["customParams"].any? { |param, value| param =~ LAYER_FILTER_REGEX }
76
+ layer["baseURL"] = rewrite_wms_uri(layer["baseURL"], use_cgi)
77
+ if layer["customParams"] #Set map_resolution for mapserver (MapFish print bug?)
78
+ layer["customParams"].delete("DPI")
79
+ layer["customParams"]["map_resolution"] = request.parameters["dpi"]
80
+ end
81
+ # For permission check in WMS controller: pass session as WMS request parameter
82
+ #layer["customParams"]["session"] =
83
+ else
84
+ # collect inaccessible layers for later removal
85
+ layers_to_delete << layer
86
+ end
87
+ end
88
+
89
+ if layer["baseURL"].nil? && layer["styles"] #Vector layers
90
+ layer["styles"].each_value do |style| #NoMethodError (undefined method `each_value' for [""]:Array):
91
+ if style["externalGraphic"]
92
+ style["externalGraphic"].gsub!(LOCAL_GRAPHICS_HOST, '127.0.0.1')
93
+ style["externalGraphic"].gsub!(/^https:/, 'http:')
94
+ end
95
+ end
96
+ end
97
+ end
98
+ # remove inaccessible layers
99
+ request.parameters["layers"] -= layers_to_delete
100
+
101
+ request.parameters["pages"].each do |page|
102
+ # round center coordinates
103
+ page["center"].collect! {|coord| (coord * 100.0).round / 100.0 }
104
+ # add blank user strings if missing
105
+ page["user_title"] = " " if page["user_title"].blank?
106
+ page["user_comment"] = " " if page["user_comment"].blank?
107
+ # base url
108
+ page["base_url"] = "#{request.protocol}#{request.host}"
109
+ # disclaimer
110
+ topic = Topic.accessible_by(current_ability).where(:name => page["topic"]).first
111
+ page["disclaimer"] = topic.nil? ? Topic.default_print_disclaimer : topic.print_disclaimer
112
+ end
113
+
114
+ logger.info request.parameters.to_yaml
115
+
116
+ if PRINT_URL.present?
117
+ call_servlet(request)
118
+ else
119
+ #print-standalone
120
+ tempId = SecureRandom.random_number(2**31)
121
+ temp = TMP_PREFIX + tempId.to_s + TMP_SUFFIX
122
+ cmd = baseCmd + " --output=" + temp
123
+ result = ""
124
+ errors = ""
125
+ status = POpen4::popen4(cmd) do |stdout, stderr, stdin, pid|
126
+ stdin.puts request.parameters.to_json
127
+ #body = request.body
128
+ #FileUtils.copy_stream(body, stdin)
129
+ #body.close
130
+ stdin.close
131
+ result = stdout.readlines.join("\n")
132
+ errors = stderr.readlines.join("\n")
133
+ end
134
+ if status.nil? || status.exitstatus != 0
135
+ raise JavaError.new(cmd, errors)
136
+ else
137
+ convert_and_send_link(temp, tempId, request.parameters["dpi"], request.parameters["outputFormat"])
138
+ end
139
+ end
140
+ end
141
+
142
+ def show
143
+ output_format = params[:format]
144
+ if OUTPUT_FORMATS.include?(output_format)
145
+ temp = TMP_PREFIX + params[:id] + ".#{output_format}"
146
+ case output_format
147
+ when "pdf"
148
+ type = 'application/x-pdf'
149
+ when "png"
150
+ type = 'image/png'
151
+ when "jpg"
152
+ type = 'image/jpeg'
153
+ when "tif"
154
+ type = 'image/tiff'
155
+ when "gif"
156
+ type = 'image/gif'
157
+ end
158
+ send_file temp, :type => type, :disposition => 'attachment', :filename => params[:id] + ".#{output_format}"
159
+ end
160
+ end
161
+
162
+ protected
163
+
164
+ def rewrite_wms_uri(url, use_cgi)
165
+ #http://wms.zh.ch/basis -> http://127.0.0.1/cgi-bin/mapserv.fcgi?MAP=/opt/geodata/mapserver/maps/intranet/basis.map&
166
+ out = url
167
+ # get topic from layer URL
168
+ uri = URI.parse(url)
169
+ localwms = LOCAL_WMS.any? { |ref| uri.host =~ ref }
170
+ if localwms
171
+ topic = File.basename(uri.path)
172
+ localhost = (@zone == ZONE_INTRANET) ? '127.0.0.1' : 'localhost'
173
+ out = "http://#{localhost}#{use_cgi ? MAPSERV_CGI_URL : MAPSERV_URL}?MAP=#{MAPPATH}/#{@zone}/#{topic}.map&"
174
+ #out = "http://#{localhost}:#{request.port}/wms/#{topic}"
175
+ end
176
+ out
177
+ end
178
+
179
+ def baseCmd
180
+ "java -cp #{GbMapfishPrint::PRINT_JAR} org.mapfish.print.ShellMapPrinter --config=#{@configFile}"
181
+ end
182
+
183
+ def cleanupTempFiles
184
+ minTime = Time.now - TMP_PURGE_SECONDS;
185
+ OUTPUT_FORMATS.each do |output_format|
186
+ Dir.glob(TMP_PREFIX + "*." + output_format).each do |path|
187
+ if File.mtime(path) < minTime
188
+ File.delete(path)
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ def call_servlet(request)
195
+ url = URI.parse(URI.decode(PRINT_URL))
196
+ logger.info "Forward request: #{PRINT_URL}"
197
+ printspec = request.parameters.to_json
198
+
199
+ response = nil
200
+ begin
201
+ http = Net::HTTP.new(url.host, url.port)
202
+ http.start do
203
+ case request.method.to_s
204
+ when 'GET' then response = http.get(url.path) #, request.headers
205
+ #when 'POST' then response = http.post(url.path, printspec)
206
+ when 'POST' then response = http.get("#{url.path}?spec=#{CGI.escape(printspec)}") #-> GET print.pdf
207
+ else
208
+ raise Exception.new("unsupported method `#{request.method}'.")
209
+ end
210
+ end
211
+ rescue => err
212
+ logger.info("#{err.class}: #{err.message}")
213
+ render :nothing => true, :status => 500
214
+ return
215
+ end
216
+ #send_data response.body, :status => response.code, :type=>'application/x-pdf', :disposition=>'attachment', :filename=>'map.pdf'
217
+ tempId = SecureRandom.random_number(2**31)
218
+ temp = TMP_PREFIX + tempId.to_s + TMP_SUFFIX
219
+ File.open(temp, 'w') {|f| f.write(response.body) }
220
+ convert_and_send_link(temp, tempId, request.parameters["dpi"], request.parameters["outputFormat"])
221
+ end
222
+
223
+ # optionally convert PDF to image and send link to print result
224
+ def convert_and_send_link(temp_pdf, temp_id, dpi, output_format)
225
+ temp_suffix = ".pdf"
226
+
227
+ if output_format != "pdf" && OUTPUT_FORMATS.include?(output_format)
228
+ # convert PDF to image
229
+ pdf = Magick::Image.read(temp_pdf) { self.density = dpi }.first
230
+ temp_suffix = ".#{output_format}"
231
+ temp_img = TMP_PREFIX + temp_id.to_s + temp_suffix
232
+ pdf.write(temp_img)
233
+ File.delete(temp_pdf)
234
+ end
235
+
236
+ respond_to do |format|
237
+ format.json do
238
+ render :json=>{ 'getURL' => url_for(:action=>'show', :id=>temp_id) + temp_suffix }
239
+ end
240
+ end
241
+ end
242
+
243
+ end
@@ -6,8 +6,12 @@ class TopicsController < ApplicationController
6
6
  }
7
7
 
8
8
  def index
9
- params[:gbapp] = 'gbzh' if params[:gbapp] == 'default' #FIXME
10
9
  @app = Gbapplication.find_by_name(params[:gbapp]) if params[:gbapp]
10
+ if @app.nil?
11
+ logger.error "Gbapplication '#{params[:gbapp]}' not found"
12
+ head :bad_request
13
+ return
14
+ end
11
15
 
12
16
  respond_to do |format|
13
17
  format.json do
@@ -41,7 +41,7 @@ class GeoModel < ActiveRecord::Base
41
41
  end
42
42
 
43
43
  def bbox
44
- envelope = GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb(extent).envelope
44
+ envelope = GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb(extent).envelope #TODO: replace with rgeo
45
45
  [envelope.lower_corner.x, envelope.lower_corner.y, envelope.upper_corner.x, envelope.upper_corner.y]
46
46
  end
47
47
 
@@ -12,6 +12,10 @@ class Layer < ActiveRecord::Base
12
12
  scope :defaultorder, order(:topic_name, :name)
13
13
  scope :unused, includes(:topics_layers).where('topics_layers.layer_id IS NULL')
14
14
 
15
+ #Namespace for run-time geo classes
16
+ module Geo
17
+ end
18
+
15
19
  # Enum for RailsAdmin form (causes exception in name search)
16
20
  #def sublayer_group_enum
17
21
  # SublayerGroup.all.collect {|p| [ p.name, p.id ] }
@@ -0,0 +1,283 @@
1
+ class Layer < ActiveRecord::Base
2
+ has_many :topics_layers, :dependent => :destroy
3
+ has_many :topics, :through => :topics_layers
4
+ belongs_to :sublayer_group
5
+
6
+ attr_protected []
7
+
8
+ validates :name, :presence => true, :uniqueness => {:scope => :topic_name}
9
+ validates_format_of :name, :with => /\A[A-Za-z][\w-]*\Z/
10
+ validates_format_of :topic_name, :with => /\A[\w-]+\Z/
11
+
12
+ scope :defaultorder, order(:topic_name, :name)
13
+ scope :unused, includes(:topics_layers).where('topics_layers.layer_id IS NULL')
14
+
15
+ #Namespace for run-time geo classes
16
+ module Geo
17
+ end
18
+
19
+ # Enum for RailsAdmin form (causes exception in name search)
20
+ #def sublayer_group_enum
21
+ # SublayerGroup.all.collect {|p| [ p.name, p.id ] }
22
+ #end
23
+
24
+ #Structure for Topic selection
25
+ def self.list(ability, layer_type, topic_name)
26
+ topic = Topic.accessible_by(ability).includes(:layers).where(:name => topic_name).first
27
+ layers = topic.nil? ? [] : topic.layers.accessible_by(ability).all
28
+ topic_layers = topic.nil? ? [] : topic.topics_layers.select {|tl| layers.include?(tl.layer) }
29
+ wms_layer_list(ability, topic, topic_layers)
30
+ end
31
+
32
+ def self.wms_layer_list(ability, topic, topic_layers)
33
+ wms_layers = topic_layers.collect do |topic_layer|
34
+ layer = topic_layer.layer
35
+ {
36
+ "id" => topic_layer.id,
37
+ "layername"=> layer.name,
38
+ "topic"=> topic.name,
39
+ "groupname" => layer.sublayer_group.try(:name),
40
+ "toclayertitle"=> layer.title,
41
+ "leglayertitle"=> layer.title,
42
+ "showscale"=> "true",
43
+ "minscale"=> layer.minscale,
44
+ "maxscale"=> layer.maxscale,
45
+ "wms_sort"=> topic_layer.wms_sort, # MapServer layer order
46
+ #"leg_sort"=> topic_layer.leg_sort, # Not used client side (Legend sort is in defined in HTML). Query result order.
47
+ #"query_sort"=> topic_layer.leg_sort, # deprecated
48
+ "toc_sort"=> topic_layer.toc_sort, # Layer tree order
49
+ "wms"=> "false",
50
+ "visini"=> topic_layer.visini,
51
+ "visuser"=> topic_layer.visini, #User visibility is in request_state
52
+ "showtoc"=> "true",
53
+ "editeable"=> ability.can?(:edit, layer)
54
+ }
55
+ end
56
+ {
57
+ "success" => true,
58
+ "messageProperty"=> {"topic"=> topic.name, "legendtitle"=> "Legende", "legendraster"=> "true"},
59
+ "results"=> wms_layers.size,
60
+ "wmslayers"=> wms_layers
61
+ }
62
+ end
63
+
64
+ def full_name
65
+ "#{topic_name}-#{name}".downcase
66
+ end
67
+
68
+ def feature_class
69
+ fc = "Geo::#{feature_class_name}".constantize rescue nil #Geo.const_defined?(feature_class_name) seems not to work here
70
+ fc ||= Geo.module_eval <<EOS
71
+ class #{feature_class_name} < GeoModel
72
+ self.table_name = '#{table}'
73
+ self.primary_key = '#{pkey}'
74
+
75
+ self
76
+ end
77
+ EOS
78
+ end
79
+
80
+ def feature_class_name
81
+ table.camelize.singularize
82
+ end
83
+
84
+ def geometry_column
85
+ feature_class.try(:geometry_column)
86
+ end
87
+
88
+ def attribute(name)
89
+ if feature_class.nil?
90
+ ::Attribute.new(self, name)
91
+ else
92
+ @attrs ||= feature_class.columns.inject({}) do |h, c|
93
+ #logger.info "************************* feature_class column c #{c.inspect}"
94
+ h[c.name] = ::Attribute.new(self, c.name)
95
+ h
96
+ end
97
+ @attrs[name] ||= ::Attribute.new(self, name) #Add ad-hoc Attr. for calculated columns (e.g. custom SQL in query fields)
98
+ end
99
+ #logger.info "************************* Attribute for name '#{name}': #{@attrs[name].inspect}"
100
+ end
101
+
102
+ #def filtered(ability)
103
+ # feature_class.where(ability.resource_access_filter(self))
104
+ #end
105
+
106
+ def query_fields(ability)
107
+ return '' if feature_class.nil?
108
+ area_field = "ST_Area(#{geometry_column.name}) AS area"
109
+ #TODO: measure -> Measure(geometry_column, lat, lon)
110
+ ([pkey]+ident_fields_for(ability)+[feature_class.extent_field, area_field]).join(',')
111
+ end
112
+
113
+ def ident_fields_for(ability)
114
+ #attributes.accessible_by(ability) & fields
115
+ #logger.info "************************* fields layer #{name}: #{ident_fields}"
116
+ #logger.info "************************* roles: #{ability.roles.collect(&:name).join(',')}"
117
+ allowed_fields = ident_fields.split(',').select { |f| ability.can?(:show, attribute(f)) }
118
+ #logger.info "************************* ident_fields layer #{name}: #{allowed_fields.inspect}"
119
+ allowed_fields
120
+ end
121
+
122
+ def query(ability, query_topic, searchbbox)
123
+ if feature_class
124
+ begin
125
+ #query_topic: {... customQueries: {<layername>: <query_method> }
126
+ #e.g.
127
+ #{"queryTopics":[{
128
+ # "level":"main","topic":"Lageklassen2011ZH","divCls":"legmain","layers":"seen,lageklassen-2011-flaechen,grenzen,gemeindegrenzen,bezirkslabels"
129
+ # customQueries: {'seen': 'tiefen_statistik'},
130
+ # customParams: {'tiefe': 25}
131
+ # }]}
132
+ custom_query_method = query_topic['customQueries'][name] rescue nil
133
+ logger.debug "******** #{feature_class} ***************************************************"
134
+ features = if custom_query_method
135
+ logger.debug "Custom query on layer #{name}: #{query_topic.inspect}"
136
+ feature_class.send(custom_query_method, self, query_topic, searchbbox)
137
+ else
138
+ logger.debug "Identify on layer #{name} with query fields #{query_fields(ability)} at #{searchbbox.inspect}"
139
+ feature_class.identify_filter(searchbbox, searchdistance).select(query_fields(ability)).all
140
+ end
141
+ logger.debug "Number of features: #{features.size}"
142
+ # calculate bbox of all features
143
+ unless features.empty?
144
+ envelope = GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb(features.first['extent']).envelope
145
+ features.each do |feature|
146
+ next if feature == features.first
147
+ envelope.extend!(GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb(feature['extent']).envelope)
148
+ end
149
+ bbox = [envelope.lower_corner.x, envelope.lower_corner.y, envelope.upper_corner.x, envelope.upper_corner.y]
150
+ end
151
+ rescue Exception => e
152
+ features = "Table: <b>#{table}</b><br/>Exception: #{e}<br/>query fields: #{query_fields(ability)}<br/>db fields: #{feature_class.column_names.join(',')}<br/>missing: <font color='red'>#{(query_fields(ability).split(',') - feature_class.column_names).join(', ')}</font><br/><br/>"
153
+ logger.info "Identfy error on layer #{name} #{features}"
154
+ end
155
+ [self, features, bbox]
156
+ else
157
+ logger.warn "Table for layer #{name} not found. (Table name: '#{table}')"
158
+ nil
159
+ end
160
+ end
161
+
162
+ # Partial for identify result
163
+ def info_fname
164
+ "_#{name}_info.html.erb"
165
+ end
166
+
167
+ def info_file
168
+ File.join(Rails.root, 'app', 'views', 'layers', 'custom', topic_name.downcase, info_fname)
169
+ end
170
+
171
+ def info_file_auto
172
+ File.join(Rails.root, 'app', 'views', 'layers', 'custom', topic_name.downcase, 'auto', info_fname)
173
+ end
174
+
175
+ # ignore auto file if empty file exists
176
+ def info_file_empty
177
+ File.join(Rails.root, 'app', 'views', 'layers', 'custom', topic_name.downcase, "_#{name}_info_leer.html.erb")
178
+ end
179
+
180
+ def info
181
+ @info ||= begin
182
+ if File.exist?(info_file)
183
+ "layers/custom/#{topic_name.downcase}/#{info_fname[1..-10]}"
184
+ elsif !File.exist?(info_file_empty) && File.exist?(info_file_auto)
185
+ "layers/custom/#{topic_name.downcase}/auto/#{info_fname[1..-10]}"
186
+ else
187
+ nil
188
+ end
189
+ end
190
+ end
191
+
192
+ def infotext(count)
193
+ count > 0 ? "resultcount_p" : "resultcount_s"
194
+ end
195
+
196
+ def infotab
197
+ # INFOLAYOUT=0^1^2^3^4^5^6^7 *** Wenn der Parameter = 1 ist, wird ein leerer String �bergeben.
198
+ # *** Wenn der Parameter = 0 ist, wird der entsprechende Teil weggelassen wenn m�glich
199
+ #
200
+ # LayoutString(0) = "Im Umkreis von <EM>xUmkreisx</EM> Meter(n) wurde <EM>xAnzahlx</EM> Datensatz gefunden.<br><br>"
201
+ # LayoutString(1) = "Im Umkreis von <EM>xUmkreisx</EM> Meter(n) wurden <EM>xAnzahlx</EM> Datens&aumltze gefunden.<br><br>"
202
+ # LayoutString(2) = "layer"
203
+ # LayoutString(3) = "infotext"
204
+ # LayoutString(4) = "infotab"
205
+ # LayoutString(5) = "tabtitle"
206
+ # LayoutString(6) = "tabcell"
207
+ # LayoutString(7) = "2" ( If = "" Then 1 Tabellenzeile pro Record [z.B. "1" oder ""], else [z.B. "2"] 1 Zeile pro Feld)
208
+
209
+ "infotable_horizontal"
210
+ end
211
+
212
+ def legend_fname
213
+ "_#{name}_legend.html.erb"
214
+ end
215
+
216
+ def legend_file
217
+ File.join(Rails.root, 'app', 'views', 'layers', 'custom', topic_name.downcase, legend_fname)
218
+ end
219
+
220
+ def legend_file_auto
221
+ File.join(Rails.root, 'app', 'views', 'layers', 'custom', topic_name.downcase, 'auto', legend_fname)
222
+ end
223
+
224
+ def legend
225
+ @legend ||= begin
226
+ if File.exist?(legend_file)
227
+ "layers/custom/#{topic_name.downcase}/#{legend_fname[1..-10]}"
228
+ elsif File.exist?(legend_file_auto)
229
+ "layers/custom/#{topic_name.downcase}/auto/#{legend_fname[1..-10]}"
230
+ else
231
+ nil
232
+ end
233
+ end
234
+ end
235
+
236
+ def quoted_wms_layers
237
+ wms_layers.split(',').collect {|l| %Q<"#{l}"> }.join(',')
238
+ end
239
+
240
+ DEFAULT_SELECTION_STYLE = {
241
+ 'POLYGON' =>
242
+ '<PolygonSymbolizer>'+
243
+ '<Fill>'+
244
+ '<CssParameter name="fill">#ff0090</CssParameter>'+
245
+ '<CssParameter name="fill-opacity">0.6</CssParameter>'+
246
+ '</Fill>'+
247
+ '<Stroke>'+
248
+ '<CssParameter name="stroke">#ff0090</CssParameter>'+
249
+ '<CssParameter name="stroke-width">2.00</CssParameter>'+
250
+ '</Stroke>'+
251
+ '</PolygonSymbolizer>',
252
+ 'LINESTRING' =>
253
+ '<LineSymbolizer>'+
254
+ '<Stroke>'+
255
+ '<CssParameter name="stroke">#ff0090</CssParameter>'+
256
+ '<CssParameter name="stroke-width">10.00</CssParameter>'+
257
+ '</Stroke>'+
258
+ '</LineSymbolizer>',
259
+ 'POINT' =>
260
+ '<PointSymbolizer>'+
261
+ '<Graphic>'+
262
+ '<Mark>'+
263
+ '<WellKnownName>circle</WellKnownName>'+
264
+ '<Fill>'+
265
+ '<CssParameter name="fill">#ff0090</CssParameter>'+
266
+ '</Fill>'+
267
+ '</Mark>'+
268
+ '<Size>45.0</Size>'+
269
+ '</Graphic>'+
270
+ '</PointSymbolizer>'
271
+ }
272
+
273
+ def selection_symbolizer
274
+ if selection_style.blank?
275
+ gtyp = feature_class.geometry_type.sub(/^MULTI/, '').sub(/M$/, '') #MULTIPOINTM -> POINT
276
+ logger.error "Unsupported selection geometry type #{feature_class.geometry_type}" unless DEFAULT_SELECTION_STYLE.has_key?(gtyp)
277
+ DEFAULT_SELECTION_STYLE[gtyp] || ''
278
+ else
279
+ selection_style
280
+ end
281
+ end
282
+
283
+ end
@@ -1 +1,3 @@
1
- #::RGeo::ActiveRecord::GeometryMixin.set_json_generator(:geojson)
1
+ require 'rgeo-activerecord' # required by activerecord-postgis-adapter
2
+
3
+ ::RGeo::ActiveRecord::GeometryMixin.set_json_generator(:geojson)
@@ -7,3 +7,8 @@ module GbMapfishAppserver
7
7
  engine_name "mapfish"
8
8
  end
9
9
  end
10
+
11
+ SearchRule = Struct.new(:model, :fields, :alias_fields)
12
+
13
+ LocateRule = Struct.new(:model, :layer, :search_field)
14
+
@@ -1,3 +1,3 @@
1
1
  module GbMapfishAppserver
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -37,7 +37,7 @@ module Mapfish
37
37
  ENV['DEFAULT_SITE'] = options["default-site-name"]
38
38
  ENV['ADMIN_PWD'] = SecureRandom.hex(4)
39
39
  begin
40
- MapfishAppserver::Engine.load_seed
40
+ GbMapfishAppserver::Engine.load_seed
41
41
  puts "Generated user for administraton"
42
42
  puts "User: 'admin' - Password: '#{ENV['ADMIN_PWD']}'"
43
43
  rescue
@@ -56,6 +56,16 @@ module Mapfish
56
56
  end
57
57
  end
58
58
 
59
+ def add_search_rules_initializer
60
+ path = "#{Rails.root}/config/initializers/search_rules.rb"
61
+ if File.exists?(path)
62
+ puts "Skipping config/initializers/search_rules.rb creation, as file already exists!"
63
+ else
64
+ puts "Adding search_rules initializer (config/initializers/search_rules.rb)..."
65
+ template "search_rules.rb", path
66
+ end
67
+ end
68
+
59
69
  def rm_application_controller
60
70
  remove_file "#{Rails.root}/app/controllers/application_controller.rb"
61
71
  end
@@ -23,8 +23,3 @@ DEFAULT_Y = 252000
23
23
 
24
24
  # regex for WMS parameters to detect if layer filter is used
25
25
  LAYER_FILTER_REGEX = /^filter_.+$/i
26
-
27
- #Load models in models/geo/ (why not automatically loaded?)
28
- Dir[File.join(Rails.root, "app", "models", "geo", "*.rb")].each do |geomodel|
29
- require_dependency geomodel
30
- end
@@ -0,0 +1,5 @@
1
+ SEARCHRULES = {
2
+ }
3
+
4
+ LOCATERULES = {
5
+ }
@@ -3,15 +3,16 @@ namespace :mapfile do
3
3
  require 'rubygems'
4
4
  require 'iconv'
5
5
 
6
- desc "Create a topic from a mapfile. MAPFILE=file SITE=host"
6
+ desc "Create a topic from a mapfile. MAPFILE=file SITE=host DBONLY=false"
7
7
  task :import_topic => :environment do
8
8
  mapfile = ENV['MAPFILE']
9
9
  site = ENV['SITE'] || SITE_DEFAULT #Use empty string for unpublished map
10
+ dbonly = ENV['DBONLY'] || false
10
11
  if mapfile.nil?
11
12
  puts "Error: Missing argument MAPFILE"
12
13
  else
13
14
  import = MapfileImport.new(mapfile, site)
14
- import.import
15
+ import.import(dbonly)
15
16
  end
16
17
  end
17
18
 
@@ -40,7 +41,7 @@ namespace :mapfile do
40
41
  @ic = Iconv.new('UTF-8','LATIN1')
41
42
  end
42
43
 
43
- def import
44
+ def import(dbonly = false)
44
45
  topic = Topic.find_or_create_by_name(@map.name)
45
46
  topic.title = @map.web.metadata['ows_title'] || @map.web.metadata['wms_title']
46
47
  puts "Importing topic '#{topic.name}' with title '#{topic.title}'"
@@ -133,73 +134,75 @@ namespace :mapfile do
133
134
 
134
135
  layer.save!
135
136
 
136
- #Info & Legend
137
- mkdir_p File.dirname(layer.info_file_auto)
137
+ unless dbonly
138
+ #Info & Legend
139
+ mkdir_p File.dirname(layer.info_file_auto)
138
140
 
139
- if queryable
140
- if mlayer.type == MS_LAYER_RASTER || mlayer.type == MS_LAYER_ANNOTATION
141
- puts "Warning: Raster/Anntotation layer '#{layer.name}' is queryable (TEMPLATE #{mlayer.template})"
142
- end
143
- #puts "Creating #{layer.info_file_auto}"
144
- fields = layer.ident_fields.split(',') rescue []
145
- aliases = if fields.empty?
146
- puts "Warning: Query layer '#{layer.name}' has no attribute definition (wms_include_items)"
147
- []
148
- else
149
- layer.alias_fields.split(',')
150
- end
151
- infotab_template = "_infotable_auto"
152
- template = File.open(File.join(File.dirname(__FILE__), 'templates', "#{infotab_template}.html.erb")).read
153
- template = ERB.new(template, nil, '<>')
154
- File.open(layer.info_file_auto, 'w') do |file|
155
- file << template.result(binding)
141
+ if queryable
142
+ if mlayer.type == MS_LAYER_RASTER || mlayer.type == MS_LAYER_ANNOTATION
143
+ puts "Warning: Raster/Anntotation layer '#{layer.name}' is queryable (TEMPLATE #{mlayer.template})"
144
+ end
145
+ #puts "Creating #{layer.info_file_auto}"
146
+ fields = layer.ident_fields.split(',') rescue []
147
+ aliases = if fields.empty?
148
+ puts "Warning: Query layer '#{layer.name}' has no attribute definition (wms_include_items)"
149
+ []
150
+ else
151
+ layer.alias_fields.split(',')
152
+ end
153
+ infotab_template = "_infotable_auto"
154
+ template = File.open(File.join(File.dirname(__FILE__), 'templates', "#{infotab_template}.html.erb")).read
155
+ template = ERB.new(template, nil, '<>')
156
+ File.open(layer.info_file_auto, 'w') do |file|
157
+ file << template.result(binding)
158
+ end
156
159
  end
157
- end
158
160
 
159
- # Layer legend
160
- legend_icon_path = File.join(Rails.root, 'public', 'images', 'custom', topic_name.downcase)
161
- mkdir_p legend_icon_path
162
- if mlayer.type != MS_LAYER_RASTER && mlayer.type != MS_LAYER_ANNOTATION
163
- #puts "Creating #{layer.legend_file_auto}"
164
- File.open(layer.legend_file_auto, 'w') do |file|
165
- file << "<table class='legtab'>\n"
166
- mlayer.classes.each_with_index do |lclass, i|
167
- #Symbol size for Polygon and Line layers
168
- width = 23
169
- height = 13
170
- filename = nil
171
- if mlayer.type == MS_LAYER_POINT
172
- style = lclass.styles.first
173
- if style.nil?
174
- puts "Warning: Missing style in layer '#{layer.name}'"
175
- else
176
- symbol = @map.symbolset.symbols[style.symbol]
177
- if style.size > 0
178
- width = height = style.size.to_i+1
179
- end
180
- if symbol.imagepath
181
- filename = symbol.imagepath
161
+ # Layer legend
162
+ legend_icon_path = File.join(Rails.root, 'public', 'images', 'custom', topic_name.downcase)
163
+ mkdir_p legend_icon_path
164
+ if mlayer.type != MS_LAYER_RASTER && mlayer.type != MS_LAYER_ANNOTATION
165
+ #puts "Creating #{layer.legend_file_auto}"
166
+ File.open(layer.legend_file_auto, 'w') do |file|
167
+ file << "<table class='legtab'>\n"
168
+ mlayer.classes.each_with_index do |lclass, i|
169
+ #Symbol size for Polygon and Line layers
170
+ width = 23
171
+ height = 13
172
+ filename = nil
173
+ if mlayer.type == MS_LAYER_POINT
174
+ style = lclass.styles.first
175
+ if style.nil?
176
+ puts "Warning: Missing style in layer '#{layer.name}'"
177
+ else
178
+ symbol = @map.symbolset.symbols[style.symbol]
179
+ if style.size > 0
180
+ width = height = style.size.to_i+1
181
+ end
182
+ if symbol.imagepath
183
+ filename = symbol.imagepath
184
+ end
182
185
  end
183
186
  end
184
- end
185
- if filename.nil?
186
- begin
187
- icon = lclass.createLegendIcon(@map, mlayer, width, height)
188
- filename = "#{layer.name}#{i}.png"
189
- icon.save(File.join(legend_icon_path, filename))
190
- rescue Exception => e
191
- puts "Warning: createLegendIcon for class '#{lclass.name}' failed: #{e}"
187
+ if filename.nil?
188
+ begin
189
+ icon = lclass.createLegendIcon(@map, mlayer, width, height)
190
+ filename = "#{layer.name}#{i}.png"
191
+ icon.save(File.join(legend_icon_path, filename))
192
+ rescue Exception => e
193
+ puts "Warning: createLegendIcon for class '#{lclass.name}' failed: #{e}"
194
+ end
195
+ else
196
+ symfile = File.join(@map.mappath, filename)
197
+ filename = File.basename(filename)
198
+ cp(symfile, File.join(legend_icon_path, filename))
192
199
  end
193
- else
194
- symfile = File.join(@map.mappath, filename)
195
- filename = File.basename(filename)
196
- cp(symfile, File.join(legend_icon_path, filename))
200
+ sympath ="/images/custom/#{topic_name.downcase}/#{filename}"
201
+ legtext = lclass.name.force_encoding('utf-8').encode || lclass.getExpressionString
202
+ file << " <%= leg_tab_row('#{legtext}', '#{sympath}') %>\n"
197
203
  end
198
- sympath ="/images/custom/#{topic_name.downcase}/#{filename}"
199
- legtext = lclass.name || lclass.getExpressionString
200
- file << " <%= leg_tab_row('#{legtext}', '#{sympath}') %>\n"
204
+ file << "</table>\n"
201
205
  end
202
- file << "</table>\n"
203
206
  end
204
207
  end
205
208
 
@@ -213,20 +216,22 @@ namespace :mapfile do
213
216
  tl.save!
214
217
  end
215
218
 
216
- #Legend Template
217
- mkdir_p File.dirname(topic.legend_file_auto)
218
- MapfileImport.gen_topic_legend(topic)
219
+ unless dbonly
220
+ #Legend Template
221
+ mkdir_p File.dirname(topic.legend_file_auto)
222
+ MapfileImport.gen_topic_legend(topic)
219
223
 
220
- #Info Header Template
221
- #puts "Creating #{topic.info_header_file}"
222
- touch(topic.info_header_file)
224
+ #Info Header Template
225
+ #puts "Creating #{topic.info_header_file}"
226
+ touch(topic.info_header_file)
223
227
 
224
- #Topic icon
225
- topic_icon = File.join(Rails.root, 'public', 'images', 'custom', topic.icon_fname)
226
- unless File.exist?(topic_icon)
227
- mkdir_p File.dirname(topic_icon)
228
- cp(File.join(File.dirname(__FILE__), 'templates', 'themekl-default.gif'),
229
- topic_icon)
228
+ #Topic icon
229
+ topic_icon = File.join(Rails.root, 'public', 'images', 'custom', topic.icon_fname)
230
+ unless File.exist?(topic_icon)
231
+ mkdir_p File.dirname(topic_icon)
232
+ cp(File.join(File.dirname(__FILE__), 'templates', 'themekl-default.gif'),
233
+ topic_icon)
234
+ end
230
235
  end
231
236
 
232
237
  unless @site.empty?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gb_mapfish_appserver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-16 00:00:00.000000000 Z
12
+ date: 2013-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &17509680 !ruby/object:Gem::Requirement
16
+ requirement: &23143380 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.2.13
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *17509680
24
+ version_requirements: *23143380
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json
27
- requirement: &17509260 !ruby/object:Gem::Requirement
27
+ requirement: &23142780 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *17509260
35
+ version_requirements: *23142780
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: acts_as_tree
38
- requirement: &17508720 !ruby/object:Gem::Requirement
38
+ requirement: &23139880 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - =
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 0.2.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *17508720
46
+ version_requirements: *23139880
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: devise
49
- requirement: &17508220 !ruby/object:Gem::Requirement
49
+ requirement: &23139360 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - =
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.0.4
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *17508220
57
+ version_requirements: *23139360
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: cancan
60
- requirement: &17507760 !ruby/object:Gem::Requirement
60
+ requirement: &23138860 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - =
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.6.7
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *17507760
68
+ version_requirements: *23138860
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rails_admin
71
- requirement: &17523680 !ruby/object:Gem::Requirement
71
+ requirement: &23154640 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - =
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 0.0.5
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *17523680
79
+ version_requirements: *23154640
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: fastercsv
82
- requirement: &17523300 !ruby/object:Gem::Requirement
82
+ requirement: &23154220 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,21 @@ dependencies:
87
87
  version: '0'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *17523300
90
+ version_requirements: *23154220
91
+ - !ruby/object:Gem::Dependency
92
+ name: GeoRuby
93
+ requirement: &23153320 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: 0.1.4
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *23153320
91
102
  - !ruby/object:Gem::Dependency
92
103
  name: rgeo
93
- requirement: &17522760 !ruby/object:Gem::Requirement
104
+ requirement: &23152540 !ruby/object:Gem::Requirement
94
105
  none: false
95
106
  requirements:
96
107
  - - =
@@ -98,10 +109,10 @@ dependencies:
98
109
  version: 0.3.20
99
110
  type: :runtime
100
111
  prerelease: false
101
- version_requirements: *17522760
112
+ version_requirements: *23152540
102
113
  - !ruby/object:Gem::Dependency
103
114
  name: rgeo-geojson
104
- requirement: &17522260 !ruby/object:Gem::Requirement
115
+ requirement: &23152040 !ruby/object:Gem::Requirement
105
116
  none: false
106
117
  requirements:
107
118
  - - =
@@ -109,10 +120,10 @@ dependencies:
109
120
  version: 0.2.1
110
121
  type: :runtime
111
122
  prerelease: false
112
- version_requirements: *17522260
123
+ version_requirements: *23152040
113
124
  - !ruby/object:Gem::Dependency
114
125
  name: pg
115
- requirement: &17521800 !ruby/object:Gem::Requirement
126
+ requirement: &23151580 !ruby/object:Gem::Requirement
116
127
  none: false
117
128
  requirements:
118
129
  - - =
@@ -120,10 +131,10 @@ dependencies:
120
131
  version: 0.14.0
121
132
  type: :runtime
122
133
  prerelease: false
123
- version_requirements: *17521800
134
+ version_requirements: *23151580
124
135
  - !ruby/object:Gem::Dependency
125
136
  name: activerecord-postgis-adapter
126
- requirement: &17521340 !ruby/object:Gem::Requirement
137
+ requirement: &23151060 !ruby/object:Gem::Requirement
127
138
  none: false
128
139
  requirements:
129
140
  - - =
@@ -131,7 +142,7 @@ dependencies:
131
142
  version: 0.4.1
132
143
  type: :runtime
133
144
  prerelease: false
134
- version_requirements: *17521340
145
+ version_requirements: *23151060
135
146
  description: Mapfish Appserver is a framework for web mapping applications using OGC
136
147
  standards and the Mapfish protocol.
137
148
  email:
@@ -168,9 +179,9 @@ files:
168
179
  - app/views/groups_users/_form.html.erb
169
180
  - app/views/groups_users/show.html.erb
170
181
  - app/views/apps/_request_state.html.erb
171
- - app/views/apps/show.html.erb
172
182
  - app/views/layouts/embedded.html.erb
173
183
  - app/views/layouts/application.html.erb
184
+ - app/controllers/print_controller.rb~
174
185
  - app/controllers/registrations_controller.rb
175
186
  - app/controllers/categories_controller.rb
176
187
  - app/controllers/application_controller.rb
@@ -196,6 +207,7 @@ files:
196
207
  - app/models/gbapplication.rb
197
208
  - app/models/geo_model.rb
198
209
  - app/models/category.rb
210
+ - app/models/layer.rb~
199
211
  - app/models/wfs.rb
200
212
  - app/models/group.rb
201
213
  - app/models/user.rb
@@ -222,7 +234,6 @@ files:
222
234
  - config/initializers/devise.rb
223
235
  - config/initializers/geodb.rb
224
236
  - config/initializers/rails_admin.rb
225
- - config/initializers/search_rules.rb
226
237
  - config/initializers/rgeo.rb
227
238
  - config/routes.rb
228
239
  - db/seeds.rb
@@ -240,6 +251,7 @@ files:
240
251
  - lib/generators/mapfish/viewer/templates/viewer.html.erb
241
252
  - lib/generators/mapfish/install/install_generator.rb
242
253
  - lib/generators/mapfish/install/templates/print.yml
254
+ - lib/generators/mapfish/install/templates/search_rules.rb
243
255
  - lib/generators/mapfish/install/templates/sencha/workspace/sencha.cfg
244
256
  - lib/generators/mapfish/install/templates/sencha/workspace/plugin.xml
245
257
  - lib/generators/mapfish/install/templates/geodatabase.yml
@@ -4656,12 +4668,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
4656
4668
  - - ! '>='
4657
4669
  - !ruby/object:Gem::Version
4658
4670
  version: '0'
4671
+ segments:
4672
+ - 0
4673
+ hash: 1722996203916667069
4659
4674
  required_rubygems_version: !ruby/object:Gem::Requirement
4660
4675
  none: false
4661
4676
  requirements:
4662
4677
  - - ! '>='
4663
4678
  - !ruby/object:Gem::Version
4664
4679
  version: '0'
4680
+ segments:
4681
+ - 0
4682
+ hash: 1722996203916667069
4665
4683
  requirements: []
4666
4684
  rubyforge_project:
4667
4685
  rubygems_version: 1.8.11
@@ -1,23 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
- <title>GIS-Browser</title>
6
- <base href="<%= request.protocol %><%= request.host %><%= request.port_string %>/apps/<%= @app %>/" />
7
- <link rel="stylesheet" type="text/css" href="resources/css/cdzh/app.css"/>
8
- <link rel="stylesheet" type="text/css" href="/lib/GbZh/css/gbzh.css"/>
9
- <link rel="stylesheet" type="text/css" href="/lib/GbZh/css/general.css"/>
10
- <script type="text/javascript" src="lib/openlayers/OpenLayers.js"></script>
11
- <script type="text/javascript" src="all-classes.js"></script>
12
- <%= render :partial => 'request_state' %>
13
- <script type="text/javascript" src="/lib/openlayers/lib/OpenLayers/Control/ArcIntersection.js"></script>
14
- <script type="text/javascript" src="/lib/openlayers/lib/OpenLayers/Control/OrthogonalLines.js"></script>
15
- <script type="text/javascript" src="/lib/proj4js/lib/proj4js-compressed.js"></script>
16
- <script type="text/javascript" src="/lib/proj4js/lib/defs/EPSG21781.js"></script>
17
- <script type="text/javascript" src="locale/gb41-lang-<%= I18n.locale %>.js"></script>
18
- <%= csrf_meta_tags %>
19
- </head>
20
- <body>
21
- <noscript>Bitte aktivieren Sie Javascript und Cookies, um diese Applikation zu nutzen!</noscript>
22
- </body>
23
- </html>
@@ -1,3 +0,0 @@
1
- SearchRule = Struct.new(:model, :fields, :alias_fields)
2
-
3
- LocateRule = Struct.new(:model, :layer, :search_field)