specify_cli 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +117 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +43 -0
- data/Rakefile +15 -0
- data/bin/specify_cli +248 -0
- data/lib/specify.rb +45 -0
- data/lib/specify/branch_parser.rb +85 -0
- data/lib/specify/cli.rb +11 -0
- data/lib/specify/cli/database_setup.rb +46 -0
- data/lib/specify/cli/stubs.rb +63 -0
- data/lib/specify/cli/viewset.rb +21 -0
- data/lib/specify/configuration.rb +12 -0
- data/lib/specify/configuration/config.rb +120 -0
- data/lib/specify/configuration/db_config.rb +162 -0
- data/lib/specify/configuration/host_config.rb +37 -0
- data/lib/specify/database.rb +140 -0
- data/lib/specify/models.rb +43 -0
- data/lib/specify/models/accession.rb +33 -0
- data/lib/specify/models/agent.rb +138 -0
- data/lib/specify/models/app_resource_data.rb +32 -0
- data/lib/specify/models/app_resource_dir.rb +43 -0
- data/lib/specify/models/auto_numbering_scheme.rb +94 -0
- data/lib/specify/models/collecting_event.rb +38 -0
- data/lib/specify/models/collection.rb +67 -0
- data/lib/specify/models/collection_object.rb +127 -0
- data/lib/specify/models/createable.rb +21 -0
- data/lib/specify/models/determination.rb +63 -0
- data/lib/specify/models/discipline.rb +61 -0
- data/lib/specify/models/division.rb +26 -0
- data/lib/specify/models/geography.rb +5 -0
- data/lib/specify/models/geography/administrative_division.rb +32 -0
- data/lib/specify/models/geography/geographic_name.rb +66 -0
- data/lib/specify/models/geography/geography.rb +23 -0
- data/lib/specify/models/institution.rb +13 -0
- data/lib/specify/models/locality.rb +50 -0
- data/lib/specify/models/preparation.rb +53 -0
- data/lib/specify/models/preparation_type.rb +30 -0
- data/lib/specify/models/record_set.rb +55 -0
- data/lib/specify/models/record_set_item.rb +29 -0
- data/lib/specify/models/taxonomy.rb +6 -0
- data/lib/specify/models/taxonomy/common_name.rb +14 -0
- data/lib/specify/models/taxonomy/rank.rb +31 -0
- data/lib/specify/models/taxonomy/taxon.rb +54 -0
- data/lib/specify/models/taxonomy/taxonomy.rb +21 -0
- data/lib/specify/models/tree_queryable.rb +55 -0
- data/lib/specify/models/updateable.rb +20 -0
- data/lib/specify/models/user.rb +104 -0
- data/lib/specify/models/view_set_object.rb +32 -0
- data/lib/specify/number_format.rb +60 -0
- data/lib/specify/services.rb +18 -0
- data/lib/specify/services/service.rb +51 -0
- data/lib/specify/services/stub_generator.rb +291 -0
- data/lib/specify/services/view_loader.rb +177 -0
- data/lib/specify/session.rb +77 -0
- data/lib/specify/user_type.rb +61 -0
- data/lib/specify/version.rb +19 -0
- data/man/specify_cli-database.1 +60 -0
- data/man/specify_cli-database.1.html +137 -0
- data/man/specify_cli-database.1.ronn +53 -0
- data/man/specify_cli-repository.1 +55 -0
- data/man/specify_cli-repository.1.html +128 -0
- data/man/specify_cli-repository.1.ronn +42 -0
- data/man/specify_cli-stubs.1 +177 -0
- data/man/specify_cli-stubs.1.html +239 -0
- data/man/specify_cli-stubs.1.ronn +147 -0
- data/man/specify_cli-viewset.1 +92 -0
- data/man/specify_cli-viewset.1.html +154 -0
- data/man/specify_cli-viewset.1.ronn +72 -0
- data/man/specify_cli.1 +213 -0
- data/man/specify_cli.1.html +252 -0
- data/man/specify_cli.1.ronn +157 -0
- data/spec/branch_parser_spec.rb +94 -0
- data/spec/cli/stubs_spec.rb +44 -0
- data/spec/configuration/config_spec.rb +269 -0
- data/spec/configuration/db_config_spec.rb +299 -0
- data/spec/configuration/host_config_spec.rb +64 -0
- data/spec/database_spec.rb +83 -0
- data/spec/examples.txt +217 -0
- data/spec/helpers.rb +15 -0
- data/spec/models/app_resource_data_spec.rb +38 -0
- data/spec/models/app_resource_dir_spec.rb +8 -0
- data/spec/models/auto_numbering_scheme_spec.rb +78 -0
- data/spec/models/collection_object_spec.rb +92 -0
- data/spec/models/collection_spec.rb +32 -0
- data/spec/models/discipline_spec.rb +31 -0
- data/spec/models/record_set_spec.rb +18 -0
- data/spec/models/user_spec.rb +182 -0
- data/spec/models/view_set_object_spec.rb +70 -0
- data/spec/number_format_spec.rb +43 -0
- data/spec/services/stub_generator_spec.rb +635 -0
- data/spec/services/view_loader_spec.rb +436 -0
- data/spec/session_spec.rb +105 -0
- data/spec/spec_helper.rb +116 -0
- data/spec/support/db.yml +12 -0
- data/spec/support/stub.yaml +17 -0
- data/spec/support/stub_locality.yaml +19 -0
- data/spec/support/viewsets/paleo.views.xml +30 -0
- data/spec/support/viewsets/paleo.xml +30 -0
- data/spec/user_type_spec.rb +79 -0
- data/specify_cli.gemspec +27 -0
- data/specify_cli.rdoc +1 -0
- metadata +246 -0
data/lib/specify.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# require 'specify/version.rb'
|
4
|
+
|
5
|
+
require 'date'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'io/console'
|
8
|
+
require 'mysql2'
|
9
|
+
require 'open3'
|
10
|
+
require 'pathname'
|
11
|
+
require 'psych'
|
12
|
+
require 'readline'
|
13
|
+
require 'securerandom'
|
14
|
+
require 'sequel'
|
15
|
+
|
16
|
+
require_relative 'specify/branch_parser'
|
17
|
+
require_relative 'specify/cli'
|
18
|
+
require_relative 'specify/configuration'
|
19
|
+
require_relative 'specify/database'
|
20
|
+
require_relative 'specify/number_format'
|
21
|
+
require_relative 'specify/session'
|
22
|
+
require_relative 'specify/user_type'
|
23
|
+
require_relative 'specify/services'
|
24
|
+
|
25
|
+
# FIXME: causes warnings, but is also required for call from bash script
|
26
|
+
# raises name error for VERSION and DESCRIPTION constants otherwise
|
27
|
+
require_relative 'specify/version'
|
28
|
+
|
29
|
+
# A module that provides functionaliy to manage Specify app resources.
|
30
|
+
module Specify
|
31
|
+
GIT_CURRENT_BRANCH = 'git rev-parse --abbrev-ref HEAD'
|
32
|
+
|
33
|
+
BRANCH_ERROR = 'Branch name not parsable: '
|
34
|
+
|
35
|
+
# FileError is a module that contains errors for file operations.
|
36
|
+
module FileError
|
37
|
+
VIEWS_FILE = 'Files must be .views.xml files'
|
38
|
+
NO_FILE = "File not found"
|
39
|
+
end
|
40
|
+
|
41
|
+
# LoginError is a module that contains errors for User logins.
|
42
|
+
module LoginError
|
43
|
+
INCONSISTENT_LOGIN = 'User is already logged in to a different collection'
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Specify
|
4
|
+
# BranchParsers parse the information required to set a
|
5
|
+
# Specify::Service::ViewLoade#target for upload of _.views.xml_ files from a
|
6
|
+
# string that follows the convention <tt>Database/CollectionName/level</tt>.
|
7
|
+
#
|
8
|
+
# This can be the name of a git branch of a repository residing in a folder
|
9
|
+
# denoting the hostname.
|
10
|
+
class BranchParser
|
11
|
+
# The name of the collection. Must be an existing
|
12
|
+
# Specify::Model::Collection#name.
|
13
|
+
attr_reader :collection
|
14
|
+
|
15
|
+
# A Specify::Configuration::HostConfig.
|
16
|
+
attr_reader :config
|
17
|
+
|
18
|
+
# The name of a _Specify_ database.
|
19
|
+
attr_reader :database
|
20
|
+
|
21
|
+
# The name of a MySQL/MariaDB host.
|
22
|
+
attr_reader :host
|
23
|
+
|
24
|
+
# The name of a _Specify_ user (an existing Specify::Model::User#name).
|
25
|
+
attr_reader :user
|
26
|
+
|
27
|
+
# Creates a new instance of BranchParser for the current Git _HEAD_.
|
28
|
+
#
|
29
|
+
# +config+: a database configuration YAML file.
|
30
|
+
def self.current_branch(config)
|
31
|
+
stdout_str, stderr_str, status = Open3.capture3(GIT_CURRENT_BRANCH)
|
32
|
+
unless status.exitstatus.zero?
|
33
|
+
STDERR.puts "There was an error running #{GIT_CURRENT_BRANCH}"
|
34
|
+
STDERR.puts stderr_str
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
branch = stdout_str.chomp
|
38
|
+
new(Dir.pwd, branch, config)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns a new BranchParser with +view_file_path+ and +name+.
|
42
|
+
#
|
43
|
+
# +view_file_path+: the directory path of the _.vews.xml_ file (that path
|
44
|
+
# must be mapped to a host name in the +config+).
|
45
|
+
#
|
46
|
+
# +name+: a String with a branch name conforming to the convention
|
47
|
+
# <tt>Database/CollectionName/level</tt>.
|
48
|
+
#
|
49
|
+
# +config+: a database configuration YAML file.
|
50
|
+
def initialize(view_file_path, name, config = nil)
|
51
|
+
@config = Configuration::HostConfig.new(config)
|
52
|
+
@database, collection, @level, @user = *name.split('/')
|
53
|
+
raise ArgumentError, BRANCH_ERROR + name unless collection && level
|
54
|
+
@host = @config.resolve_host view_file_path
|
55
|
+
@collection = normalize_name collection
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns the attributes of +self+ as a hash.
|
59
|
+
def to_h
|
60
|
+
{ host: host,
|
61
|
+
database: database,
|
62
|
+
collection: collection,
|
63
|
+
level: level }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the level to a Specify::Service::ViewLoader will upload.
|
67
|
+
def level
|
68
|
+
case @level
|
69
|
+
when 'collection', 'discipline'
|
70
|
+
@level.to_sym
|
71
|
+
when 'user'
|
72
|
+
{ user: @user }
|
73
|
+
else
|
74
|
+
{ user_type: @level.downcase.to_sym }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def normalize_name(name)
|
81
|
+
name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1 \2')
|
82
|
+
.gsub(/([a-z\d])([A-Z])/, '\1 \2')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/specify/cli.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Specify
|
4
|
+
module CLI
|
5
|
+
# Asks the user to configure a database.
|
6
|
+
def self.configure_database(config)
|
7
|
+
STDERR.puts "Configuring new database: #{config.database}"
|
8
|
+
config.user_name = require_input 'MySQL user name'
|
9
|
+
config.user_password = require_input 'password (blank for prompt)'
|
10
|
+
config.session_user = require_input 'Specify user (leave blank to skip)'
|
11
|
+
config.save
|
12
|
+
end
|
13
|
+
|
14
|
+
# Asks the user to configure a host.
|
15
|
+
def self.configure_host(config)
|
16
|
+
return unless proceed? "host #{config.host} not known"
|
17
|
+
config.port = require_input 'port number (leave blank for default)'
|
18
|
+
config.save
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates a new database configuratin YAML file.
|
22
|
+
def self.db_config!(file, global_options)
|
23
|
+
return if File.exist?(global_options[:db_config])
|
24
|
+
STDERR.puts "Creating new config file #{file}"
|
25
|
+
Specify::Configuration::Config.empty file do |config|
|
26
|
+
config.add_host global_options[:host], global_options[:port]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Asks the user to proceed. Returns +true+ if the user answers answers with
|
31
|
+
# 'Yes'.
|
32
|
+
def self.proceed?(message)
|
33
|
+
STDERR.puts message
|
34
|
+
STDERR.print "Configure? (Y/n)"
|
35
|
+
return true if /^[Yy](es)?/.match Readline.readline(': ')
|
36
|
+
end
|
37
|
+
|
38
|
+
# Prompts the user for input with +message+.
|
39
|
+
def self.require_input(message)
|
40
|
+
STDERR.print message
|
41
|
+
answer = Readline.readline(': ')
|
42
|
+
return if answer.empty?
|
43
|
+
answer
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Specify
|
4
|
+
module CLI
|
5
|
+
# Transforms +arg+ (a String passed as a command line argument) containing
|
6
|
+
# hierarchical information (such as geographic or taxonomic) into a
|
7
|
+
# structured Hash that can be used to set the
|
8
|
+
# Specify::Service::StubGenerator#collecting_data= or
|
9
|
+
# Specify::Service::StubGenerator#determination=.
|
10
|
+
def self.arg_to_hash(arg)
|
11
|
+
return unless arg
|
12
|
+
arg.split(';')
|
13
|
+
.map { |pair| pair.split(':').map(&:strip) }
|
14
|
+
.to_h
|
15
|
+
.transform_keys { |key| key == 'locality' ? key.to_sym : key }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates stub records with +generator+ (a Specify::Service::StubGenerator).
|
19
|
+
#
|
20
|
+
# +count+: the number of stub records to be created.
|
21
|
+
def self.make_stubs(generator, count)
|
22
|
+
STDERR.puts "started creating #{count} records"
|
23
|
+
STDERR.puts "cataloger: #{generator.cataloger}"
|
24
|
+
generator.database.transaction do
|
25
|
+
generator.create count
|
26
|
+
STDERR.puts "creating: #{generator.generated.last.catalog_number}"
|
27
|
+
end
|
28
|
+
STDERR.puts 'done'
|
29
|
+
puts "generated #{generator.generated.count} catalog numbers:"
|
30
|
+
puts '--------------------------'
|
31
|
+
generator.generated.each { |co| puts co.CatalogNumber }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns a Hash for intialization of a Specify::Service::StubGenerator
|
35
|
+
# from +global_options+, +args+, and command +options+.
|
36
|
+
def self.wrap_args(global_options, args, options)
|
37
|
+
params = {}
|
38
|
+
stub_generator = {}
|
39
|
+
stub_generator[:host] = global_options[:host]
|
40
|
+
stub_generator[:database] = global_options[:database]
|
41
|
+
stub_generator[:collection] = args.shift
|
42
|
+
stub_generator[:specify_user] = global_options[:specify_user]
|
43
|
+
stub_generator[:config] = global_options[:db_config]
|
44
|
+
params[:stub_generator] = stub_generator
|
45
|
+
params.merge stub_parameters(options)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Parses the parameters for stub records to created by a
|
49
|
+
# Specify::Service::StubGenerator from the command +options+.
|
50
|
+
def self.stub_parameters(options)
|
51
|
+
params = { 'dataset_name' => options[:dataset],
|
52
|
+
'cataloger' => options[:cataloger],
|
53
|
+
'accession' => options[:accession],
|
54
|
+
'collecting_data' => arg_to_hash(options[:geography]),
|
55
|
+
'default_locality_name' => options[:locality],
|
56
|
+
'determination' => arg_to_hash(options[:taxon]) }
|
57
|
+
return params unless options[:preptype]
|
58
|
+
params['preparation'] = { type: options[:preptype],
|
59
|
+
count: options[:prepcount] }
|
60
|
+
params.compact
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Specify
|
4
|
+
module CLI
|
5
|
+
# Parses the _level_ for the Specify::Service::ViewLoader to upload
|
6
|
+
# _.vioews.xml_ files to from the command +options+.
|
7
|
+
def self.level(options)
|
8
|
+
if options[:d]
|
9
|
+
:discipline
|
10
|
+
elsif options[:c]
|
11
|
+
:collection
|
12
|
+
elsif options[:t]
|
13
|
+
{ user_type: options[:t] }
|
14
|
+
elsif options[:u]
|
15
|
+
{ user: options[:u] }
|
16
|
+
else
|
17
|
+
raise 'level required (use -d, -c, -t, or -u option)'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'configuration/config'
|
4
|
+
require_relative 'configuration/db_config'
|
5
|
+
require_relative 'configuration/host_config'
|
6
|
+
|
7
|
+
module Specify
|
8
|
+
# Configuration is a module that contains classes that provide configuration
|
9
|
+
# facilities.
|
10
|
+
module Configuration
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Specify
|
4
|
+
module Configuration
|
5
|
+
# Configurations wrap a database configuaratin file (_.rc.yaml_ file).
|
6
|
+
#
|
7
|
+
# Configuration is the superclass of the DBConfig and HostConfig classes.
|
8
|
+
class Config
|
9
|
+
# A Hash containing the directory-host-mapping parameters for the
|
10
|
+
# HostConfig subclass.
|
11
|
+
attr_reader :dir_names
|
12
|
+
|
13
|
+
# A Hash containing the database parameters for the DBConfig subclass.
|
14
|
+
attr_reader :hosts
|
15
|
+
|
16
|
+
# Returns a new empty Config for +file+ that can serve as a template.
|
17
|
+
#
|
18
|
+
# +file+: the YAML file containg the configuration
|
19
|
+
def self.empty(file, &block)
|
20
|
+
if File.exist?(file)
|
21
|
+
raise "#{file} exists, won't overwrite"
|
22
|
+
end
|
23
|
+
config = new file, dir_names: {}, hosts: {}, &block
|
24
|
+
config.save
|
25
|
+
config
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a new Config for +file+ (a YAML file containg the
|
29
|
+
# configuration).
|
30
|
+
#
|
31
|
+
# <tt>dir_names</tt>: a Hash with directory names as keys, host names as
|
32
|
+
# values.
|
33
|
+
#
|
34
|
+
# +hosts+: a Hash with host configurations. The hash should have the
|
35
|
+
# structure:
|
36
|
+
# {
|
37
|
+
# :hosts => {
|
38
|
+
# 'hostname' => {
|
39
|
+
# :port => Integer,
|
40
|
+
# :databases => {
|
41
|
+
# 'database name' => {
|
42
|
+
# :db_user => {
|
43
|
+
# :name => 'mysql_user_name',
|
44
|
+
# :password => 'password'
|
45
|
+
# },
|
46
|
+
# :sp_user => 'specify_user_name'
|
47
|
+
# }
|
48
|
+
# }
|
49
|
+
# }
|
50
|
+
# }
|
51
|
+
# }
|
52
|
+
# Leave +:password+ out to be prompted.
|
53
|
+
def initialize(file = nil, dir_names: nil, hosts: nil)
|
54
|
+
@file = Pathname.new(file)
|
55
|
+
if dir_names || hosts
|
56
|
+
@dir_names = dir_names
|
57
|
+
@hosts = hosts
|
58
|
+
@params = { dir_names: dir_names, hosts: hosts }
|
59
|
+
else
|
60
|
+
@params = Psych.load_file(@file)
|
61
|
+
@dir_names = @params[:dir_names]
|
62
|
+
@hosts = @params[:hosts]
|
63
|
+
end
|
64
|
+
yield(self) if block_given?
|
65
|
+
@saved = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
# Adds a configuration for the database with +name+ to the +host+
|
69
|
+
# configuration.
|
70
|
+
def add_database(name, host:)
|
71
|
+
add_host(host) unless hosts[host]
|
72
|
+
if hosts.dig host, :databases, name
|
73
|
+
raise "Database '#{name}' on '#{host}' already configured"
|
74
|
+
end
|
75
|
+
db = hosts[host][:databases][name] = db_template
|
76
|
+
yield(db) if block_given?
|
77
|
+
@saved = false
|
78
|
+
end
|
79
|
+
|
80
|
+
# Adds a configuration for the host with +name+.
|
81
|
+
def add_host(name, port = nil)
|
82
|
+
raise "Host '#{name}' already configured" if hosts[name]
|
83
|
+
hosts[name] = { port: port, databases: {} }
|
84
|
+
@saved = false
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns a Hash with the contents of the configuration YAML file.
|
88
|
+
def params
|
89
|
+
{ dir_names: @dir_names, hosts: @hosts }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Saves the current state to the YAML configuration file.
|
93
|
+
def save
|
94
|
+
File.open(@file, 'w') do |file|
|
95
|
+
file.write(Psych.dump(@params))
|
96
|
+
end
|
97
|
+
@saved = true
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns +false+ if the instance has been modified since the last save.
|
101
|
+
def saved?
|
102
|
+
@saved
|
103
|
+
end
|
104
|
+
|
105
|
+
# Marks the instance as modified.
|
106
|
+
def touch
|
107
|
+
@saved = false
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def db_template
|
113
|
+
{
|
114
|
+
db_user: { name: nil, password: nil },
|
115
|
+
sp_user: nil
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Specify
|
4
|
+
module Configuration
|
5
|
+
# DBConfigs are Specify:Database configurations.
|
6
|
+
class DBConfig < Config
|
7
|
+
# The name of the _Specify_ database.
|
8
|
+
attr_reader :database
|
9
|
+
|
10
|
+
# The name of the MySQL/MariaDB host for the _Specify_ database.
|
11
|
+
attr_reader :host
|
12
|
+
|
13
|
+
# The port for the MySQL/MariaDB server for the _Specify_ database.
|
14
|
+
attr_reader :port
|
15
|
+
|
16
|
+
# The MySQL/MariaDB user for the database. This is typically the _Specify_
|
17
|
+
# <em>master user</em>.
|
18
|
+
attr_reader :user_name
|
19
|
+
|
20
|
+
# An existing Specify::Model::User#name; the name of the
|
21
|
+
# Specify::Model::User that is logged in to #collection during a Session.
|
22
|
+
attr_reader :session_user
|
23
|
+
|
24
|
+
# Returns a new DBConfig for +database+ on +host+
|
25
|
+
#
|
26
|
+
# _file_: the YAML file (path) containg the configuration.
|
27
|
+
def initialize(host, database, file = nil)
|
28
|
+
super(file)
|
29
|
+
@host = host
|
30
|
+
@database = database
|
31
|
+
@port = hosts.dig @host, :port
|
32
|
+
@user_name = params&.dig :db_user, :name
|
33
|
+
@user_password = params&.dig :db_user, :password
|
34
|
+
@session_user = params&.fetch :sp_user, nil
|
35
|
+
@saved = known? ? true : false
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the connection paramaters for the database as a Hash.
|
39
|
+
def connection
|
40
|
+
raise "#{database} on #{host} not configured" unless known?
|
41
|
+
{ host: host,
|
42
|
+
port: port || 3306,
|
43
|
+
user: user_name,
|
44
|
+
password: @user_password }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns +true+ if #user_name differs from the user +:name+ in the
|
48
|
+
# #params of the YAML file.
|
49
|
+
def changed_user?
|
50
|
+
params[:db_user][:name] != user_name
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns +true+ if the <em>user_password</em> attribute differs from the
|
54
|
+
# +:password+ in the #params of the YAML file.
|
55
|
+
def changed_password?
|
56
|
+
params[:db_user][:password] != @user_password
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns +true+ if #port differs from the +:port+ in the #params of the
|
60
|
+
# YAML file.
|
61
|
+
def changed_port?
|
62
|
+
hosts[host][:port] != port
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns +true+ if the #session_user differs from the <tt>:so_user</tt>
|
66
|
+
# in the #params of the YAML file.
|
67
|
+
def changed_session_user?
|
68
|
+
params[:sp_user] != session_user
|
69
|
+
end
|
70
|
+
|
71
|
+
# Sets the #database.
|
72
|
+
def database=(name)
|
73
|
+
@database = name
|
74
|
+
touch
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns a Hash with the MySQL/MariaDB user name and password.
|
78
|
+
def db_user
|
79
|
+
{ name: @user_name, password: @user_password }
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sets the #host
|
83
|
+
def host=(name)
|
84
|
+
@host = name
|
85
|
+
touch
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns +true+ if #host is known (has been configured), +false+
|
89
|
+
# otherwise.
|
90
|
+
def host?
|
91
|
+
hosts[host]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns +true+ if #database is known (has been configured), +false+
|
95
|
+
# otherwise.
|
96
|
+
def known?
|
97
|
+
params ? true : false
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns a Hash with the parameters for the #host #database from the
|
101
|
+
# configuration YAML file.
|
102
|
+
def params
|
103
|
+
super.dig:hosts, @host, :databases, @database
|
104
|
+
end
|
105
|
+
|
106
|
+
# Sets the #port
|
107
|
+
def port=(number)
|
108
|
+
@port = number&.to_i
|
109
|
+
raise ArgumentError, "invalid port number: #{number}" unless port_valid?
|
110
|
+
touch
|
111
|
+
end
|
112
|
+
|
113
|
+
# Saves the current state to the YAML file.
|
114
|
+
def save
|
115
|
+
return true if saved?
|
116
|
+
host? ? update_host : save_new_host
|
117
|
+
super
|
118
|
+
end
|
119
|
+
|
120
|
+
# Sets #session_user.
|
121
|
+
def session_user=(name)
|
122
|
+
@session_user = name
|
123
|
+
touch
|
124
|
+
end
|
125
|
+
|
126
|
+
# Sets the #user_name.
|
127
|
+
def user_name=(name)
|
128
|
+
@user_name = name
|
129
|
+
touch
|
130
|
+
end
|
131
|
+
|
132
|
+
# Sets the MySQL/MariaDB <em>user_password</em>.
|
133
|
+
def user_password=(password)
|
134
|
+
@user_password = password
|
135
|
+
touch
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def save_new_host
|
141
|
+
add_host host, port
|
142
|
+
add_database database, host: host
|
143
|
+
end
|
144
|
+
|
145
|
+
def update_database
|
146
|
+
params[:db_user][:name] = user_name if changed_user?
|
147
|
+
params[:db_user][:password] = @user_password if changed_password?
|
148
|
+
params[:sp_user] = session_user if changed_session_user?
|
149
|
+
end
|
150
|
+
|
151
|
+
def update_host
|
152
|
+
hosts[host][:port] = port if changed_port?
|
153
|
+
add_database database, host: host unless known?
|
154
|
+
update_database
|
155
|
+
end
|
156
|
+
|
157
|
+
def port_valid?
|
158
|
+
port.nil? || port.to_i.positive?
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|