When a user is created it's associated to his own database. All his user tables are created in this database

1.0
Fernando Blat 14 years ago
parent cd15592f83
commit 0677693e05

@ -7,5 +7,13 @@ require 'rake'
CartoDB::Application.load_tasks
Rake.application.instance_variable_get('@tasks').delete('default')
task :default => ["spec:models", "spec:acceptance"]
namespace :spec do
desc "Run the code examples in spec/acceptance"
RSpec::Core::RakeTask.new(:cartodb_acceptance) do |t|
t.pattern = "spec/acceptance/**/*_spec.rb"
end
end
task :default => ["db:test:prepare", "spec:models", "spec:cartodb_acceptance"]

@ -1,16 +1,11 @@
# coding: UTF-8
class UserTableAlreadyExist < StandardError; end
class Table < Sequel::Model(:user_tables)
# Privacy constants
PRIVATE = 0
PUBLIC = 1
# DB table preffix
DB_TABLE_PREFFIX = 'users_tables_'
## Callbacks
# Before creating a user table a table should be created in the database.
@ -18,12 +13,13 @@ class Table < Sequel::Model(:user_tables)
def before_create
update_updated_at
unless self.user_id.blank? || self.name.blank?
self.db_table_name = DB_TABLE_PREFFIX + self.user_id.to_s + '_' + self.name.sanitize.tr('-','_')
self.db_table_name = self.name.sanitize.tr('-','_')
unless self.db_table_name.blank?
unless Rails::Sequel.connection.table_exists?(self.db_table_name.to_sym)
Rails::Sequel.connection.create_table self.db_table_name.to_sym
else
raise UserTableAlreadyExist
user = User.select(:id,:database_name).filter(:id => self.user_id).first
user.in_database do |user_database|
unless user_database.table_exists?(self.db_table_name.to_sym)
user_database.create_table self.db_table_name.to_sym
end
end
end
end
@ -41,11 +37,17 @@ class Table < Sequel::Model(:user_tables)
def execute_sql(sql)
update_updated_at!
Rails::Sequel.connection[db_table_name.to_sym].with_sql(sql).all
user = User.select(:id,:database_name).filter(:id => self.user_id).first
user.in_database do |user_database|
user_database[db_table_name.to_sym].with_sql(sql).all
end
end
def rows_count
Rails::Sequel.connection[db_table_name.to_sym].count
user = User.select(:id,:database_name).filter(:id => self.user_id).first
user.in_database do |user_database|
user_database[db_table_name.to_sym].count
end
end
private

@ -2,8 +2,26 @@
class User < Sequel::Model
## Authentication methods
## Callbacks
def after_create
super
self.database_name = case Rails.env
when 'development'
"cartodb_dev_user_#{self.id}_db"
when 'test'
"cartodb_test_user_#{self.id}_db"
else
"cartodb_user_#{self.id}_db"
end
save
Thread.new do
Rails::Sequel.connection.run("create database #{self.database_name}")
end.join
end
#### End of Callbacks
## Authentication methods
AUTH_DIGEST = '999f2da2a5fd99c5af493af3daf22fde939c0e67'
def self.password_digest(password, salt)
@ -34,6 +52,13 @@ class User < Sequel::Model
#### End of Authentication methods
def in_database(&block)
connection = ::Sequel.connect(::Rails::Sequel.configuration.environment_for(Rails.env).merge('database' => self.database_name))
result = yield(connection)
connection.disconnect
result
end
def tables
Table.filter(:user_id => self.id).order(:id).reverse
end

@ -6,6 +6,7 @@ class UsersMigration < Sequel::Migration
String :email, :null => false, :unique => true
String :crypted_password, :null => false
String :salt, :null => false
String :database_name
end
end

@ -0,0 +1,35 @@
Sequel.migration do
up do
create_table(:schema_migrations) do
String :filename, :text=>true, :null=>false
primary_key [:filename]
end
create_table(:user_tables, :ignore_index_errors=>true) do
primary_key :id
Integer :user_id, :null=>false
String :name, :text=>true, :null=>false
Integer :privacy, :default=>0, :null=>false
String :db_table_name, :text=>true, :null=>false
DateTime :updated_at, :null=>false
index [:user_id]
index [:user_id, :privacy]
end
create_table(:users, :ignore_index_errors=>true) do
primary_key :id
String :email, :text=>true, :null=>false
String :crypted_password, :text=>true, :null=>false
String :salt, :text=>true, :null=>false
String :database_name, :text=>true
index [:email], :name=>:users_email_key, :unique=>true
end
end
down do
drop_table(:schema_migrations, :user_tables, :users)
end
end

@ -1,5 +1,17 @@
# coding: UTF-8
## Remove all user databases
tables = Rails::Sequel.connection.tables
Rails::Sequel.connection[tables.first].with_sql(
"SELECT datname FROM pg_database WHERE datistemplate IS FALSE AND datallowconn IS TRUE AND datname like 'cartodb_dev_user_%'"
).map(:datname).each { |user_database_name| Rails::Sequel.connection.run("drop database #{user_database_name}") }
Rails::Sequel.connection[tables.first].with_sql(
"SELECT datname FROM pg_database WHERE datistemplate IS FALSE AND datallowconn IS TRUE AND datname like 'cartodb_test_user_%'"
).map(:datname).each { |user_database_name| Rails::Sequel.connection.run("drop database #{user_database_name}") }
## Create users
User.create :email => 'admin@example.com', :password => 'example'
## Development demo data

@ -13,13 +13,16 @@ describe Table do
user = create_user
table = Table.create :name => 'Wadus table', :user_id => user.id
table.db_table_name.should_not be_blank
table.db_table_name.should == "users_tables_#{user.id}_wadus_table"
table.db_table_name.should == "wadus_table"
end
it "should fetch empty data from the database by SQL sentences" do
user = create_user
table = Table.create :name => 'Wadus table', :user_id => user.id
Rails::Sequel.connection.table_exists?(table.db_table_name.to_sym).should be_true
Rails::Sequel.connection.table_exists?(table.db_table_name.to_sym).should be_false
user.in_database do |user_database|
user_database.table_exists?(table.db_table_name.to_sym).should be_true
end
rows = table.execute_sql "select * from #{table.db_table_name} limit 1"
rows.should be_empty
table.rows_count.should == 0

@ -22,4 +22,13 @@ describe User do
user.tables_count.should == 1
user.tables.all.should == [Table.first(:user_id => user.id)]
end
it "should has his own database, created when the account is created" do
user = create_user
user.database_name.should == "cartodb_test_user_#{user.id}_db"
user.in_database do |user_database|
user_database.test_connection.should == true
user_database.tables.should be_empty
end
end
end

@ -15,4 +15,11 @@ RSpec.configure do |config|
config.before(:each) do
Rails::Sequel.connection.tables.each{ |t| next if t == :schema_migrations; Rails::Sequel.connection[t].truncate }
end
config.after(:each) do
Rails::Sequel.connection[Rails::Sequel.connection.tables.first].with_sql(
"SELECT datname FROM pg_database WHERE datistemplate IS FALSE AND datallowconn IS TRUE AND datname like 'cartodb_test_user_%'"
).map(:datname).each { |user_database_name| Rails::Sequel.connection.run("drop database #{user_database_name}") }
end
end

Loading…
Cancel
Save