pgchief 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -1
- data/README.md +8 -2
- data/lib/pgchief/command/database_create.rb +1 -0
- data/lib/pgchief/command/database_privileges_grant.rb +23 -0
- data/lib/pgchief/command/user_drop.rb +27 -1
- data/lib/pgchief/prompt/base.rb +32 -3
- data/lib/pgchief/prompt/create_database.rb +1 -2
- data/lib/pgchief/prompt/create_user.rb +6 -2
- data/lib/pgchief/prompt/database_management.rb +1 -1
- data/lib/pgchief/prompt/drop_database.rb +1 -2
- data/lib/pgchief/prompt/drop_user.rb +1 -2
- data/lib/pgchief/prompt/grant_database_privileges.rb +20 -0
- data/lib/pgchief/prompt/start.rb +1 -2
- data/lib/pgchief/prompt/user_management.rb +7 -3
- data/lib/pgchief/version.rb +1 -1
- data/lib/pgchief.rb +2 -0
- metadata +4 -3
- data/lib/pgchief/prompt/grant_database_priveleges.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dac74bd646caf6b54ac884174ea91654af3733a4a638b45cf7e690c501c0534a
|
4
|
+
data.tar.gz: b0be173c4090cda9a176f25434318f805f6892324e8b7a148db6ee93a09e24c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57135dde1c56aee8a082a36f03b440470a74549bd21ae970167ca5e4c02da91ed254ecf2a670818a712cdd6ad615372cd9a75229ff3f20c61f8ade718f0bf0a0
|
7
|
+
data.tar.gz: 2a70cc3718d84daba51d552c5d7a3ae144567bdb660db57fc4f890ff13ff3b154996f0ae5cae15212e3a433d01e8f2188cb1e62064cd364c51e7c9c0705d4671
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,26 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
6
|
+
and this project will try its best to adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
1
8
|
## [Unreleased]
|
2
9
|
|
3
|
-
|
10
|
+
### Additions
|
11
|
+
|
12
|
+
- Add `j` and `k` keys as substitutes for `↑` and `↓`.
|
13
|
+
- Allow exiting the program with the `esc` key.
|
14
|
+
- Add ability to grant access privileges for newly created users.
|
15
|
+
- Or grant privileges for existing users to database(s).
|
16
|
+
|
17
|
+
### Fixes
|
18
|
+
|
19
|
+
- GitHub now running CI successfully.
|
20
|
+
- Newly created databases are no longer open for connection by default. `CONNECT` is revoked by default for them.
|
21
|
+
- When dropping users, loop through all the databases they have access to and revoke access before dropping them.
|
22
|
+
|
23
|
+
## [0.1.0] - 2024-08-30
|
4
24
|
|
5
25
|
- Initial release
|
6
26
|
- Create database ✅
|
@@ -8,3 +28,6 @@
|
|
8
28
|
- Drop database ✅
|
9
29
|
- Drop user ✅
|
10
30
|
- List databases ✅
|
31
|
+
|
32
|
+
[Unreleased]: https://github.com/jayroh/pgchief/compare/v0.1.0...HEAD
|
33
|
+
[0.1.0]: https://github.com/jayroh/pgchief/releases/tag/v0.1.0
|
data/README.md
CHANGED
@@ -32,6 +32,11 @@ export DATABASE_URL=postgresql://postgres:password@postgres.local:5432
|
|
32
32
|
pgchief
|
33
33
|
```
|
34
34
|
|
35
|
+
Note:
|
36
|
+
|
37
|
+
1. Prompts accept both `↑` and `↓` arrows, as well as `j` and `k`.
|
38
|
+
2. Pressing the `esc` key at any point amidst a prompt will exit out of the program.
|
39
|
+
|
35
40
|
## Development of the gem
|
36
41
|
|
37
42
|
1. Clone this repo.
|
@@ -106,7 +111,8 @@ backup_dir = "~/.pg_backups"
|
|
106
111
|
- [x] Drop database
|
107
112
|
- [x] Drop user
|
108
113
|
- [x] List databases
|
109
|
-
- [
|
114
|
+
- [x] Give user permissions to use database
|
115
|
+
- [ ] Initialize toml file
|
110
116
|
- [ ] Back up database
|
111
117
|
- [ ] Restore database
|
112
|
-
- [ ]
|
118
|
+
- [ ] Display connection information
|
@@ -11,6 +11,7 @@ module Pgchief
|
|
11
11
|
raise Pgchief::Errors::DatabaseExistsError if db_exists?
|
12
12
|
|
13
13
|
conn.exec("CREATE DATABASE #{database}")
|
14
|
+
conn.exec("REVOKE CONNECT ON DATABASE #{database} FROM PUBLIC")
|
14
15
|
|
15
16
|
"Database '#{database}' created successfully!"
|
16
17
|
rescue PG::Error => e
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pgchief
|
4
|
+
module Command
|
5
|
+
# Class to grant database privileges
|
6
|
+
class DatabasePrivilegesGrant < Base
|
7
|
+
def call
|
8
|
+
username = params.first
|
9
|
+
databases = params.last
|
10
|
+
|
11
|
+
databases.each do |database|
|
12
|
+
conn.exec("GRANT CONNECT ON DATABASE #{database} TO #{username};")
|
13
|
+
end
|
14
|
+
|
15
|
+
"Privileges granted to #{username} on #{databases.join(", ")}"
|
16
|
+
rescue PG::Error => e
|
17
|
+
"Error: #{e.message}"
|
18
|
+
ensure
|
19
|
+
conn.close
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -10,7 +10,8 @@ module Pgchief
|
|
10
10
|
@username = params.first
|
11
11
|
raise Pgchief::Errors::UserExistsError unless user_exists?
|
12
12
|
|
13
|
-
|
13
|
+
revoke_all_privileges
|
14
|
+
drop_user
|
14
15
|
|
15
16
|
"User '#{username}' dropped successfully!"
|
16
17
|
rescue PG::Error => e
|
@@ -19,10 +20,35 @@ module Pgchief
|
|
19
20
|
conn.close
|
20
21
|
end
|
21
22
|
|
23
|
+
private
|
24
|
+
|
22
25
|
def user_exists?
|
23
26
|
query = "SELECT 1 FROM pg_user WHERE usename = '#{username}'"
|
24
27
|
conn.exec(query).any?
|
25
28
|
end
|
29
|
+
|
30
|
+
def revoke_all_privileges
|
31
|
+
databases_with_access.each do |database|
|
32
|
+
conn.exec("REVOKE ALL PRIVILEGES ON DATABASE #{database} FROM #{username};")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def drop_user
|
37
|
+
conn.exec("DROP USER #{username}")
|
38
|
+
end
|
39
|
+
|
40
|
+
def databases_with_access
|
41
|
+
@databases_with_access ||= begin
|
42
|
+
results = conn.exec <<~SQL
|
43
|
+
SELECT datname
|
44
|
+
FROM pg_database
|
45
|
+
WHERE has_database_privilege('#{username}', datname, 'CONNECT')
|
46
|
+
AND datname NOT IN ('postgres', 'template1', 'template0')
|
47
|
+
SQL
|
48
|
+
|
49
|
+
results.map { |row| row["datname"] }
|
50
|
+
end
|
51
|
+
end
|
26
52
|
end
|
27
53
|
end
|
28
54
|
end
|
data/lib/pgchief/prompt/base.rb
CHANGED
@@ -4,16 +4,45 @@ module Pgchief
|
|
4
4
|
module Prompt
|
5
5
|
# Base class for prompt classes
|
6
6
|
class Base
|
7
|
-
def self.
|
8
|
-
|
7
|
+
def self.call(*params)
|
8
|
+
new(*params).call
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
attr_reader :params
|
12
|
+
|
13
|
+
def initialize(*params)
|
14
|
+
@params = params
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def klassify(scope, words)
|
12
22
|
Object.const_get([
|
13
23
|
"Pgchief", "::", scope.capitalize, "::",
|
14
24
|
words.split.map(&:capitalize)
|
15
25
|
].flatten.join)
|
16
26
|
end
|
27
|
+
|
28
|
+
def yes_or_no(question, yes: nil, no: nil) # rubocop:disable Naming/MethodParameterName
|
29
|
+
response = prompt.yes?(question)
|
30
|
+
response ? yes&.call : no&.call
|
31
|
+
end
|
32
|
+
|
33
|
+
def prompt
|
34
|
+
@prompt ||= TTY::Prompt.new.tap do |p|
|
35
|
+
p.on(:keypress) do |event|
|
36
|
+
p.trigger(:keydown) if event.value == "j"
|
37
|
+
p.trigger(:keyup) if event.value == "k"
|
38
|
+
end
|
39
|
+
|
40
|
+
p.on(:keyescape) do
|
41
|
+
p.say "\n\nExiting...bye-bye 👋\n\n"
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
17
46
|
end
|
18
47
|
end
|
19
48
|
end
|
@@ -4,8 +4,7 @@ module Pgchief
|
|
4
4
|
module Prompt
|
5
5
|
# Class to ask for database name, in order to create it
|
6
6
|
class CreateDatabase < Base
|
7
|
-
def
|
8
|
-
prompt = TTY::Prompt.new
|
7
|
+
def call
|
9
8
|
database = prompt.ask("Database name:")
|
10
9
|
result = Pgchief::Command::DatabaseCreate.call(database)
|
11
10
|
|
@@ -4,13 +4,17 @@ module Pgchief
|
|
4
4
|
module Prompt
|
5
5
|
# Class to prompt for user creation details
|
6
6
|
class CreateUser < Base
|
7
|
-
def
|
8
|
-
prompt = TTY::Prompt.new
|
7
|
+
def call
|
9
8
|
username = prompt.ask("Username:")
|
10
9
|
password = prompt.mask("Password:")
|
11
10
|
result = Pgchief::Command::UserCreate.call(username, password)
|
12
11
|
|
13
12
|
prompt.say result
|
13
|
+
|
14
|
+
yes_or_no(
|
15
|
+
"Give \"#{username}\" access to database(s)?",
|
16
|
+
yes: -> { Pgchief::Prompt::GrantDatabasePrivileges.call(username) }
|
17
|
+
)
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
@@ -4,7 +4,7 @@ module Pgchief
|
|
4
4
|
module Prompt
|
5
5
|
# Class to manage database operations
|
6
6
|
class DatabaseManagement < Base
|
7
|
-
def
|
7
|
+
def call
|
8
8
|
prompt = TTY::Prompt.new
|
9
9
|
result = prompt.select("Database management", ["Create database", "Drop database", "Database List"])
|
10
10
|
scope = result == "Database List" ? "command" : "prompt"
|
@@ -4,8 +4,7 @@ module Pgchief
|
|
4
4
|
module Prompt
|
5
5
|
# Class to prompt for which database to drop
|
6
6
|
class DropDatabase < Base
|
7
|
-
def
|
8
|
-
prompt = TTY::Prompt.new
|
7
|
+
def call
|
9
8
|
database = prompt.select("Which database needs to be dropped?", Pgchief::Database.all)
|
10
9
|
result = Pgchief::Command::DatabaseDrop.call(database)
|
11
10
|
|
@@ -4,8 +4,7 @@ module Pgchief
|
|
4
4
|
module Prompt
|
5
5
|
# Class to prompt for which user to drop
|
6
6
|
class DropUser < Base
|
7
|
-
def
|
8
|
-
prompt = TTY::Prompt.new
|
7
|
+
def call
|
9
8
|
user = prompt.select("Which user needs to be deleted?", Pgchief::User.all)
|
10
9
|
result = Pgchief::Command::UserDrop.call(user)
|
11
10
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pgchief
|
4
|
+
module Prompt
|
5
|
+
# Class to ask for database names, in order to create it
|
6
|
+
class GrantDatabasePrivileges < Base
|
7
|
+
def call
|
8
|
+
username = params.first || select_user
|
9
|
+
databases = prompt.multi_select("Give \"#{username}\" access to database(s):", Pgchief::Database.all)
|
10
|
+
result = Pgchief::Command::DatabasePrivilegesGrant.call(username, databases)
|
11
|
+
|
12
|
+
prompt.say result
|
13
|
+
end
|
14
|
+
|
15
|
+
def select_user
|
16
|
+
prompt.select("Select user to update:", Pgchief::User.all)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/pgchief/prompt/start.rb
CHANGED
@@ -4,9 +4,13 @@ module Pgchief
|
|
4
4
|
module Prompt
|
5
5
|
# Class to manage users
|
6
6
|
class UserManagement < Base
|
7
|
-
def
|
8
|
-
|
9
|
-
|
7
|
+
def call
|
8
|
+
result = prompt.select("User management", [
|
9
|
+
"Create user",
|
10
|
+
"Drop user",
|
11
|
+
"User list",
|
12
|
+
"Grant database privileges"
|
13
|
+
])
|
10
14
|
|
11
15
|
scope = result == "User list" ? "command" : "prompt"
|
12
16
|
klassify(scope, result).call
|
data/lib/pgchief/version.rb
CHANGED
data/lib/pgchief.rb
CHANGED
@@ -14,11 +14,13 @@ require "pgchief/prompt/database_management"
|
|
14
14
|
require "pgchief/prompt/drop_database"
|
15
15
|
require "pgchief/prompt/drop_user"
|
16
16
|
require "pgchief/prompt/user_management"
|
17
|
+
require "pgchief/prompt/grant_database_privileges"
|
17
18
|
|
18
19
|
require "pgchief/command/base"
|
19
20
|
require "pgchief/command/database_create"
|
20
21
|
require "pgchief/command/database_drop"
|
21
22
|
require "pgchief/command/database_list"
|
23
|
+
require "pgchief/command/database_privileges_grant"
|
22
24
|
require "pgchief/command/user_create"
|
23
25
|
require "pgchief/command/user_drop"
|
24
26
|
require "pgchief/command/user_list"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pgchief
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Oliveira
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- lib/pgchief/command/database_create.rb
|
91
91
|
- lib/pgchief/command/database_drop.rb
|
92
92
|
- lib/pgchief/command/database_list.rb
|
93
|
+
- lib/pgchief/command/database_privileges_grant.rb
|
93
94
|
- lib/pgchief/command/user_create.rb
|
94
95
|
- lib/pgchief/command/user_drop.rb
|
95
96
|
- lib/pgchief/command/user_list.rb
|
@@ -101,7 +102,7 @@ files:
|
|
101
102
|
- lib/pgchief/prompt/database_management.rb
|
102
103
|
- lib/pgchief/prompt/drop_database.rb
|
103
104
|
- lib/pgchief/prompt/drop_user.rb
|
104
|
-
- lib/pgchief/prompt/
|
105
|
+
- lib/pgchief/prompt/grant_database_privileges.rb
|
105
106
|
- lib/pgchief/prompt/start.rb
|
106
107
|
- lib/pgchief/prompt/user_management.rb
|
107
108
|
- lib/pgchief/user.rb
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Pgchief
|
4
|
-
module Prompt
|
5
|
-
# Class to ask for database names, in order to create it
|
6
|
-
class GrantDatabasePrivileges
|
7
|
-
def self.call(username)
|
8
|
-
databases = Pgchief::Database.all
|
9
|
-
prompt = TTY::Prompt.new
|
10
|
-
databases = prompt.select("Select database:", databases, multiselect: true)
|
11
|
-
Pgchief::Command::GrantDatabasePrivileges.call(username, databases)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|