.ruby-version
.idea
coverage
+
+config/settings.local.yml
+config/settings/*.local.yml
+config/environments/*.local.yml
global:
- OSM_MEMCACHE_SERVERS="127.0.0.1"
before_script:
- - cp config/example.application.yml config/application.yml
- psql -U postgres -c "CREATE DATABASE openstreetmap"
- psql -U postgres -c "CREATE EXTENSION btree_gist" openstreetmap
- make -C db/functions libpgosm.so
After [installing](INSTALL.md) this software, you may need to carry out some of these configuration steps, depending on your tasks.
+## Application configuration
+
+Many settings are available in `config/settings.yml`. You can customize your installation of The Rails Port by overriding these values using `config/settings.local.yml`
+
## Populating the database
Your installation comes with no geographic data loaded. You can either create new data using one of the editors (Potlatch 2, iD, JOSM etc) or by loading an OSM extract.
* Everything else can be left with the default blank values.
* Click the "Register" button
* On the next page, copy the "consumer key"
-* Edit config/application.yml in your rails tree
-* Uncomment and change the "potlatch2_key" configuration value
+* Edit config/settings.local.yml in your rails tree
+* Add the "potlatch2_key" configuration key and the consumer key as the value
* Restart your rails server
-An example excerpt from application.yml:
+An example excerpt from settings.local.yml:
```
# Default editor
Follow the same process for registering and configuring iD (`id_key`) and the website/Notes (`oauth_key`), or to save time, simply reuse the same consumer key for each.
-**NOTE:** If you forget to set up OAuth, then you will get an error message similar to `uninitialized constant ActionView::CompiledTemplates::ID_KEY`.
-
## Troubleshooting
Rails has its own log. To inspect the log, do this:
gem "active_record_union"
gem "cancancan"
gem "composite_primary_keys", "~> 11.1.0"
+gem "config"
gem "delayed_job_active_record"
gem "dynamic_form"
gem "http_accept_language", "~> 2.0.0"
composite_primary_keys (11.1.0)
activerecord (~> 5.2.1)
concurrent-ruby (1.1.5)
+ config (1.7.1)
+ activesupport (>= 3.0)
+ deep_merge (~> 1.2.1)
+ dry-validation (>= 0.12.2)
coveralls (0.8.22)
json (>= 1.8, < 3)
simplecov (~> 0.16.1)
crass (1.0.4)
dalli (2.7.9)
debug_inspector (0.0.3)
+ deep_merge (1.2.1)
delayed_job (4.1.5)
activesupport (>= 3.0, < 5.3)
delayed_job_active_record (4.1.3)
activerecord (>= 3.0, < 5.3)
delayed_job (>= 3.0, < 5)
docile (1.3.1)
+ dry-configurable (0.8.2)
+ concurrent-ruby (~> 1.0)
+ dry-core (~> 0.4, >= 0.4.7)
+ dry-container (0.7.0)
+ concurrent-ruby (~> 1.0)
+ dry-configurable (~> 0.1, >= 0.1.3)
+ dry-core (0.4.7)
+ concurrent-ruby (~> 1.0)
+ dry-equalizer (0.2.2)
+ dry-inflector (0.1.2)
+ dry-logic (0.5.0)
+ dry-container (~> 0.2, >= 0.2.6)
+ dry-core (~> 0.2)
+ dry-equalizer (~> 0.2)
+ dry-types (0.14.0)
+ concurrent-ruby (~> 1.0)
+ dry-container (~> 0.3)
+ dry-core (~> 0.4, >= 0.4.4)
+ dry-equalizer (~> 0.2)
+ dry-inflector (~> 0.1, >= 0.1.2)
+ dry-logic (~> 0.5, >= 0.5)
+ dry-validation (0.13.0)
+ concurrent-ruby (~> 1.0)
+ dry-configurable (~> 0.1, >= 0.1.3)
+ dry-core (~> 0.2, >= 0.2.1)
+ dry-equalizer (~> 0.2)
+ dry-logic (~> 0.5, >= 0.5.0)
+ dry-types (~> 0.14, >= 0.14)
dynamic_form (1.1.4)
erubi (1.8.0)
execjs (2.7.0)
capybara (~> 2.13)
coffee-rails (~> 4.2)
composite_primary_keys (~> 11.1.0)
+ config
coveralls
dalli
delayed_job_active_record
bundle install
```
-## Application setup
-
-We need to create the `config/application.yml` file from the example template. This contains various configuration options.
-
-```
-cp config/example.application.yml config/application.yml
-```
-
-You can customize your installation of The Rails Port by changing the values in `config/application.yml`
-
## Database setup
The Rails Port uses three databases - one for development, one for testing, and one for production. The database-specific configuration
}
var thunderforestOptions = {
-<% if defined?(THUNDERFOREST_KEY) %>
- apikey: <%= THUNDERFOREST_KEY.to_json %>
+<% if Settings.key?(:thunderforest_key) %>
+ apikey: <%= Settings.thunderforest_key.to_json %>
<% end %>
};
-//= depend_on application.yml
+//= depend_on settings.yml
+//= depend_on settings.local.yml
OSM = {
<% if defined?(PIWIK) %>
PIWIK: <%= PIWIK.to_json %>,
<% end %>
- MAX_REQUEST_AREA: <%= MAX_REQUEST_AREA.to_json %>,
- SERVER_PROTOCOL: <%= SERVER_PROTOCOL.to_json %>,
- SERVER_URL: <%= SERVER_URL.to_json %>,
- API_VERSION: <%= API_VERSION.to_json %>,
+ MAX_REQUEST_AREA: <%= Settings.max_request_area.to_json %>,
+ SERVER_PROTOCOL: <%= Settings.server_protocol.to_json %>,
+ SERVER_URL: <%= Settings.server_url.to_json %>,
+ API_VERSION: <%= Settings.api_version.to_json %>,
STATUS: <%= STATUS.to_json %>,
- MAX_NOTE_REQUEST_AREA: <%= MAX_NOTE_REQUEST_AREA.to_json %>,
- OVERPASS_URL: <%= OVERPASS_URL.to_json %>,
- NOMINATIM_URL: <%= NOMINATIM_URL.to_json %>,
- GRAPHHOPPER_URL: <%= GRAPHHOPPER_URL.to_json %>,
- FOSSGIS_OSRM_URL: <%= FOSSGIS_OSRM_URL.to_json %>,
+ MAX_NOTE_REQUEST_AREA: <%= Settings.max_note_request_area.to_json %>,
+ OVERPASS_URL: <%= Settings.overpass_url.to_json %>,
+ NOMINATIM_URL: <%= Settings.nominatim_url.to_json %>,
+ GRAPHHOPPER_URL: <%= Settings.graphhopper_url.to_json %>,
+ FOSSGIS_OSRM_URL: <%= Settings.fossgis_osrm_url.to_json %>,
DEFAULT_LOCALE: <%= I18n.default_locale.to_json %>,
-<% if defined?(THUNDERFOREST_KEY) %>
- THUNDERFOREST_KEY: <%= THUNDERFOREST_KEY.to_json %>,
+<% if Settings.key?(:thunderforest_key) %>
+ THUNDERFOREST_KEY: <%= Settings.thunderforest_key.to_json %>,
<% end %>
MARKER_GREEN: <%= image_path("marker-green.png").to_json %>,
return 6372795 * 2 * Math.asin(
Math.sqrt(
- Math.pow(Math.sin(latdiff / 2), 2) +
+ Math.pow(Math.sin(latdiff / 2), 2) +
Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(lngdiff / 2), 2)
));
}
def amf_handle_error_with_timeout(call, rootobj, rootid)
amf_handle_error(call, rootobj, rootid) do
- OSM::Timer.timeout(API_TIMEOUT, OSM::APITimeoutError) do
+ OSM::Timer.timeout(Settings.api_timeout, OSM::APITimeoutError) do
yield
end
end
return
end
- nodes = Node.bbox(bbox).where(:visible => true).includes(:node_tags).limit(MAX_NUMBER_OF_NODES + 1)
+ nodes = Node.bbox(bbox).where(:visible => true).includes(:node_tags).limit(Settings.max_number_of_nodes + 1)
node_ids = nodes.collect(&:id)
- if node_ids.length > MAX_NUMBER_OF_NODES
- report_error("You requested too many nodes (limit is #{MAX_NUMBER_OF_NODES}). Either request a smaller area, or use planet.osm")
+ if node_ids.length > Settings.max_number_of_nodes
+ report_error("You requested too many nodes (limit is #{Settings.max_number_of_nodes}). Either request a smaller area, or use planet.osm")
return
end
bbox.check_boundaries
# Check the the bounding box is not too big
- bbox.check_size(MAX_NOTE_REQUEST_AREA)
+ bbox.check_size(Settings.max_note_request_area)
# Find the notes we want to return
@notes = notes.bbox(bbox).order("updated_at DESC").limit(result_limit).preload(:comments)
bbox = BoundingBox.from_bbox_params(params)
bbox.check_boundaries
- bbox.check_size(MAX_NOTE_REQUEST_AREA)
+ bbox.check_size(Settings.max_note_request_area)
notes = notes.bbox(bbox)
end
return
end
- offset = page * TRACEPOINTS_PER_PAGE
+ offset = page * Settings.tracepoints_per_page
# Figure out the bbox
# check boundary is sane and area within defined
# get all the points
ordered_points = Tracepoint.bbox(bbox).joins(:trace).where(:gpx_files => { :visibility => %w[trackable identifiable] }).order("gpx_id DESC, trackid ASC, timestamp ASC")
unordered_points = Tracepoint.bbox(bbox).joins(:trace).where(:gpx_files => { :visibility => %w[public private] }).order("gps_points.latitude", "gps_points.longitude", "gps_points.timestamp")
- points = ordered_points.union_all(unordered_points).offset(offset).limit(TRACEPOINTS_PER_PAGE)
+ points = ordered_points.union_all(unordered_points).offset(offset).limit(Settings.tracepoints_per_page)
doc = XML::Document.new
doc.encoding = XML::Encoding::UTF_8
end
def require_oauth
- @oauth = current_user.access_token(OAUTH_KEY) if current_user && defined? OAUTH_KEY
+ @oauth = current_user.access_token(Settings.oauth_key) if current_user && Settings.key?(:oauth_key)
end
##
##
# wrap an api call in a timeout
def api_call_timeout
- OSM::Timer.timeout(API_TIMEOUT, Timeout::Error) do
+ OSM::Timer.timeout(Settings.api_timeout, Timeout::Error) do
yield
end
rescue Timeout::Error
##
# wrap a web page in a timeout
def web_timeout
- OSM::Timer.timeout(WEB_TIMEOUT, Timeout::Error) do
+ OSM::Timer.timeout(Settings.web_timeout, Timeout::Error) do
yield
end
rescue ActionView::Template::Error => ex
append_content_security_policy_directives(
:child_src => %w[http://127.0.0.1:8111 https://127.0.0.1:8112],
:frame_src => %w[http://127.0.0.1:8111 https://127.0.0.1:8112],
- :connect_src => [NOMINATIM_URL, OVERPASS_URL, FOSSGIS_OSRM_URL, GRAPHHOPPER_URL],
+ :connect_src => [Settings.nominatim_url, Settings.overpass_url, Settings.fossgis_osrm_url, Settings.graphhopper_url],
:form_action => %w[render.openstreetmap.org],
:style_src => %w['unsafe-inline']
)
elsif current_user&.preferred_editor
current_user.preferred_editor
else
- DEFAULT_EDITOR
+ Settings.default_editor
end
editor
helper_method :preferred_editor
def update_totp
- if defined?(TOTP_KEY)
+ if Settings.key?(:totp_key)
cookies["_osm_totp_token"] = {
- :value => ROTP::TOTP.new(TOTP_KEY, :interval => 3600).now,
+ :value => ROTP::TOTP.new(Settings.totp_key, :interval => 3600).now,
:domain => "openstreetmap.org",
:expires => 1.hour.from_now
}
@entries = user.diary_entries
@title = t("diary_entries.feed.user.title", :user => user.display_name)
@description = t("diary_entries.feed.user.description", :user => user.display_name)
- @link = url_for :action => "index", :display_name => user.display_name, :host => SERVER_URL, :protocol => SERVER_PROTOCOL
+ @link = url_for :action => "index", :display_name => user.display_name, :host => Settings.server_url, :protocol => Settings.server_protocol
else
head :not_found
return
@entries = @entries.where(:language_code => params[:language])
@title = t("diary_entries.feed.language.title", :language_name => Language.find(params[:language]).english_name)
@description = t("diary_entries.feed.language.description", :language_name => Language.find(params[:language]).english_name)
- @link = url_for :action => "index", :language => params[:language], :host => SERVER_URL, :protocol => SERVER_PROTOCOL
+ @link = url_for :action => "index", :language => params[:language], :host => Settings.server_url, :protocol => Settings.server_protocol
else
@title = t("diary_entries.feed.all.title")
@description = t("diary_entries.feed.all.description")
- @link = url_for :action => "index", :host => SERVER_URL, :protocol => SERVER_PROTOCOL
+ @link = url_for :action => "index", :host => Settings.server_url, :protocol => Settings.server_protocol
end
end
if @params[:lat] && @params[:lon]
@sources.push "latlon"
@sources.push "osm_nominatim_reverse"
- @sources.push "geonames_reverse" if defined?(GEONAMES_USERNAME)
+ @sources.push "geonames_reverse" if Settings.key?(:geonames_username)
elsif @params[:query]
if @params[:query] =~ /^\d{5}(-\d{4})?$/
@sources.push "osm_nominatim"
@sources.push "osm_nominatim"
else
@sources.push "osm_nominatim"
- @sources.push "geonames" if defined?(GEONAMES_USERNAME)
+ @sources.push "geonames" if Settings.key?(:geonames_username)
end
end
if response.get_elements("geodata/error").empty?
@results.push(:lat => response.text("geodata/latt"),
:lon => response.text("geodata/longt"),
- :zoom => POSTCODE_ZOOM,
+ :zoom => Settings.postcode_zoom,
:name => query.upcase)
end
exclude = "&exclude_place_ids=#{params[:exclude]}" if params[:exclude]
# ask nominatim
- response = fetch_xml("#{NOMINATIM_URL}search?format=xml&extratags=1&q=#{escape_query(query)}#{viewbox}#{exclude}&accept-language=#{http_accept_language.user_preferred_languages.join(',')}")
+ response = fetch_xml("#{Settings.nominatim_url}search?format=xml&extratags=1&q=#{escape_query(query)}#{viewbox}#{exclude}&accept-language=#{http_accept_language.user_preferred_languages.join(',')}")
# extract the results from the response
results = response.elements["searchresults"]
@results = []
# ask geonames.org
- response = fetch_xml("http://api.geonames.org/search?q=#{escape_query(query)}&lang=#{lang}&maxRows=20&username=#{GEONAMES_USERNAME}")
+ response = fetch_xml("http://api.geonames.org/search?q=#{escape_query(query)}&lang=#{lang}&maxRows=20&username=#{Settings.geonames_username}")
# parse the response
response.elements.each("geonames/geoname") do |geoname|
country = geoname.text("countryName")
@results.push(:lat => lat, :lon => lon,
- :zoom => GEONAMES_ZOOM,
+ :zoom => Settings.geonames_zoom,
:name => name,
:suffix => ", #{country}")
end
@results = []
# ask nominatim
- response = fetch_xml("#{NOMINATIM_URL}reverse?lat=#{lat}&lon=#{lon}&zoom=#{zoom}&accept-language=#{http_accept_language.user_preferred_languages.join(',')}")
+ response = fetch_xml("#{Settings.nominatim_url}reverse?lat=#{lat}&lon=#{lon}&zoom=#{zoom}&accept-language=#{http_accept_language.user_preferred_languages.join(',')}")
# parse the response
response.elements.each("reversegeocode/result") do |result|
@results = []
# ask geonames.org
- response = fetch_xml("http://api.geonames.org/countrySubdivision?lat=#{lat}&lng=#{lon}&lang=#{lang}&username=#{GEONAMES_USERNAME}")
+ response = fetch_xml("http://api.geonames.org/countrySubdivision?lat=#{lat}&lng=#{lon}&lang=#{lang}&username=#{Settings.geonames_username}")
# parse the response
response.elements.each("geonames/countrySubdivision") do |geoname|
country = geoname.text("countryName")
@results.push(:lat => lat, :lon => lon,
- :zoom => GEONAMES_ZOOM,
+ :zoom => Settings.geonames_zoom,
:name => name,
:suffix => ", #{country}")
end
@message.sender = current_user
@message.sent_on = Time.now.getutc
- if current_user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= MAX_MESSAGES_PER_HOUR
+ if current_user.sent_messages.where("sent_on >= ?", Time.now.getutc - 1.hour).count >= Settings.max_messages_per_hour
flash[:error] = t ".limit_exceeded"
render :action => "new"
elsif @message.save
end
def oauth1_authorize
- override_content_security_policy_directives(:form_action => []) if CSP_ENFORCE || defined?(CSP_REPORT_URL)
+ override_content_security_policy_directives(:form_action => []) if Settings.csp_enforce || Settings.key?(:csp_report_url)
if @token.invalidated?
@message = t "oauth.authorize_failure.invalid"
flash[:notice] = t ".trace_uploaded"
flash[:warning] = t ".traces_waiting", :count => current_user.traces.where(:inserted => false).count if current_user.traces.where(:inserted => false).count > 4
- TraceImporterJob.perform_later(@trace) if TRACE_USE_JOB_QUEUE
+ TraceImporterJob.perform_later(@trace) if Settings.trace_use_job_queue
redirect_to :action => :index, :display_name => current_user.display_name
else
flash[:error] = t("traces.create.upload_failed") if @trace.valid?
trace.visible = false
trace.save
flash[:notice] = t ".scheduled_for_deletion"
- TraceDestroyerJob.perform_later(trace) if TRACE_USE_JOB_QUEUE
+ TraceDestroyerJob.perform_later(trace) if Settings.trace_use_job_queue
redirect_to :action => :index, :display_name => trace.user.display_name
end
rescue ActiveRecord::RecordNotFound
before_action :allow_thirdparty_images, :only => [:show, :account]
def terms
- @legale = params[:legale] || OSM.ip_to_country(request.remote_ip) || DEFAULT_LEGALE
+ @legale = params[:legale] || OSM.ip_to_country(request.remote_ip) || Settings.default_legale
@text = OSM.legal_text_for_country(@legale)
if request.xhr?
flash[:error] = t "users.confirm_resend.failure", :name => params[:display_name]
else
Notifier.signup_confirm(user, user.tokens.create).deliver_later
- flash[:notice] = t("users.confirm_resend.success", :email => user.email, :sender => SUPPORT_EMAIL).html_safe
+ flash[:notice] = t("users.confirm_resend.success", :email => user.email, :sender => Settings.support_email).html_safe
end
redirect_to :action => "login"
when "active", "confirmed" then
successful_login(user, request.env["omniauth.params"]["referer"])
when "suspended" then
- failed_login t("users.login.account is suspended", :webmaster => "mailto:#{SUPPORT_EMAIL}").html_safe
+ failed_login t("users.login.account is suspended", :webmaster => "mailto:#{Settings.support_email}").html_safe
else
failed_login t("users.login.auth failure")
end
elsif user = User.authenticate(:username => username, :password => password, :pending => true)
unconfirmed_login(user)
elsif User.authenticate(:username => username, :password => password, :suspended => true)
- failed_login t("users.login.account is suspended", :webmaster => "mailto:#{SUPPORT_EMAIL}").html_safe, username
+ failed_login t("users.login.account is suspended", :webmaster => "mailto:#{Settings.support_email}").html_safe, username
else
failed_login t("users.login.auth failure"), username
end
# the <a> but Outlook only on the <strong>
:style => "text-decoration: none"
),
- user_url(display_name, :host => SERVER_URL),
+ user_url(display_name, :host => Settings.server_url),
:target => "_blank",
:rel => "noopener",
:style => "text-decoration: none; color: #222"
class Notifier < ActionMailer::Base
- default :from => EMAIL_FROM,
- :return_path => EMAIL_RETURN_PATH,
+ default :from => Settings.email_from,
+ :return_path => Settings.email_return_path,
:auto_submitted => "auto-generated"
helper :application
before_action :set_shared_template_vars
end
def from_address(name, type, id, digest, user_id = nil)
- if Object.const_defined?(:MESSAGES_DOMAIN) && domain = MESSAGES_DOMAIN
+ if Settings.key?(:messages_domain) && domain = Settings.messages_domain
if user_id
"#{name} <#{type}-#{id}-#{user_id}-#{digest[0, 6]}@#{domain}>"
else
"#{name} <#{type}-#{id}-#{digest[0, 6]}@#{domain}>"
end
else
- EMAIL_FROM
+ Settings.email_from
end
end
end
end
def oauth_server
- @oauth_server ||= OAuth::Server.new("https://" + SERVER_URL)
+ @oauth_server ||= OAuth::Server.new("https://" + Settings.server_url)
end
def credentials
end
def oauth10?
- (defined? OAUTH_10_SUPPORT) && OAUTH_10_SUPPORT && callback_url.blank?
+ Settings.key?(:oauth_10_support) && Settings.oauth_10_support && callback_url.blank?
end
end
end
def large_picture_name
- "#{GPX_IMAGE_DIR}/#{id}.gif"
+ "#{Settings.gpx_image_dir}/#{id}.gif"
end
def icon_picture_name
- "#{GPX_IMAGE_DIR}/#{id}_icon.gif"
+ "#{Settings.gpx_image_dir}/#{id}_icon.gif"
end
def trace_name
- "#{GPX_TRACE_DIR}/#{id}.gpx"
+ "#{Settings.gpx_trace_dir}/#{id}.gpx"
end
def mime_type
@preferred_languages = nil
end
- def nearby(radius = NEARBY_RADIUS, num = NEARBY_USERS)
+ def nearby(radius = Settings.nearby_radius, num = Settings.nearby_users)
if home_lon && home_lat
gc = OSM::GreatCircle.new(home_lat, home_lon)
sql_for_area = QuadTile.sql_for_area(gc.bounds(radius), "home_")
##
# perform a spam check on a user
def spam_check
- update(:status => "suspended") if status == "active" && spam_score > SPAM_THRESHOLD
+ update(:status => "suspended") if status == "active" && spam_score > Settings.spam_threshold
end
##
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
belongs_to :revoker, :class_name => "User", :foreign_key => :revoker_id
- PERIODS = USER_BLOCK_PERIODS
+ PERIODS = Settings.user_block_periods
##
# scope to match active blocks
def preconditions_ok?(old_nodes = [])
return false if nds.empty?
- raise OSM::APITooManyWayNodesError.new(id, nds.length, MAX_NUMBER_OF_WAY_NODES) if nds.length > MAX_NUMBER_OF_WAY_NODES
+ raise OSM::APITooManyWayNodesError.new(id, nds.length, Settings.max_number_of_way_nodes) if nds.length > Settings.max_number_of_way_nodes
# check only the new nodes, for efficiency - old nodes having been checked last time and can't
# be deleted when they're in-use.
xml.instruct! :xml, :version => "1.0"
xml.osm(OSM::API.new.xml_root_attributes) do |osm|
osm.api do |api|
- api.version(:minimum => API_VERSION.to_s, :maximum => API_VERSION.to_s)
- api.area(:maximum => MAX_REQUEST_AREA.to_s)
- api.note_area(:maximum => MAX_NOTE_REQUEST_AREA.to_s)
- api.tracepoints(:per_page => TRACEPOINTS_PER_PAGE.to_s)
- api.waynodes(:maximum => MAX_NUMBER_OF_WAY_NODES.to_s)
- api.changesets(:maximum_elements => Changeset::MAX_ELEMENTS.to_s)
- api.timeout(:seconds => API_TIMEOUT.to_s)
- api.status(:database => @database_status.to_s,
- :api => @api_status.to_s,
- :gpx => @gpx_status.to_s)
+ api.version(:minimum => Settings.api_version, :maximum => Settings.api_version)
+ api.area(:maximum => Settings.max_request_area)
+ api.note_area(:maximum => Settings.max_note_request_area)
+ api.tracepoints(:per_page => Settings.tracepoints_per_page)
+ api.waynodes(:maximum => Settings.max_number_of_way_nodes)
+ api.changesets(:maximum_elements => Changeset::MAX_ELEMENTS)
+ api.timeout(:seconds => Settings.api_timeout)
+ api.status(:database => @database_status,
+ :api => @api_status,
+ :gpx => @gpx_status)
end
osm.policy do |policy|
policy.imagery do |imagery|
- IMAGERY_BLACKLIST.each do |url_regex|
+ Settings.imagery_blacklist.each do |url_regex|
imagery.blacklist(:regex => url_regex.to_s)
end
end
<%= tag("meta", { :name => "msapplication-TileImage", :content => image_path("mstile-144x144.png") }) %>
<%= tag("meta", { :name => "theme-color", :content => "#ffffff" }) %>
<%= canonical_tag %>
- <% if defined?(PUBLISHER_URL) -%>
- <%= tag("link", { :rel => "publisher", :href => PUBLISHER_URL }) %>
+ <% if Settings.key?(:publisher_url) -%>
+ <%= tag("link", { :rel => "publisher", :href => Settings.publisher_url }) %>
<% end -%>
<%= tag("link", { :rel => "search", :type => "application/opensearchdescription+xml", :title => "OpenStreetMap Search", :href => asset_path("osm.xml") }) %>
<%= tag("meta", { :name => "description", :content => "OpenStreetMap is the free wiki world map." }) %>
<p><%= t 'notifier.email_confirm_html.greeting' %></p>
-<p><%= t 'notifier.email_confirm_html.hopefully_you', :server_url => SERVER_URL, :new_address => @address %></p>
+<p><%= t 'notifier.email_confirm_html.hopefully_you', :server_url => Settings.server_url, :new_address => @address %></p>
<p><%= t 'notifier.email_confirm_html.click_the_link' %></p>
<%= t 'notifier.email_confirm_plain.greeting' %>
-<%= word_wrap(t 'notifier.email_confirm_plain.hopefully_you', :server_url => SERVER_URL, :new_address => @address) %>
+<%= word_wrap(t 'notifier.email_confirm_plain.hopefully_you', :server_url => Settings.server_url, :new_address => @address) %>
<%= t 'notifier.email_confirm_plain.click_the_link' %>
<p><%= t(".greeting") %></p>
-<p><%= t(".created", :site_url => SERVER_URL) %></p>
+<p><%= t(".created", :site_url => Settings.server_url) %></p>
<p><%= t(".confirm") %></p>
<%= fp(t(".greeting")) %>
-<%= fp(t(".created", :site_url => SERVER_URL)) %>
+<%= fp(t(".created", :site_url => Settings.server_url)) %>
<%= fp(t(".confirm")) %>
<%= javascript_include_tag "edit/id" %>
<div id="map">
- <% data = { :key => ID_KEY } -%>
+ <% data = { :key => Settings.id_key } -%>
<% data[:lat] = @lat if @lat -%>
<% data[:lon] = @lon if @lon -%>
<% data[:gpx] = trace_data_url(params[:gpx], :format => :xml) if params[:gpx] -%>
<% data[:lat] = @lat if @lat -%>
<% data[:lon] = @lon if @lon -%>
<% data[:zoom] = @zoom if @zoom -%>
- <% if defined? POTLATCH2_KEY %>
- <% token = current_user.access_token(POTLATCH2_KEY) %>
+ <% if Settings.key?(:potlatch2_key) %>
+ <% token = current_user.access_token(Settings.potlatch2_key) %>
<% data[:token] = token.token -%>
<% data[:token_secret] = token.secret -%>
<% data[:consumer_key] = token.client_application.key -%>
</head>
<body>
<% data = {} -%>
-<% if defined? ID_KEY %>
-<% token = current_user.access_token(ID_KEY) %>
+<% if Settings.key?(:id_key) %>
+<% token = current_user.access_token(Settings.id_key) %>
<% data[:token] = token.token -%>
<% data[:token_secret] = token.secret -%>
<% data[:consumer_key] = token.client_application.key -%>
</div>
<div class="form-row">
<label class="standard-label"><%= t '.preferred editor' %></label>
- <%= f.select :preferred_editor, [[t("editor.default", :name => t("editor.#{DEFAULT_EDITOR}.name")), 'default']] + Editors::ALL_EDITORS.collect { |e| [t("editor.#{e}.description"), e] } %>
+ <%= f.select :preferred_editor, [[t("editor.default", :name => t("editor.#{Settings.default_editor}.name")), 'default']] + Editors::ALL_EDITORS.collect { |e| [t("editor.#{e}.description"), e] } %>
</div>
</fieldset>
<div class="message">
<h1><%= t 'users.new.no_auto_account_create' %></h1>
- <h2><%= raw t 'users.new.contact_webmaster', :webmaster => "mailto:#{SUPPORT_EMAIL}" %></h2>
+ <h2><%= raw t 'users.new.contact_webmaster', :webmaster => "mailto:#{Settings.support_email}" %></h2>
</div>
<ul class='clearfix' id="login_auth_buttons">
<li><%= link_to image_tag("openid.png", :alt => t(".auth_providers.openid.title")), "#", :id => "openid_open_url", :title => t(".auth_providers.openid.title") %></li>
- <% if defined?(GOOGLE_AUTH_ID) -%>
+ <% if Settings.key?(:google_auth_id) -%>
<li><%= auth_button "google", "google" %></li>
<% end -%>
- <% if defined?(FACEBOOK_AUTH_ID) -%>
+ <% if Settings.key?(:facebook_auth_id) -%>
<li><%= auth_button "facebook", "facebook" %></li>
<% end -%>
- <% if defined?(WINDOWSLIVE_AUTH_ID) -%>
+ <% if Settings.key?(:windowslive_auth_id) -%>
<li><%= auth_button "windowslive", "windowslive" %></li>
<% end -%>
- <% if defined?(GITHUB_AUTH_ID) -%>
+ <% if Settings.key?(:github_auth_id) -%>
<li><%= auth_button "github", "github" %></li>
<% end -%>
- <% if defined?(WIKIPEDIA_AUTH_ID) -%>
+ <% if Settings.key?(:wikipedia_auth_id) -%>
<li><%= auth_button "wikipedia", "wikipedia" %></li>
<% end -%>
<li><%= auth_button "yahoo", "openid", :openid_url => "yahoo.com" %></li>
<h1><%= t ".heading" %></h1>
<% end %>
-<%= raw t ".body", :webmaster => link_to(t(".webmaster"), "mailto:#{SUPPORT_EMAIL}") %>
+<%= raw t ".body", :webmaster => link_to(t(".webmaster"), "mailto:#{Settings.support_email}") %>
-application.yml
database.yml
require_relative "boot"
-require_relative "preinitializer"
+# Guard against deployments with old-style application.yml configurations
+# Otherwise, admins might not be aware that they are now silently ignored
+# and major problems could occur
+# rubocop:disable Rails/Output, Rails/Exit
+if File.exist?(File.expand_path("application.yml", __dir__))
+ puts "The config/application.yml file is no longer supported"
+ puts "Default settings are now found in config/settings.yml and you can override these in config/settings.local.yml"
+ puts "To prevent unexpected behaviour, please copy any custom settings to config/settings.local.yml"
+ puts " and then remove your config/application.yml file."
+ exit!
+end
+# rubocop:enable Rails/Output, Rails/Exit
+
+# Set the STATUS constant from the environment, if it matches a recognized value
+ALLOWED_STATUS = [
+ :online, # online and operating normally
+ :api_readonly, # site online but API in read-only mode
+ :api_offline, # site online but API offline
+ :database_readonly, # database and site in read-only mode
+ :database_offline, # database offline with site in emergency mode
+ :gpx_offline # gpx storage offline
+].freeze
+
+status = if ENV["STATUS"] && ALLOWED_STATUS.include?(ENV["STATUS"].to_sym)
+ ENV["STATUS"].to_sym
+ else
+ :online
+ end
+Object.const_set("STATUS", status)
if STATUS == :database_offline
require "action_controller/railtie"
config.paths["app/models"].skip_eager_load! if STATUS == :database_offline
# Use memcached for caching if required
- config.cache_store = :mem_cache_store, MEMCACHE_SERVERS, { :namespace => "rails:cache" } if defined?(MEMCACHE_SERVERS)
+ config.cache_store = :mem_cache_store, Settings.memcache_servers, { :namespace => "rails:cache" } if Settings.key?(:memcache_servers)
# Use logstash for logging if required
- if defined?(LOGSTASH_PATH)
+ if Settings.key?(:logstash_path)
config.logstasher.enabled = true
config.logstasher.suppress_app_log = false
- config.logstasher.logger_path = LOGSTASH_PATH
+ config.logstasher.logger_path = Settings.logstash_path
config.logstasher.log_controller_parameters = true
end
end
config.log_tags = [:request_id]
# Use a different log path in production.
- config.paths["log"] = LOG_PATH if defined?(LOG_PATH)
+ config.paths["log"] = Settings.log_path if Settings.key?(:log_path)
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
+++ /dev/null
-defaults: &defaults
- # The server protocol and host
- server_protocol: "http"
- server_url: "openstreetmap.example.com"
- # Publisher
- #publisher_url: ""
- # The generator
- generator: "OpenStreetMap server"
- copyright_owner: "OpenStreetMap and contributors"
- attribution_url: "http://www.openstreetmap.org/copyright"
- license_url: "http://opendatacommons.org/licenses/odbl/1-0/"
- # Support email address
- support_email: "openstreetmap@example.com"
- # Sender addresses for emails
- email_from: "OpenStreetMap <openstreetmap@example.com>"
- email_return_path: "openstreetmap@example.com"
- # API version
- api_version: "0.6"
- # Application status - possible values are:
- # :online - online and operating normally
- # :api_readonly - site online but API in read-only mode
- # :api_offline - site online but API offline
- # :database_readonly - database and site in read-only mode
- # :database_offline - database offline with site in emergency mode
- # :gpx_offline - gpx storage offline
- status: :online
- # The maximum area you're allowed to request, in square degrees
- max_request_area: 0.25
- # Number of GPS trace/trackpoints returned per-page
- tracepoints_per_page: 5000
- # Maximum number of nodes that will be returned by the api in a map request
- max_number_of_nodes: 50000
- # Maximum number of nodes that can be in a way (checked on save)
- max_number_of_way_nodes: 2000
- # The maximum area you're allowed to request notes from, in square degrees
- max_note_request_area: 25
- # Zoom level to use for postcode results from the geocoder
- postcode_zoom: 15
- # Zoom level to use for geonames results from the geocoder
- geonames_zoom: 12
- # Timeout for API calls in seconds
- api_timeout: 300
- # Timeout for web pages in seconds
- web_timeout: 30
- # Periods (in hours) which are allowed for user blocks
- user_block_periods: [0, 1, 3, 6, 12, 24, 48, 96]
- # Rate limit for message sending
- max_messages_per_hour: 60
- # Domain for handling message replies
- #messages_domain: "messages.openstreetmap.org"
- # Geonames authentication details
- #geonames_username: ""
- # GeoIP database
- #geoip_database: ""
- # Users to show as being nearby
- nearby_users: 30
- # Max radius, in km, for nearby users
- nearby_radius: 50
- # Spam threshold
- spam_threshold: 50
- # Default legale (jurisdiction location) for contributor terms
- default_legale: GB
- # Use the built-in jobs queue for importing traces
- # Leave as false if you are using the external high-speed gpx importer
- # https://github.com/openstreetmap/gpx-import
- trace_use_job_queue: false
- # Location of GPX traces and images
- gpx_trace_dir: "/home/osm/traces"
- gpx_image_dir: "/home/osm/images"
- # Location of data for attachments
- attachments_dir: ":rails_root/public/attachments"
- # Log file to use
- #log_path: ""
- # Log file to use for logstash
- #logstash_path: ""
- # List of memcache servers to use for caching
- #memcache_servers: []
- # Enable legacy OAuth 1.0 support
- oauth_10_support: true
- # URL of Nominatim instance to use for geocoding
- nominatim_url: "https://nominatim.openstreetmap.org/"
- # Default editor
- default_editor: "id"
- # OAuth consumer key for Potlatch 2
- #potlatch2_key: ""
- # OAuth consumer key for the web site
- #oauth_key: ""
- # OAuth consumer key for iD
- #id_key: ""
- # Imagery to return in capabilities as blacklisted
- imagery_blacklist:
- # Current Google imagery URLs have google or googleapis in the domain
- # with a vt or kh endpoint, and x, y and z query parameters
- - ".*\\.google(apis)?\\..*/(vt|kh)[\\?/].*([xyz]=.*){3}.*"
- # Blacklist VWorld
- - "http://xdworld\\.vworld\\.kr:8080/.*"
- # Blacklist here
- - ".*\\.here\\.com[/:].*"
- # URL of Overpass instance to use for feature queries
- overpass_url: "https://overpass-api.de/api/interpreter"
- # Routing endpoints
- graphhopper_url: "https://graphhopper.com/api/1/route"
- fossgis_osrm_url: "https://routing.openstreetmap.de/"
- # External authentication credentials
- #google_auth_id: ""
- #google_auth_secret: ""
- #google_openid_realm: ""
- #facebook_auth_id: ""
- #facebook_auth_secret: ""
- #windowslive_auth_id: ""
- #windowslive_auth_secret: ""
- #github_auth_id: ""
- #github_auth_secret: ""
- #wikipedia_auth_id: ""
- #wikipedia_auth_secret: ""
- # Thunderforest authentication details
- #thunderforest_key: ""
- # Key for generating TOTP tokens
- #totp_key: ""
- # Enforce Content-Security-Policy
- csp_enforce: false
- # URL for reporting Content-Security-Policy violations
- #csp_report_url: ""
-
-development:
- <<: *defaults
-
-production:
- <<: *defaults
-
-test:
- <<: *defaults
- # Geonames credentials for testing
- geonames_username: "dummy"
- # External authentication credentials for testing
- google_auth_id: "dummy"
- google_auth_secret: "dummy"
- google_openid_realm: "https://www.openstreetmap.org"
- facebook_auth_id: "dummy"
- facebook_auth_secret: "dummy"
- windowslive_auth_id: "dummy"
- windowslive_auth_secret: "dummy"
- github_auth_id: "dummy"
- github_auth_secret: "dummy"
- wikipedia_auth_id: "dummy"
- wikipedia_auth_secret: "dummy"
# Set the host and protocol for all ActionMailer URLs
ActionMailer::Base.default_url_options = {
- :host => SERVER_URL,
- :protocol => SERVER_PROTOCOL
+ :host => Settings.server_url,
+ :protocol => Settings.server_protocol
}
CanonicalRails.setup do |config|
# Force the protocol. If you do not specify, the protocol will be based on the incoming request's protocol.
- config.protocol = "#{SERVER_PROTOCOL}://"
+ config.protocol = "#{Settings.server_protocol}://"
# This is the main host, not just the TLD, omit slashes and protocol. If you have more than one, pick the one you want to rank in search results.
- config.host = SERVER_URL
- config.port = SERVER_PROTOCOL == "https" ? 443 : 80
+ config.host = Settings.server_url
+ config.port = Settings.server_protocol == "https" ? 443 : 80
# http://en.wikipedia.org/wiki/URL_normalization
# Trailing slash represents semantics of a directory, ie a collection view - implying an :index get route;
--- /dev/null
+Config.setup do |config|
+ # Name of the constant exposing loaded settings
+ config.const_name = "Settings"
+
+ # Ability to remove elements of the array set in earlier loaded settings file. For example value: '--'.
+ #
+ # config.knockout_prefix = nil
+
+ # Overwrite an existing value when merging a `nil` value.
+ # When set to `false`, the existing value is retained after merge.
+ #
+ # config.merge_nil_values = true
+
+ # Overwrite arrays found in previously loaded settings file. When set to `false`, arrays will be merged.
+ #
+ # config.overwrite_arrays = true
+
+ # Load environment variables from the `ENV` object and override any settings defined in files.
+ #
+ # config.use_env = false
+
+ # Define ENV variable prefix deciding which variables to load into config.
+ #
+ # config.env_prefix = 'Settings'
+
+ # What string to use as level separator for settings loaded from ENV variables. Default value of '.' works well
+ # with Heroku, but you might want to change it for example for '__' to easy override settings from command line, where
+ # using dots in variable names might not be allowed (eg. Bash).
+ #
+ # config.env_separator = '.'
+
+ # Ability to process variables names:
+ # * nil - no change
+ # * :downcase - convert to lower case
+ #
+ # config.env_converter = :downcase
+
+ # Parse numeric values as integers instead of strings.
+ #
+ # config.env_parse_values = true
+
+ # Validate presence and type of specific config values. Check https://github.com/dry-rb/dry-validation for details.
+ #
+ config.schema do
+ required(:api_version).filled(:str?)
+ required(:max_request_area).filled(:number?)
+ required(:max_note_request_area).filled(:number?)
+ required(:tracepoints_per_page).filled(:int?)
+ required(:max_number_of_way_nodes).filled(:int?)
+ required(:api_timeout).filled(:int?)
+ required(:imagery_blacklist).maybe(:array?)
+ end
+end
OmniAuth.config.logger = Rails.logger
OmniAuth.config.failure_raise_out_environments = []
-if defined?(MEMCACHE_SERVERS)
+if Settings.key?(:memcache_servers)
require "openid/store/memcache"
- openid_store = OpenID::Store::Memcache.new(Dalli::Client.new(MEMCACHE_SERVERS, :namespace => "rails"))
+ openid_store = OpenID::Store::Memcache.new(Dalli::Client.new(Settings.memcache_servers, :namespace => "rails"))
else
require "openid/store/filesystem"
github_options = { :name => "github", :scope => "user:email" }
wikipedia_options = { :name => "wikipedia", :client_options => { :site => "https://meta.wikimedia.org" } }
-google_options[:openid_realm] = GOOGLE_OPENID_REALM if defined?(GOOGLE_OPENID_REALM)
+google_options[:openid_realm] = Settings.google_openid_realm if Settings.key?(:google_openid_realm)
Rails.application.config.middleware.use OmniAuth::Builder do
provider :openid, openid_options
- provider :google_oauth2, GOOGLE_AUTH_ID, GOOGLE_AUTH_SECRET, google_options if defined?(GOOGLE_AUTH_ID)
- provider :facebook, FACEBOOK_AUTH_ID, FACEBOOK_AUTH_SECRET, facebook_options if defined?(FACEBOOK_AUTH_ID)
- provider :windowslive, WINDOWSLIVE_AUTH_ID, WINDOWSLIVE_AUTH_SECRET, windowslive_options if defined?(WINDOWSLIVE_AUTH_ID)
- provider :github, GITHUB_AUTH_ID, GITHUB_AUTH_SECRET, github_options if defined?(GITHUB_AUTH_ID)
- provider :mediawiki, WIKIPEDIA_AUTH_ID, WIKIPEDIA_AUTH_SECRET, wikipedia_options if defined?(WIKIPEDIA_AUTH_ID)
+ provider :google_oauth2, Settings.google_auth_id, Settings.google_auth_secret, google_options if Settings.key?(:google_auth_id)
+ provider :facebook, Settings.facebook_auth_id, Settings.facebook_auth_secret, facebook_options if Settings.key?(:facebook_auth_id)
+ provider :windowslive, Settings.windowslive_auth_id, Settings.windowslive_auth_secret, windowslive_options if Settings.key?(:windowslive_auth_id)
+ provider :github, Settings.github_auth_id, Settings.github_auth_secret, github_options if Settings.key?(:github_auth_id)
+ provider :mediawiki, Settings.wikipedia_auth_id, Settings.wikipedia_auth_secret, wikipedia_options if Settings.key?(:wikipedia_auth_id)
end
end
Paperclip::Attachment.default_options[:url] = "/attachments/:class/:attachment/:id_partition/:style/:fingerprint.:extension"
-Paperclip::Attachment.default_options[:path] = "#{ATTACHMENTS_DIR}/:class/:attachment/:id_partition/:style/:fingerprint.:extension"
+Paperclip::Attachment.default_options[:path] = "#{Settings.attachments_dir}/:class/:attachment/:id_partition/:style/:fingerprint.:extension"
Paperclip::Attachment.default_options[:url_generator] = Paperclip::AssetUrlGenerator
csp_policy[:connect_src] << PIWIK["location"] if defined?(PIWIK)
csp_policy[:img_src] << PIWIK["location"] if defined?(PIWIK)
csp_policy[:script_src] << PIWIK["location"] if defined?(PIWIK)
-csp_policy[:report_uri] << CSP_REPORT_URL if defined?(CSP_REPORT_URL)
+csp_policy[:report_uri] << Settings.csp_report_url if Settings.key?(:csp_report_url)
cookie_policy = {
:secure => SecureHeaders::OPT_OUT,
SecureHeaders::Configuration.default do |config|
config.hsts = SecureHeaders::OPT_OUT
- if CSP_ENFORCE
+ if Settings.csp_enforce
config.csp = csp_policy
config.csp_report_only = SecureHeaders::OPT_OUT
- elsif defined?(CSP_REPORT_URL)
+ elsif Settings.key?(:csp_report_url)
config.csp = SecureHeaders::OPT_OUT
config.csp_report_only = csp_policy
else
# Be sure to restart your server when you modify this file.
-if defined?(MEMCACHE_SERVERS)
- Rails.application.config.session_store :mem_cache_store, :memcache_server => MEMCACHE_SERVERS, :namespace => "rails:session", :key => "_osm_session"
+if Settings.key?(:memcache_servers)
+ Rails.application.config.session_store :mem_cache_store, :memcache_server => Settings.memcache_servers, :namespace => "rails:session", :key => "_osm_session"
else
Rails.application.config.session_store :cache_store, :key => "_osm_session", :cache => ActiveSupport::Cache::MemoryStore.new
end
+++ /dev/null
-require "yaml"
-
-env = if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any?
- "test"
- else
- ENV["RAILS_ENV"] || "development"
- end
-
-config = YAML.load_file(File.expand_path(env == "test" ? "../example.application.yml" : "../application.yml", __FILE__))
-
-ENV.each do |key, value|
- Object.const_set(Regexp.last_match(1).upcase, value) if key =~ /^OSM_(.*)$/
-end
-
-config[env].each do |key, value|
- Object.const_set(key.upcase, value) unless Object.const_defined?(key.upcase)
-end
--- /dev/null
+# The server protocol and host
+server_protocol: "http"
+server_url: "openstreetmap.example.com"
+# Publisher
+#publisher_url: ""
+# The generator
+generator: "OpenStreetMap server"
+copyright_owner: "OpenStreetMap and contributors"
+attribution_url: "http://www.openstreetmap.org/copyright"
+license_url: "http://opendatacommons.org/licenses/odbl/1-0/"
+# Support email address
+support_email: "openstreetmap@example.com"
+# Sender addresses for emails
+email_from: "OpenStreetMap <openstreetmap@example.com>"
+email_return_path: "openstreetmap@example.com"
+# API version
+api_version: "0.6"
+# Application status - possible values are:
+# :online - online and operating normally
+# :api_readonly - site online but API in read-only mode
+# :api_offline - site online but API offline
+# :database_readonly - database and site in read-only mode
+# :database_offline - database offline with site in emergency mode
+# :gpx_offline - gpx storage offline
+status: :online
+# The maximum area you're allowed to request, in square degrees
+max_request_area: 0.25
+# Number of GPS trace/trackpoints returned per-page
+tracepoints_per_page: 5000
+# Maximum number of nodes that will be returned by the api in a map request
+max_number_of_nodes: 50000
+# Maximum number of nodes that can be in a way (checked on save)
+max_number_of_way_nodes: 2000
+# The maximum area you're allowed to request notes from, in square degrees
+max_note_request_area: 25
+# Zoom level to use for postcode results from the geocoder
+postcode_zoom: 15
+# Zoom level to use for geonames results from the geocoder
+geonames_zoom: 12
+# Timeout for API calls in seconds
+api_timeout: 300
+# Timeout for web pages in seconds
+web_timeout: 30
+# Periods (in hours) which are allowed for user blocks
+user_block_periods: [0, 1, 3, 6, 12, 24, 48, 96]
+# Rate limit for message sending
+max_messages_per_hour: 60
+# Domain for handling message replies
+#messages_domain: "messages.openstreetmap.org"
+# Geonames authentication details
+#geonames_username: ""
+# GeoIP database
+#geoip_database: ""
+# Users to show as being nearby
+nearby_users: 30
+# Max radius, in km, for nearby users
+nearby_radius: 50
+# Spam threshold
+spam_threshold: 50
+# Default legale (jurisdiction location) for contributor terms
+default_legale: GB
+# Use the built-in jobs queue for importing traces
+# Leave as false if you are using the external high-speed gpx importer
+# https://github.com/openstreetmap/gpx-import
+trace_use_job_queue: false
+# Location of GPX traces and images
+gpx_trace_dir: "/home/osm/traces"
+gpx_image_dir: "/home/osm/images"
+# Location of data for attachments
+attachments_dir: ":rails_root/public/attachments"
+# Log file to use
+#log_path: ""
+# Log file to use for logstash
+#logstash_path: ""
+# List of memcache servers to use for caching
+#memcache_servers: []
+# Enable legacy OAuth 1.0 support
+oauth_10_support: true
+# URL of Nominatim instance to use for geocoding
+nominatim_url: "https://nominatim.openstreetmap.org/"
+# Default editor
+default_editor: "id"
+# OAuth consumer key for Potlatch 2
+#potlatch2_key: ""
+# OAuth consumer key for the web site
+#oauth_key: ""
+# OAuth consumer key for iD
+#id_key: ""
+# Imagery to return in capabilities as blacklisted
+imagery_blacklist:
+ # Current Google imagery URLs have google or googleapis in the domain
+ # with a vt or kh endpoint, and x, y and z query parameters
+ - ".*\\.google(apis)?\\..*/(vt|kh)[\\?/].*([xyz]=.*){3}.*"
+ # Blacklist VWorld
+ - "http://xdworld\\.vworld\\.kr:8080/.*"
+ # Blacklist here
+ - ".*\\.here\\.com[/:].*"
+# URL of Overpass instance to use for feature queries
+overpass_url: "https://overpass-api.de/api/interpreter"
+# Routing endpoints
+graphhopper_url: "https://graphhopper.com/api/1/route"
+fossgis_osrm_url: "https://routing.openstreetmap.de/"
+# External authentication credentials
+#google_auth_id: ""
+#google_auth_secret: ""
+#google_openid_realm: ""
+#facebook_auth_id: ""
+#facebook_auth_secret: ""
+#windowslive_auth_id: ""
+#windowslive_auth_secret: ""
+#github_auth_id: ""
+#github_auth_secret: ""
+#wikipedia_auth_id: ""
+#wikipedia_auth_secret: ""
+# Thunderforest authentication details
+#thunderforest_key: ""
+# Key for generating TOTP tokens
+#totp_key: ""
+# Enforce Content-Security-Policy
+csp_enforce: false
+# URL for reporting Content-Security-Policy violations
+#csp_report_url: ""
--- /dev/null
+gpx_trace_dir: <%= Rails.root.join("test", "gpx", "traces") %>
+gpx_image_dir: <%= Rails.root.join("test", "gpx", "images") %>
+# Geonames credentials for testing
+geonames_username: "dummy"
+# External authentication credentials for testing
+google_auth_id: "dummy"
+google_auth_secret: "dummy"
+google_openid_realm: "https://www.openstreetmap.org"
+facebook_auth_id: "dummy"
+facebook_auth_secret: "dummy"
+windowslive_auth_id: "dummy"
+windowslive_auth_secret: "dummy"
+github_auth_id: "dummy"
+github_auth_secret: "dummy"
+wikipedia_auth_id: "dummy"
+wikipedia_auth_secret: "dummy"
module Auth
PROVIDERS = { "None" => "", "OpenID" => "openid" }.tap do |providers|
- providers["Google"] = "google" if defined?(GOOGLE_AUTH_ID)
- providers["Facebook"] = "facebook" if defined?(FACEBOOK_AUTH_ID)
- providers["Windows Live"] = "windowslive" if defined?(WINDOWSLIVE_AUTH_ID)
- providers["GitHub"] = "github" if defined?(GITHUB_AUTH_ID)
- providers["Wikipedia"] = "wikipedia" if defined?(WIKIPEDIA_AUTH_ID)
+ providers["Google"] = "google" if Settings.key?(:google_auth_id)
+ providers["Facebook"] = "facebook" if Settings.key?(:facebook_auth_id)
+ providers["Windows Live"] = "windowslive" if Settings.key?(:windowslive_auth_id)
+ providers["GitHub"] = "github" if Settings.key?(:github_auth_id)
+ providers["Wikipedia"] = "wikipedia" if Settings.key?(:wikipedia_auth_id)
end.freeze
end
self
end
- def check_size(max_area = MAX_REQUEST_AREA)
+ def check_size(max_area = Settings.max_request_area)
# check the bbox isn't too large
if area > max_area
raise OSM::APIBadBoundingBox, "The maximum bbox size is " + max_area.to_s +
end
def xml_root_attributes
- { "version" => API_VERSION.to_s,
- "generator" => GENERATOR,
- "copyright" => COPYRIGHT_OWNER,
- "attribution" => ATTRIBUTION_URL,
- "license" => LICENSE_URL }
+ { "version" => Settings.api_version,
+ "generator" => Settings.generator,
+ "copyright" => Settings.copyright_owner,
+ "attribution" => Settings.attribution_url,
+ "license" => Settings.license_url }
end
end
def self.ip_to_country(ip_address)
- ipinfo = geoip_database.country(ip_address) if defined?(GEOIP_DATABASE)
+ ipinfo = geoip_database.country(ip_address) if Settings.key?(:geoip_database)
if ipinfo
country = ipinfo.country_code2
# Return the terms and conditions text for a given country
def self.legal_text_for_country(country_code)
file_name = Rails.root.join("config", "legales", country_code.to_s + ".yml")
- file_name = Rails.root.join("config", "legales", DEFAULT_LEGALE + ".yml") unless File.exist? file_name
+ file_name = Rails.root.join("config", "legales", Settings.default_legale + ".yml") unless File.exist? file_name
YAML.load_file(file_name)
end
# Return the GeoIP database handle
def self.geoip_database
- @geoip_database ||= GeoIP.new(GEOIP_DATABASE) if defined?(GEOIP_DATABASE)
+ @geoip_database ||= GeoIP.new(Settings.geoip_database) if Settings.key?(:geoip_database)
end
end
def test_capabilities
get :show
assert_response :success
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "api", :count => 1 do
- assert_select "version[minimum='#{API_VERSION}'][maximum='#{API_VERSION}']", :count => 1
- assert_select "area[maximum='#{MAX_REQUEST_AREA}']", :count => 1
- assert_select "note_area[maximum='#{MAX_NOTE_REQUEST_AREA}']", :count => 1
- assert_select "tracepoints[per_page='#{TRACEPOINTS_PER_PAGE}']", :count => 1
+ assert_select "version[minimum='#{Settings.api_version}'][maximum='#{Settings.api_version}']", :count => 1
+ assert_select "area[maximum='#{Settings.max_request_area}']", :count => 1
+ assert_select "note_area[maximum='#{Settings.max_note_request_area}']", :count => 1
+ assert_select "tracepoints[per_page='#{Settings.tracepoints_per_page}']", :count => 1
assert_select "changesets[maximum_elements='#{Changeset::MAX_ELEMENTS}']", :count => 1
assert_select "status[database='online']", :count => 1
assert_select "status[api='online']", :count => 1
assert_response :success
now = Time.now.getutc
hourago = now - 1.hour
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "changes[starttime='#{hourago.xmlschema}'][endtime='#{now.xmlschema}']", :count => 1 do
assert_select "tile", :count => 0
end
# changes at the time we have frozen at
now = Time.now.getutc
hourago = now - 1.hour
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "changes[starttime='#{hourago.xmlschema}'][endtime='#{now.xmlschema}']", :count => 1 do
assert_select "tile", :count => 6
end
assert_response :success
# NOTE: there was a test here for the timing, but it was too sensitive to be a good test
# and it was annoying.
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "changes", :count => 1
end
end
get :show, :params => { :id => changeset_id }
assert_response :success, "cannot get first changeset"
- assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
+ assert_select "osm[version='#{Settings.api_version}'][generator='OpenStreetMap server']", 1
assert_select "osm>changeset[id='#{changeset_id}']", 1
assert_select "osm>changeset>discussion", 0
get :show, :params => { :id => changeset_id, :include_discussion => true }
assert_response :success, "cannot get first changeset with comments"
- assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
+ assert_select "osm[version='#{Settings.api_version}'][generator='OpenStreetMap server']", 1
assert_select "osm>changeset[id='#{changeset_id}']", 1
assert_select "osm>changeset>discussion", 1
assert_select "osm>changeset>discussion>comment", 0
get :show, :params => { :id => changeset_id, :include_discussion => true }
assert_response :success, "cannot get closed changeset with comments"
- assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
+ assert_select "osm[version='#{Settings.api_version}'][generator='OpenStreetMap server']", 1
assert_select "osm>changeset[id='#{changeset_id}']", 1
assert_select "osm>changeset>discussion", 1
assert_select "osm>changeset>discussion>comment", 3
"can't upload a simple valid creation to changeset: #{@response.body}"
# check the returned payload
- assert_select "diffResult[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
+ assert_select "diffResult[version='#{Settings.api_version}'][generator='OpenStreetMap server']", 1
assert_select "diffResult>node", 1
assert_select "diffResult>way", 1
assert_select "diffResult>relation", 1
"can't do a conditional delete of in use objects: #{@response.body}"
# check the returned payload
- assert_select "diffResult[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
+ assert_select "diffResult[version='#{Settings.api_version}'][generator='OpenStreetMap server']", 1
assert_select "diffResult>node", 1
assert_select "diffResult>way", 1
assert_select "diffResult>relation", 1
"can't upload a complex diff to changeset: #{@response.body}"
# check the returned payload
- assert_select "diffResult[version='#{API_VERSION}'][generator='#{GENERATOR}']", 1
+ assert_select "diffResult[version='#{Settings.api_version}'][generator='#{Settings.generator}']", 1
assert_select "diffResult>node", 1
assert_select "diffResult>way", 1
assert_select "diffResult>relation", 1
"failed to return error in XML format"
# check the returned payload
- assert_select "osmError[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
+ assert_select "osmError[version='#{Settings.api_version}'][generator='OpenStreetMap server']", 1
assert_select "osmError>status", 1
assert_select "osmError>message", 1
end
assert_template nil
# print @response.body
# FIXME: needs more assert_select tests
- assert_select "osmChange[version='#{API_VERSION}'][generator='#{GENERATOR}']" do
+ assert_select "osmChange[version='#{Settings.api_version}'][generator='#{Settings.generator}']" do
assert_select "create", :count => 5
assert_select "create>node[id='#{node.id}'][visible='#{node.visible?}'][version='#{node.version}']" do
assert_select "tag[k='#{tag.k}'][v='#{tag.v}']"
print @response.body
end
assert_response :success, "Expected scucess with the map call"
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "bounds[minlon='#{format('%.7f', minlon)}'][minlat='#{format('%.7f', minlat)}'][maxlon='#{format('%.7f', maxlon)}'][maxlat='#{format('%.7f', maxlat)}']", :count => 1
assert_select "node[id='#{node.id}'][lat='#{format('%.7f', node.lat)}'][lon='#{format('%.7f', node.lon)}'][version='#{node.version}'][changeset='#{node.changeset_id}'][visible='#{node.visible}'][timestamp='#{node.timestamp.xmlschema}']", :count => 1 do
# This should really be more generic
bbox = "#{node.lon},#{node.lat},#{node.lon},#{node.lat}"
get :index, :params => { :bbox => bbox }
assert_response :success, "The map call should have succeeded"
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "bounds[minlon='#{node.lon}'][minlat='#{node.lat}'][maxlon='#{node.lon}'][maxlat='#{node.lat}']", :count => 1
assert_select "node[id='#{node.id}'][lat='#{format('%.7f', node.lat)}'][lon='#{format('%.7f', node.lon)}'][version='#{node.version}'][changeset='#{node.changeset_id}'][visible='#{node.visible}'][timestamp='#{node.timestamp.xmlschema}']", :count => 1 do
# This should really be more generic
bbox = "#{node.lon},#{node.lat},#{node.lon},#{node.lat}"
get :index, :params => { :bbox => bbox }
assert_response :success, "The map call should have succeeded"
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "bounds[minlon='#{node.lon}'][minlat='#{node.lat}'][maxlon='#{node.lon}'][maxlat='#{node.lat}']", :count => 1
assert_select "node", :count => 3
assert_select "node[id='#{node.id}']", :count => 1
def test_map_empty
get :index, :params => { :bbox => "179.998,89.998,179.999.1,89.999" }
assert_response :success, "The map call should have succeeded"
- assert_select "osm[version='#{API_VERSION}'][generator='#{GENERATOR}']", :count => 1 do
+ assert_select "osm[version='#{Settings.api_version}'][generator='#{Settings.generator}']", :count => 1 do
assert_select "bounds[minlon='179.9980000'][minlat='89.9980000'][maxlon='179.9990000'][maxlat='89.9990000']", :count => 1
assert_select "node", :count => 0
assert_select "way", :count => 0
@badbigbbox.each do |bbox|
get :index, :params => { :bbox => bbox }
assert_response :bad_request, "The bbox:#{bbox} was expected to be too big"
- assert_equal "The maximum bbox size is #{MAX_REQUEST_AREA}, and your request was too large. Either request a smaller area, or use planet.osm", @response.body, "bbox: #{bbox}"
+ assert_equal "The maximum bbox size is #{Settings.max_request_area}, and your request was too large. Either request a smaller area, or use planet.osm", @response.body, "bbox: #{bbox}"
end
end
assert_response :success
# count one osm element
- assert_select "osm[version='#{API_VERSION}'][generator='OpenStreetMap server']", 1
+ assert_select "osm[version='#{Settings.api_version}'][generator='OpenStreetMap server']", 1
# we should have only the expected number of relations
assert_select "osm>relation", expected_relations.size
@badbigbbox.each do |bbox|
get :index, :params => { :bbox => bbox }
assert_response :bad_request, "The bbox:#{bbox} was expected to be too big"
- assert_equal "The maximum bbox size is #{MAX_REQUEST_AREA}, and your request was too large. Either request a smaller area, or use planet.osm", @response.body, "bbox: #{bbox}"
+ assert_equal "The maximum bbox size is #{Settings.max_request_area}, and your request was too large. Either request a smaller area, or use planet.osm", @response.body, "bbox: #{bbox}"
end
end
module Api
class TracesControllerTest < ActionController::TestCase
- def setup
- @gpx_trace_dir = Object.send("remove_const", "GPX_TRACE_DIR")
- Object.const_set("GPX_TRACE_DIR", Rails.root.join("test", "gpx", "traces"))
-
- @gpx_image_dir = Object.send("remove_const", "GPX_IMAGE_DIR")
- Object.const_set("GPX_IMAGE_DIR", Rails.root.join("test", "gpx", "images"))
- end
-
def teardown
- File.unlink(*Dir.glob(File.join(GPX_TRACE_DIR, "*.gpx")))
- File.unlink(*Dir.glob(File.join(GPX_IMAGE_DIR, "*.gif")))
-
- Object.send("remove_const", "GPX_TRACE_DIR")
- Object.const_set("GPX_TRACE_DIR", @gpx_trace_dir)
-
- Object.send("remove_const", "GPX_IMAGE_DIR")
- Object.const_set("GPX_IMAGE_DIR", @gpx_image_dir)
+ File.unlink(*Dir.glob(File.join(Settings.gpx_trace_dir, "*.gpx")))
+ File.unlink(*Dir.glob(File.join(Settings.gpx_image_dir, "*.gif")))
end
##
assert_equal "[OpenStreetMap] Test Message", e.subject
assert_match(/Test message body/, e.text_part.decoded)
assert_match(/Test message body/, e.html_part.decoded)
- assert_match %r{#{SERVER_URL}/messages/[0-9]+}, e.text_part.decoded
+ assert_match %r{#{Settings.server_url}/messages/[0-9]+}, e.text_part.decoded
ActionMailer::Base.deliveries.clear
m = Message.last
assert_equal user.id, m.from_user_id
private
def with_message_limit(value)
- max_messages_per_hour = Object.send("remove_const", "MAX_MESSAGES_PER_HOUR")
- Object.const_set("MAX_MESSAGES_PER_HOUR", value)
+ max_messages_per_hour = Settings.max_messages_per_hour
+ Settings.max_messages_per_hour = value
yield
- Object.send("remove_const", "MAX_MESSAGES_PER_HOUR")
- Object.const_set("MAX_MESSAGES_PER_HOUR", max_messages_per_hour)
+ Settings.max_messages_per_hour = max_messages_per_hour
end
end
##
# setup oauth keys
def setup
- Object.const_set("ID_KEY", create(:client_application).key)
- Object.const_set("POTLATCH2_KEY", create(:client_application).key)
+ Settings.id_key = create(:client_application).key
+ Settings.potlatch2_key = create(:client_application).key
stub_hostip_requests
end
##
# clear oauth keys
def teardown
- Object.send("remove_const", "ID_KEY")
- Object.send("remove_const", "POTLATCH2_KEY")
+ Settings.id_key = nil
+ Settings.potlatch2_key = nil
end
##
get :edit, :session => { :user => create(:user) }
assert_response :success
assert_template "edit"
- assert_template :partial => "_#{DEFAULT_EDITOR}", :count => 1
+ assert_template :partial => "_#{Settings.default_editor}", :count => 1
end
# Test the right editor gets used when the user has set a preference
require "minitest/mock"
class TracesControllerTest < ActionController::TestCase
- def setup
- @gpx_trace_dir = Object.send("remove_const", "GPX_TRACE_DIR")
- Object.const_set("GPX_TRACE_DIR", Rails.root.join("test", "gpx", "traces"))
-
- @gpx_image_dir = Object.send("remove_const", "GPX_IMAGE_DIR")
- Object.const_set("GPX_IMAGE_DIR", Rails.root.join("test", "gpx", "images"))
- end
-
def teardown
- File.unlink(*Dir.glob(File.join(GPX_TRACE_DIR, "*.gpx")))
- File.unlink(*Dir.glob(File.join(GPX_IMAGE_DIR, "*.gif")))
-
- Object.send("remove_const", "GPX_TRACE_DIR")
- Object.const_set("GPX_TRACE_DIR", @gpx_trace_dir)
-
- Object.send("remove_const", "GPX_IMAGE_DIR")
- Object.const_set("GPX_IMAGE_DIR", @gpx_image_dir)
+ File.unlink(*Dir.glob(File.join(Settings.gpx_trace_dir, "*.gpx")))
+ File.unlink(*Dir.glob(File.join(Settings.gpx_image_dir, "*.gif")))
end
##
def test_api_blocked
blocked_user = create(:user)
- get "/api/#{API_VERSION}/user/details"
+ get "/api/#{Settings.api_version}/user/details"
assert_response :unauthorized
- get "/api/#{API_VERSION}/user/details", :headers => auth_header(blocked_user.display_name, "test")
+ get "/api/#{Settings.api_version}/user/details", :headers => auth_header(blocked_user.display_name, "test")
assert_response :success
# now block the user
:reason => "testing",
:ends_at => Time.now.getutc + 5.minutes
)
- get "/api/#{API_VERSION}/user/details", :headers => auth_header(blocked_user.display_name, "test")
+ get "/api/#{Settings.api_version}/user/details", :headers => auth_header(blocked_user.display_name, "test")
assert_response :forbidden
end
:reason => "testing",
:ends_at => Time.now.getutc + 5.minutes
)
- get "/api/#{API_VERSION}/user/details", :headers => auth_header(blocked_user.display_name, "test")
+ get "/api/#{Settings.api_version}/user/details", :headers => auth_header(blocked_user.display_name, "test")
assert_response :forbidden
# revoke the ban
reset!
# access the API again. this time it should work
- get "/api/#{API_VERSION}/user/details", :headers => auth_header(blocked_user.display_name, "test")
+ get "/api/#{Settings.api_version}/user/details", :headers => auth_header(blocked_user.display_name, "test")
assert_response :success
end
end
def test_api_blocked
user = create(:user, :terms_seen => false, :terms_agreed => nil)
- get "/api/#{API_VERSION}/user/preferences", :headers => auth_header(user.display_name, "test")
+ get "/api/#{Settings.api_version}/user/preferences", :headers => auth_header(user.display_name, "test")
assert_response :forbidden
# touch it so that the user has seen the terms
user.terms_seen = true
user.save
- get "/api/#{API_VERSION}/user/preferences", :headers => auth_header(user.display_name, "test")
+ get "/api/#{Settings.api_version}/user/preferences", :headers => auth_header(user.display_name, "test")
assert_response :success
end
require "minitest/mock"
class TraceTest < ActiveSupport::TestCase
- def setup
- @gpx_trace_dir = Object.send("remove_const", "GPX_TRACE_DIR")
- Object.const_set("GPX_TRACE_DIR", Rails.root.join("test", "gpx", "traces"))
-
- @gpx_image_dir = Object.send("remove_const", "GPX_IMAGE_DIR")
- Object.const_set("GPX_IMAGE_DIR", Rails.root.join("test", "gpx", "images"))
- end
-
def teardown
- File.unlink(*Dir.glob(File.join(GPX_TRACE_DIR, "*.gpx")))
- File.unlink(*Dir.glob(File.join(GPX_IMAGE_DIR, "*.gif")))
-
- Object.send("remove_const", "GPX_TRACE_DIR")
- Object.const_set("GPX_TRACE_DIR", @gpx_trace_dir)
-
- Object.send("remove_const", "GPX_IMAGE_DIR")
- Object.const_set("GPX_IMAGE_DIR", @gpx_image_dir)
+ File.unlink(*Dir.glob(File.join(Settings.gpx_trace_dir, "*.gpx")))
+ File.unlink(*Dir.glob(File.join(Settings.gpx_image_dir, "*.gif")))
end
def test_visible
FakeFS do
FakeFS::FileSystem.clone(Rails.root.join("test", "gpx"))
trace = create(:trace, :fixture => "a")
- icon_path = File.join(GPX_IMAGE_DIR, "#{trace.id}_icon.gif")
+ icon_path = File.join(Settings.gpx_image_dir, "#{trace.id}_icon.gif")
FileUtils.rm(icon_path)
assert_equal false, File.exist?(icon_path)
FakeFS do
FakeFS::FileSystem.clone(Rails.root.join("test", "gpx"))
trace = create(:trace, :fixture => "a")
- large_picture_path = File.join(GPX_IMAGE_DIR, "#{trace.id}.gif")
+ large_picture_path = File.join(Settings.gpx_image_dir, "#{trace.id}.gif")
FileUtils.rm(large_picture_path)
assert_equal false, File.exist?(large_picture_path)
# Take one of the current ways and add nodes to it until we are near the limit
assert way.valid?
# it already has 1 node
- 1.upto(MAX_NUMBER_OF_WAY_NODES / 2) do
+ 1.upto(Settings.max_number_of_way_nodes / 2) do
way.add_nd_num(node_a.id)
way.add_nd_num(node_b.id)
end