Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ tmp

# docker-compose database directory
docker-db-data

/config/credentials/
72 changes: 72 additions & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
FROM debian:bookworm

ENV DEBIAN_FRONTEND=noninteractive

# Install system packages then clean up to minimize image size
RUN apt-get update \
&& apt-get install --no-install-recommends -y \
build-essential \
curl \
default-jre-headless \
file \
git-core \
gpg-agent \
libarchive-dev \
libffi-dev \
libgd-dev \
libpq-dev \
libsasl2-dev \
libvips-dev \
libxml2-dev \
libxslt1-dev \
libyaml-dev \
locales \
postgresql-client \
ruby-dev \
ruby-bundler \
tzdata \
unzip \
nodejs \
npm \
osmosis \
ca-certificates \
firefox-esr \
optipng \
pngcrush \
advancecomp \
pngquant \
jhead \
jpegoptim \
libjpeg-turbo-progs \
gifsicle

# Install yarn globally
RUN npm install --global yarn

# Add support for Postgres 16
RUN apt-get install --no-install-recommends -y postgresql-common \
&& /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y \
&& apt-get install --no-install-recommends -y postgresql-client-16

# Setup app location
RUN mkdir -p /app
WORKDIR /app
COPY . .

# Database template for Docker
COPY config/docker.database.yml config/database.yml
RUN sed -i'.bak' 's/development/production/g' config/database.yml

COPY config/example.storage.yml config/storage.yml

# https://help.openstreetmap.org/questions/69887/actionviewtemplateerror-couldnt-find-file-settingslocalyml
RUN touch config/settings.local.yml

# Install Ruby packages
RUN bundle install

# Install NodeJS packages using yarn
RUN bundle exec bin/yarn install

# Build frontend assets
RUN RAILS_ENV=production SECRET_KEY_BASE=dummy rails i18n:js:export assets:precompile
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ gem "unicode-display_width"
# Lock some modules to old versions for ruby 3.1 support
gem "zeitwerk", "< 2.7"

# TDEI Workspaces: supports multi-tenancy
# The latest stable release doesn't support Rails 7.1, yet. Use dev for now:
gem "ros-apartment", github: 'rails-on-services/apartment', branch: 'development', :require => "apartment"
#gem "ros-apartment", :require => "apartment"

# Gems useful for development
group :development do
gem "better_errors"
Expand Down
13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
GIT
remote: https://github.com/rails-on-services/apartment.git
revision: ec5a9bc7aef2ba65d7c3d369ca08aa916e56f880
branch: development
specs:
ros-apartment (3.1.0)
activerecord (>= 6.1.0, < 8.1)
activesupport (>= 6.1.0, < 8.1)
parallel (< 2.0)
public_suffix (>= 2.0.5, <= 6.0.1)
rack (>= 1.3.6, < 4.0)

GEM
remote: https://rubygems.org/
specs:
Expand Down Expand Up @@ -742,6 +754,7 @@ DEPENDENCIES
rails-i18n (~> 7.0.0)
rails_param
rinku (>= 2.0.6)
ros-apartment!
rotp
rtlcss
rubocop
Expand Down
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@

require_relative "config/application"

Apartment.db_migrate_tenants = false

Rails.application.load_tasks
61 changes: 60 additions & 1 deletion app/controllers/api/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ class UsersController < ApiController
before_action :setup_user_auth, :only => [:show, :index]
before_action :authorize, :only => [:details, :gpx_files]

authorize_resource
authorize_resource :except => [:provision]
skip_authorization_check :only => [:provision]

load_resource :only => :show

Expand Down Expand Up @@ -52,6 +53,64 @@ def gpx_files
render :content_type => "application/xml"
end

def provision
user = User.find_by(:auth_provider => "TDEI", :auth_uid => params[:auth_uid])

if user
user.email = params[:email]
user.display_name = params[:display_name]

if user.status != "active"
user.activate
end

user.save
return head :no_content
end

# TODO: temporary for TDEI auth transition:
user = User.find_by(:email => params[:email])

if user
user.auth_provider = 'TDEI'
user.auth_uid = params[:auth_uid]
user.display_name = params[:display_name]

if user.status != "active"
user.activate
end

user.save
return head :no_content
end

puts 'Create user'
user = User.new()
user.email = params[:email]
user.email_valid = true
user.display_name = params[:display_name]

user.auth_provider = 'TDEI'
user.auth_uid = params[:auth_uid]

# Set a random password--TDEI identity services manage the password:
user.pass_crypt = SecureRandom.base64(16)

user.data_public = true
user.description = '' if user.description.nil?
user.creation_address = request.remote_ip
user.languages = http_accept_language.user_preferred_languages
user.terms_agreed = Time.now.utc
user.tou_agreed = Time.now.utc
user.terms_seen = true
user.auth_provider = nil
user.auth_uid = nil
user.activate
user.save

head :no_content
end

private

def disable_terms_redirect
Expand Down
72 changes: 72 additions & 0 deletions app/controllers/api/workspaces_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# TODO: this controller needs special auth with the workspaces backend
module Api
class WorkspacesController < ApiController
before_action :check_api_readable
before_action :set_request_formats
#before_action :authorize

#authorize_resource
skip_authorization_check

around_action :api_call_handle_error, :api_call_timeout

def create
workspace_schema = 'workspace-' + params[:id]

# This runs the migrations that scaffold all of the OSM tables into a new
# schema. We don't need every table, but we can't choose. The global non-
# tenant tables match excluded models in config/initializers/apartment.rb
# that Apartment associates with the "public" schema.
#
Apartment::Tenant.create(workspace_schema)
Apartment::Tenant.switch!(workspace_schema)

# Drop tables that shadow the "public" schema. These tables cause foreign
# key constraint issues for tenant tables. The migrations include all OSM
# tables, and any unqualified references resolve to tenant schema tables.
# Removing these tables from the search path causes PostgreSQL to resolve
# tables references from the "public" schema instead:
#
connection = ActiveRecord::Base.connection
connection.execute("DROP TABLE \"#{workspace_schema}\".users CASCADE")
end

def switch
cookies[:workspace] = {
:value => params[:id],
:expires => 1.year.from_now,
}
end

def destroy
Apartment::Tenant.drop('workspace-' + params[:id])
end

def bbox
workspace_schema = 'workspace-' + params[:id]
Apartment::Tenant.switch!(workspace_schema)

out = Node
.select('MAX(latitude) AS max_lat,
MAX(longitude) AS max_lon,
MIN(latitude) AS min_lat,
MIN(longitude) AS min_lon')
.take

if out.min_lat.nil? # Workspace is empty (no nodes)
return head :no_content
end

@bbox = BoundingBox.new(out.min_lon, out.min_lat, out.max_lon, out.max_lat)

respond_to do |format|
format.xml
format.json
end
end
end
end

# TODO stub
class Workspace
end
20 changes: 20 additions & 0 deletions app/middleware/workspaces_elevator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'apartment/elevators/generic'

class WorkspacesElevator < Apartment::Elevators::Generic
def parse_tenant_name(request)
return nil if request.path.match? /^\/api\/[0-9.]+\/workspaces\//

workspace_id = request.env['HTTP_X_WORKSPACE'] # X-Workspace header

if workspace_id.blank?
workspace_id = request.cookies['workspace']
end

return nil if workspace_id.blank?
return nil unless workspace_id.match? /^\d+$/

puts 'Selecting workspace ' + workspace_id

return 'workspace-' + workspace_id
end
end
4 changes: 2 additions & 2 deletions app/models/changeset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ class Changeset < ApplicationRecord
before_save :update_closed_at

# maximum number of elements allowed in a changeset
MAX_ELEMENTS = 10000
MAX_ELEMENTS = 10000000

# maximum time a changeset is allowed to be open for.
MAX_TIME_OPEN = 1.day
MAX_TIME_OPEN = 7.day

# idle timeout increment, one hour seems reasonable.
IDLE_TIMEOUT = 1.hour
Expand Down
4 changes: 4 additions & 0 deletions app/views/api/workspaces/bbox.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
json.min_lat GeoRecord::Coord.new(@bbox.to_unscaled.min_lat)
json.min_lon GeoRecord::Coord.new(@bbox.to_unscaled.min_lon)
json.max_lat GeoRecord::Coord.new(@bbox.to_unscaled.max_lat)
json.max_lon GeoRecord::Coord.new(@bbox.to_unscaled.max_lon)
1 change: 0 additions & 1 deletion config/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
database.yml
storage.yml
4 changes: 4 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative "boot"
require_relative "../app/middleware/workspaces_elevator.rb"

require "rails/all"

Expand Down Expand Up @@ -45,5 +46,8 @@ class Application < Rails::Application
config.logstasher.logger_path = Settings.logstash_path
config.logstasher.log_controller_parameters = true
end

# TDEI Workspaces tenant partitioning:
config.middleware.use WorkspacesElevator
end
end
8 changes: 8 additions & 0 deletions config/database.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<%= ENV['RAILS_ENV'] %>:
adapter: postgresql
host: <%= ENV['WS_OSM_DB_HOST'] %>
username: <%= ENV['WS_OSM_DB_USER'] %>
password: <%= ENV['WS_OSM_DB_PASS'] %>
database: <%= ENV['WS_OSM_DB_NAME'] %>
encoding: utf8

21 changes: 5 additions & 16 deletions config/docker.database.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
# This configuration is tailored for use with docker compose. See DOCKER.md for more information.

development:
<%= ENV['RAILS_ENV'] %>:
adapter: postgresql
database: openstreetmap
username: openstreetmap
password: openstreetmap
host: db
encoding: utf8

# Warning: The database defined as 'test' will be erased and
# re-generated from your development database when you run 'rake'.
# Do not set this db to the same as development or production.
test:
adapter: postgresql
database: osm_test
username: openstreetmap
password: openstreetmap
host: db
host: <%= ENV['WS_OSM_DB_HOST'] %>
username: <%= ENV['WS_OSM_DB_USER'] %>
password: <%= ENV['WS_OSM_DB_PASS'] %>
database: <%= ENV['WS_OSM_DB_NAME'] %>
encoding: utf8
Loading
Loading