redis_web_manager 0.1.6 → 0.1.8

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +2 -0
  3. data/.travis.yml +1 -0
  4. data/Gemfile.lock +23 -1
  5. data/README.md +95 -4
  6. data/Rakefile +1 -1
  7. data/app/controllers/redis_web_manager/actions_controller.rb +15 -3
  8. data/app/controllers/redis_web_manager/application_controller.rb +4 -0
  9. data/app/controllers/redis_web_manager/clients_controller.rb +1 -1
  10. data/app/controllers/redis_web_manager/configuration_controller.rb +1 -1
  11. data/app/controllers/redis_web_manager/dashboard_controller.rb +23 -3
  12. data/app/controllers/redis_web_manager/information_controller.rb +1 -1
  13. data/app/controllers/redis_web_manager/keys_controller.rb +135 -0
  14. data/app/helpers/redis_web_manager/application_helper.rb +16 -0
  15. data/app/helpers/redis_web_manager/dashboard_helper.rb +1 -1
  16. data/app/views/redis_web_manager/dashboard/index.html.erb +20 -1
  17. data/app/views/redis_web_manager/keys/edit.html.erb +14 -0
  18. data/app/views/redis_web_manager/keys/index.html.erb +54 -0
  19. data/app/views/redis_web_manager/keys/show.html.erb +30 -0
  20. data/app/views/redis_web_manager/shared/_header.html.erb +12 -2
  21. data/app/views/redis_web_manager/shared/_status.html.erb +2 -2
  22. data/bin/rails +1 -1
  23. data/config/routes.rb +8 -0
  24. data/lib/redis_web_manager.rb +1 -1
  25. data/lib/redis_web_manager/action.rb +1 -1
  26. data/lib/redis_web_manager/data.rb +16 -0
  27. data/lib/redis_web_manager/version.rb +1 -1
  28. data/redis_web_manager.gemspec +6 -4
  29. data/spec/controllers/redis_web_manager/actions_controller_spec.rb +16 -1
  30. data/spec/controllers/redis_web_manager/clients_controller_spec.rb +1 -1
  31. data/spec/controllers/redis_web_manager/keys_controller_spec.rb +139 -0
  32. data/spec/helpers/application_helper_spec.rb +13 -1
  33. data/spec/helpers/dashboard_helper_spec.rb +1 -1
  34. data/spec/redis_web_manager_data_spec.rb +23 -0
  35. data/spec/routing/actions_controller_spec.rb +6 -0
  36. data/spec/routing/keys_controller_spec.rb +39 -0
  37. data/spec/spec_helper.rb +6 -0
  38. metadata +295 -342
@@ -2,6 +2,22 @@
2
2
 
3
3
  module RedisWebManager
4
4
  module ApplicationHelper
5
+ require 'pagy'
6
+
7
+ include ::Pagy::Frontend
8
+
9
+ def status(value)
10
+ if value
11
+ content_tag(:kbd, 'ON', class: 'bg-success bounce')
12
+ else
13
+ content_tag(:kbd, 'OFF', class: 'bg-danger bounce')
14
+ end
15
+ end
16
+
17
+ def url(value)
18
+ content_tag(:kbd, value, class: 'bg-dark')
19
+ end
20
+
5
21
  def expire(value)
6
22
  if value == -1
7
23
  'No expiration date'
@@ -17,4 +17,4 @@ module RedisWebManager
17
17
  end
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -1,7 +1,7 @@
1
1
  <div class="container">
2
2
  <%= render 'redis_web_manager/shared/status' %>
3
3
  <div class="row my-4">
4
- <div class="col-sm-12 col-md-12">
4
+ <div class="col-sm-12 col-md-9">
5
5
  <div class="row mb-4">
6
6
  <div class="col-12">
7
7
  <div class="card">
@@ -45,5 +45,24 @@
45
45
  </div>
46
46
  </div>
47
47
  </div>
48
+ <div class="col-sm-12 col-md-3">
49
+ <div class="card">
50
+ <div class="card-header">
51
+ <h5 class="card-title mb-0">
52
+ Information
53
+ </h5>
54
+ </div>
55
+ <div class="card-body p-0">
56
+ <ul class="list-group list-group-flush">
57
+ <% @information.each do |data| %>
58
+ <li class="list-group-item d-flex justify-content-between">
59
+ <div class="font-weight-normal"><%= data[:name] %></div>
60
+ <div class="font-weight-light"><%= data[:value] %></div>
61
+ </li>
62
+ <% end %>
63
+ </ul>
64
+ </div>
65
+ </div>
66
+ </div>
48
67
  </div>
49
68
  </div>
@@ -0,0 +1,14 @@
1
+ <div class="container">
2
+ <div class="row my-4">
3
+ <div class="col-sm-6 offset-sm-3">
4
+ <%= form_tag update_key_path, method: :put, class: "form-horizontal center" do %>
5
+ <div class="form-group">
6
+ <%= label_tag :key, "Name key:", class: "control-label" %>
7
+ <%= text_field_tag :key, @key[:key], class: "form-control" %>
8
+ <%= hidden_field_tag :old_key, @key[:key] %>
9
+ </div>
10
+ <%= submit_tag "Submit", class: "btn btn-default btn-primary" %>
11
+ <% end %>
12
+ </div>
13
+ </div>
14
+ </div>
@@ -0,0 +1,54 @@
1
+ <div class="container">
2
+ <%= render 'redis_web_manager/shared/status' %>
3
+ <div class="row my-4">
4
+ <div class="col-12">
5
+ <div class="card">
6
+ <div class="card-header">
7
+ <h5 class="card-title mb-0">
8
+ Keys
9
+ </h5>
10
+ </div>
11
+ <div class="card-body p-0">
12
+ <%= form_tag(keys_path, method: :get, class: 'p-4', enforce_utf8: false) do %>
13
+ <div class="input-group">
14
+ <%= text_field_tag :query, params[:query], class: 'form-control', placeholder: 'Search key(s)' %>
15
+ <div class="input-group-append">
16
+ <%= submit_tag 'Search', class: 'btn btn-primary', name: nil %>
17
+ </div>
18
+ </div>
19
+ <% end %>
20
+ <div class="table-responsive">
21
+ <table class="table mb-0">
22
+ <thead>
23
+ <tr>
24
+ <th>Name</th>
25
+ <th>Expiration Date</th>
26
+ <th>Size</th>
27
+ <th>Type</th>
28
+ <th>Options</th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ <% @keys.each do |key| %>
33
+ <tr>
34
+ <td><%= link_to (key[:key]).truncate(45), key_path(key: key[:key]), title: "Show #{key[:key]}" %></td>
35
+ <td><%= expire(key[:expire]) %></td>
36
+ <td><code><%= number_to_human_size(key[:memory]) %></code></td>
37
+ <td><kbd class="bg-dark"><%= key[:type] %></kbd></td>
38
+ <td>
39
+ <%= link_to 'Edit', edit_key_path(key: key[:key]), title: "Edit #{key[:key]}", class: 'btn btn-sm btn-primary ml-2' %>
40
+ <%= link_to 'Delete', destroy_key_path(key: key[:key]), method: :delete, data: {confirm: 'Are you sure ?'}, title: "Delete #{key[:key]}", class: 'btn btn-sm btn-danger ml-2' %>
41
+ </td>
42
+ </tr>
43
+ <% end %>
44
+ </tbody>
45
+ </table>
46
+ </div>
47
+ </div>
48
+ </div>
49
+ <div class="d-flex align-items-center justify-content-center mt-3">
50
+ <%= pagy_bootstrap_nav(@pagy).html_safe %>
51
+ </div>
52
+ </div>
53
+ </div>
54
+ </div>
@@ -0,0 +1,30 @@
1
+ <div class="container mt-4">
2
+ <div class="row">
3
+ <div class="col-12">
4
+ <label class="font-weight-normal">Key:</label>
5
+ <p class="font-weight-light">
6
+ <code><%= @key[:key] %></code>
7
+ </p>
8
+ <label class="font-weight-normal">Value:</label>
9
+ <p class="font-weight-light">
10
+ <code><%= @key[:node][:value] %></code>
11
+ </p>
12
+ <label class="font-weight-normal">Expires in:</label>
13
+ <p class="font-weight-light">
14
+ <%= expire(@key[:expire]) %>
15
+ </p>
16
+ <label class="font-weight-normal">Size:</label>
17
+ <p class="font-weight-light">
18
+ <code><%= number_to_human_size(@key[:memory]) %></code>
19
+ </p>
20
+ <label class="font-weight-normal">Type:</label>
21
+ <p class="font-weight-light">
22
+ <kbd class="bg-dark"><%= @key[:type] %></kbd>
23
+ </p>
24
+ <p class="font-weight-light">
25
+ <%= link_to 'Delete', destroy_key_path(key: @key[:key]), method: :delete, data: {confirm: 'Are you sure ?'}, title: "Delete #{@key}", class: 'btn btn-sm btn-danger w-100 mb-2' %>
26
+ <%= link_to 'Back', keys_path, title: 'View keys', class: 'btn btn-sm btn-primary w-100' %>
27
+ </p>
28
+ </div>
29
+ </div>
30
+ </div>
@@ -23,15 +23,25 @@
23
23
  </li>
24
24
  </ul>
25
25
  <ul class="navbar-nav ml-auto">
26
+ <li class="nav-item">
27
+ <%= link_to 'Reset statistics',
28
+ reset_path,
29
+ title: 'Reset statistics',
30
+ method: :delete,
31
+ data: {
32
+ confirm: 'Are you sure you want to reset statistics ?'
33
+ },
34
+ class: 'btn btn-sm btn-info nav-link text-white mr-xs-0 mr-lg-2 mb-2 mb-lg-0' %>
35
+ </li>
26
36
  <li class="nav-item">
27
37
  <%= link_to 'Flush ALL',
28
- flushall_url,
38
+ flushall_path,
29
39
  title: 'Flush ALL',
30
40
  method: :delete,
31
41
  data: {
32
42
  confirm: 'Are you sure you want to flush all DB ?'
33
43
  },
34
- class: 'btn btn-sm btn-danger nav-link text-white mr-xs-0 mr-lg-2 mb-2 mb-lg-0' %>
44
+ class: 'btn btn-sm btn-dark nav-link text-white mr-xs-0 mr-lg-2 mb-2 mb-lg-0' %>
35
45
  </li>
36
46
  <li class="nav-item">
37
47
  <%= link_to 'Flush DB',
@@ -1,6 +1,6 @@
1
1
  <div class="row my-4">
2
2
  <div class="col-12">
3
- <%= @url %>
4
- <%= @status %>
3
+ <%= url(@url) %>
4
+ <%= status(@status) %>
5
5
  </div>
6
6
  </div>
data/bin/rails CHANGED
@@ -17,4 +17,4 @@ require 'rails'
17
17
  require 'action_controller/railtie'
18
18
  require 'action_view/railtie'
19
19
  require 'sprockets/railtie'
20
- require 'rails/engine/commands'
20
+ require 'rails/engine/commands'
@@ -7,10 +7,18 @@ RedisWebManager::Engine.routes.draw do
7
7
  # Information
8
8
  get :information, to: 'information#index'
9
9
 
10
+ # Keys
11
+ get 'keys' => 'keys#index'
12
+ get 'key' => 'keys#show'
13
+ get 'key/edit' => 'keys#edit', as: :edit_key
14
+ put 'keys' => 'keys#update', as: :update_key
15
+ delete 'keys' => 'keys#destroy', as: :destroy_key
16
+
10
17
  # Clients
11
18
  get :clients, to: 'clients#index'
12
19
 
13
20
  # Actions
21
+ delete :reset, to: 'actions#reset'
14
22
  delete :flushdb, to: 'actions#flushdb'
15
23
  delete :flushall, to: 'actions#flushall'
16
24
 
@@ -10,8 +10,8 @@ require 'redis'
10
10
 
11
11
  module RedisWebManager
12
12
  mattr_accessor :redis, default: ::Redis.new
13
- mattr_accessor :authenticate, default: nil
14
13
  mattr_accessor :lifespan, default: 15.days
14
+ mattr_accessor :authenticate, default: nil
15
15
 
16
16
  class << self
17
17
  def configure
@@ -18,4 +18,4 @@ module RedisWebManager
18
18
  redis.rename(old_name, new_name)
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -4,14 +4,30 @@ module RedisWebManager
4
4
  class Data < Base
5
5
  BASE = 'RedisWebManager'
6
6
 
7
+ def keys
8
+ data.map { |key| JSON.parse(redis.get(key), symbolize_names: true) }
9
+ end
10
+
7
11
  def perform
8
12
  now = Time.now.to_i
9
13
  seconds = (now + lifespan.to_i) - now
10
14
  redis.setex("#{BASE}_#{now}", seconds, serialize.to_json)
11
15
  end
12
16
 
17
+ def flush
18
+ data.map { |key| redis.del(key) }
19
+ end
20
+
13
21
  private
14
22
 
23
+ def data
24
+ @data ||= redis.scan_each(match: "#{BASE}_*").to_a
25
+ end
26
+
27
+ def lifespan
28
+ @lifespan ||= RedisWebManager.lifespan
29
+ end
30
+
15
31
  def serialize
16
32
  {
17
33
  date: Time.now,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RedisWebManager
4
- VERSION = '0.1.6'
4
+ VERSION = '0.1.8'
5
5
  end
@@ -10,11 +10,10 @@ Gem::Specification.new do |spec|
10
10
  spec.name = 'redis_web_manager'
11
11
  spec.version = RedisWebManager::VERSION
12
12
 
13
- spec.authors = ['Boris BRESCIANI', 'Benjamin DARCET', 'Olivier DUMAS', 'Sylvain KRAISIN']
13
+ spec.authors = ['Boris BRESCIANI', 'Benjamin DARCET', 'Olivier DUMAS']
14
14
  spec.email = %w[boris2bresciani@gmail.com
15
15
  b.darcet@gmail.com
16
- dumas.olivier@outlook.fr
17
- sylvain.kraisin@gmail.com]
16
+ dumas.olivier@outlook.fr]
18
17
 
19
18
  spec.summary = 'Manage your Redis instance (See keys, memory used, connected client, etc...)'
20
19
  spec.description = 'Manage your Redis instance (See keys, memory used, connected client, configuration, information)'
@@ -35,8 +34,11 @@ Gem::Specification.new do |spec|
35
34
  spec.require_paths = ['lib']
36
35
  spec.test_files = Dir['spec/**/*']
37
36
 
37
+ spec.add_development_dependency 'coveralls', '~> 0.8'
38
38
  spec.add_development_dependency 'rspec-rails', '= 4.0.0.beta3'
39
+ spec.add_development_dependency 'simplecov', '~> 0.16'
39
40
 
41
+ spec.add_dependency 'pagy', '~> 3.7'
40
42
  spec.add_dependency 'rails', '>= 5.2', '< 7'
41
43
  spec.add_dependency 'redis', '~> 4.1.0'
42
- end
44
+ end
@@ -5,9 +5,24 @@ require 'rails_helper'
5
5
  RSpec.describe RedisWebManager::ActionsController, type: :controller do
6
6
  routes { RedisWebManager::Engine.routes }
7
7
 
8
+ describe 'DELETE #reset' do
9
+ it 'returns a success response' do
10
+ delete :reset
11
+ expect(response).to be_redirect
12
+ end
13
+ end
14
+
8
15
  describe 'DELETE #flushdb' do
16
+ it 'returns a success response' do
17
+ delete :flushdb
18
+ expect(response).to be_redirect
19
+ end
9
20
  end
10
21
 
11
22
  describe 'DELETE #flushall' do
23
+ it 'returns a success response' do
24
+ delete :flushall
25
+ expect(response).to be_redirect
26
+ end
12
27
  end
13
- end
28
+ end
@@ -11,4 +11,4 @@ RSpec.describe RedisWebManager::ClientsController, type: :controller do
11
11
  expect(response).to be_successful
12
12
  end
13
13
  end
14
- end
14
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ RSpec.describe RedisWebManager::KeysController, type: :controller do
6
+ routes { RedisWebManager::Engine.routes }
7
+ let(:redis) do
8
+ ::Redis.new
9
+ end
10
+
11
+ describe 'GET #index' do
12
+ it 'returns a success response' do
13
+ get :index
14
+ expect(response).to be_successful
15
+ get :index, params: { query: 'Search' }
16
+ expect(response).to be_successful
17
+ end
18
+ end
19
+
20
+ describe 'GET #show' do
21
+ it 'returns a success response' do
22
+ redis.set('test', 'test')
23
+ get :show, params: { key: 'test' }
24
+ expect(response).to be_successful
25
+ end
26
+ end
27
+
28
+ describe 'GET #edit' do
29
+ it 'returns a success response' do
30
+ redis.set('test', 'test')
31
+ get :edit, params: { key: 'test' }
32
+ expect(response).to be_successful
33
+ end
34
+ end
35
+
36
+ describe 'GET #update' do
37
+ it 'returns a success response' do
38
+ redis.set('test', 'test')
39
+ put :update, params: { old_name: 'test', new_name: 'testtest' }
40
+ expect(response).to be_redirect
41
+ end
42
+ end
43
+
44
+ describe 'GET #destroy' do
45
+ it 'returns a success response' do
46
+ redis.set('test', 'test')
47
+ delete :destroy, params: { key: 'test' }
48
+ expect(response).to be_redirect
49
+ end
50
+ end
51
+
52
+ describe 'Methods' do
53
+ it 'returns a hash value (get_value - string)' do
54
+ redis.set('test', 'test')
55
+ eql = {
56
+ value: 'test'
57
+ }
58
+ expect(controller.send(:get_value, 'test')).to eql(eql)
59
+ end
60
+
61
+ it 'returns a hash value (get_value - hgetall)' do
62
+ eql = {
63
+ value: {
64
+ 'name' => {
65
+ type: 'string',
66
+ value: 'hgetall'
67
+ }
68
+ }
69
+ }
70
+ redis.hset('hgetall', 'name', 'hgetall')
71
+ expect(controller.send(:get_value, 'hgetall')).to eql(eql)
72
+ end
73
+
74
+ it 'returns a hash value (get_value - lrange)' do
75
+ redis.lpush('lrange', '1')
76
+ redis.lpush('lrange', '2')
77
+ eql = {
78
+ length: 2,
79
+ values: [
80
+ {
81
+ index: 0,
82
+ type: 'json',
83
+ value: 2
84
+ },
85
+ {
86
+ index: 1,
87
+ type: 'json',
88
+ value: 1
89
+ }
90
+ ]
91
+ }
92
+ expect(controller.send(:get_value, 'lrange')).to eql(eql)
93
+ end
94
+
95
+ it 'returns a hash value (get_value - set)' do
96
+ redis.sadd('smembers', 'smembers')
97
+ eql = {
98
+ values: [{ type: 'string', value: 'smembers' }]
99
+ }
100
+ expect(controller.send(:get_value, 'smembers')).to eql(eql)
101
+ end
102
+
103
+ it 'returns a hash value (get_value - zset)' do
104
+ redis.zadd('zrange', 10, '1')
105
+ redis.zadd('zrange', 20, '2')
106
+ redis.zadd('zrange', 30, '3')
107
+ eql = {
108
+ values: [
109
+ {
110
+ score: 10.0,
111
+ type: 'json',
112
+ value: 1
113
+ },
114
+ {
115
+ score: 20.0,
116
+ type: 'json',
117
+ value: 2
118
+ },
119
+ {
120
+ score: 30.0,
121
+ type: 'json',
122
+ value: 3
123
+ }
124
+ ]
125
+ }
126
+ expect(controller.send(:get_value, 'zrange')).to eql(eql)
127
+ end
128
+
129
+ it 'returns a hash value (get_value - not found)' do
130
+ redis.zadd('zrange', 10, '1')
131
+ redis.zadd('zrange', 20, '2')
132
+ redis.zadd('zrange', 30, '3')
133
+ eql = {
134
+ value: 'Not found'
135
+ }
136
+ expect(controller.send(:get_value, 'testtesttesttesttest')).to eql(eql)
137
+ end
138
+ end
139
+ end