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 @@ -25,3 +25,5 @@ tmp

# docker-compose database directory
docker-db-data

/config/credentials/
59 changes: 59 additions & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
FROM ruby:3.2-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 \
tzdata \
unzip \
nodejs \
npm \
osmosis \
ca-certificates \
firefox-esr

# 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 . .

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 bundle exec i18n export
RUN RAILS_ENV=production SECRET_KEY_BASE=dummy rails assets:precompile
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ gem "inline_svg"
# Used to validate widths
gem "unicode-display_width"

# TDEI Workspaces: supports multi-tenancy
gem "ros-apartment", :require => "apartment"

# Gems useful for development
group :development do
gem "better_errors"
Expand Down
9 changes: 8 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ GEM
psych (5.2.6)
date
stringio
public_suffix (6.0.2)
public_suffix (6.0.1)
puma (6.6.1)
nio4r (~> 2.0)
quad_tile (1.0.1)
Expand Down Expand Up @@ -577,6 +577,12 @@ GEM
rack (>= 1.4)
rexml (3.4.2)
rinku (2.0.6)
ros-apartment (3.2.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)
rotp (6.3.0)
rouge (4.6.0)
rtlcss (0.2.1)
Expand Down Expand Up @@ -788,6 +794,7 @@ DEPENDENCIES
rails-i18n (~> 8.0.0)
rails_param
rinku (>= 2.0.6)
ros-apartment
rotp
rtlcss
rubocop
Expand Down
62 changes: 61 additions & 1 deletion app/controllers/api/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ class UsersController < ApiController
before_action :setup_user_auth, :only => [:show, :index]
before_action -> { authorize(:skip_terms => true) }, :only => [:details]

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

load_resource :only => :show

Expand Down Expand Up @@ -45,5 +46,64 @@ def details
format.json { render :show }
end
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

end
end
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: 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

Loading
Loading