eksa-framework 3.3.2 → 3.4.3
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/.eksa.json +4 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +10 -0
- data/README.md +20 -3
- data/_posts/2026-03-15-welcome-to-eksa-framework.md +145 -123
- data/app/views/about.html.erb +30 -10
- data/app/views/docs.html.erb +23 -4
- data/app/views/index.html.erb +1 -1
- data/app/views/layout.html.erb +1 -1
- data/app/views/posts/index.html.erb +26 -8
- data/app/views/posts/show.html.erb +25 -5
- data/exe/eksa +98 -3
- data/lib/eksa/auth_controller.rb +50 -0
- data/lib/eksa/cms_controller.rb +110 -0
- data/lib/eksa/controller.rb +32 -6
- data/lib/eksa/markdown_post.rb +23 -4
- data/lib/eksa/user.rb +47 -0
- data/lib/eksa/version.rb +1 -1
- data/lib/eksa/views/auth/login.html.erb +44 -0
- data/lib/eksa/views/auth/register.html.erb +53 -0
- data/lib/eksa/views/cms/edit.html.erb +63 -0
- data/lib/eksa/views/cms/index.html.erb +83 -0
- data/lib/eksa.rb +48 -3
- data/public/img/logo.jpg +0 -0
- metadata +38 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<div class="glass rounded-3xl p-10 text-white animate__animated animate__fadeIn">
|
|
2
|
+
<div class="flex items-center justify-between mb-10 pb-6 border-b border-white/10">
|
|
3
|
+
<div class="flex items-center gap-4">
|
|
4
|
+
<div class="p-4 bg-indigo-500 rounded-2xl shadow-xl">
|
|
5
|
+
<i data-lucide="layout-dashboard" class="w-8 h-8"></i>
|
|
6
|
+
</div>
|
|
7
|
+
<div>
|
|
8
|
+
<h1 class="text-4xl font-extrabold tracking-tight">CMS <span class="text-indigo-300">Dashboard</span></h1>
|
|
9
|
+
<p class="text-white/50">Kelola visibilitas postingan blog Anda</p>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="flex items-center gap-4">
|
|
13
|
+
<span class="px-4 py-2 bg-white/5 rounded-xl border border-white/10 text-sm font-medium text-white/80">
|
|
14
|
+
<i data-lucide="user" class="w-4 h-4 inline-block mr-1"></i> Admin
|
|
15
|
+
</span>
|
|
16
|
+
<a href="/auth/logout" class="px-4 py-2 bg-red-500/20 hover:bg-red-500/40 text-red-300 rounded-xl border border-red-500/30 transition shadow-lg text-sm font-bold flex items-center gap-2">
|
|
17
|
+
<i data-lucide="log-out" class="w-4 h-4"></i> Logout
|
|
18
|
+
</a>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="overflow-hidden rounded-2xl border border-white/10 bg-black/20">
|
|
23
|
+
<table class="w-full text-left border-collapse">
|
|
24
|
+
<thead>
|
|
25
|
+
<tr class="bg-white/5 text-indigo-200 text-xs uppercase tracking-widest">
|
|
26
|
+
<th class="p-4 font-bold border-b border-white/10">Postingan</th>
|
|
27
|
+
<th class="p-4 font-bold border-b border-white/10">Kategori</th>
|
|
28
|
+
<th class="p-4 font-bold border-b border-white/10">Status</th>
|
|
29
|
+
<th class="p-4 font-bold border-b border-white/10 text-right">Aksi</th>
|
|
30
|
+
</tr>
|
|
31
|
+
</thead>
|
|
32
|
+
<tbody class="divide-y divide-white/5">
|
|
33
|
+
<% if @posts.empty? %>
|
|
34
|
+
<tr>
|
|
35
|
+
<td colspan="4" class="p-8 text-center text-white/40">
|
|
36
|
+
<i data-lucide="folder-open" class="w-8 h-8 mx-auto mb-2 opacity-50"></i>
|
|
37
|
+
Belum ada postingan markdown di _posts/
|
|
38
|
+
</td>
|
|
39
|
+
</tr>
|
|
40
|
+
<% else %>
|
|
41
|
+
<% @posts.each do |post| %>
|
|
42
|
+
<tr class="hover:bg-white/5 transition">
|
|
43
|
+
<td class="p-4">
|
|
44
|
+
<p class="font-bold text-lg"><%= post.title %></p>
|
|
45
|
+
<p class="text-xs text-white/40 font-mono"><%= post.filename %></p>
|
|
46
|
+
</td>
|
|
47
|
+
<td class="p-4">
|
|
48
|
+
<span class="text-[10px] font-bold text-indigo-300 uppercase tracking-widest px-2 py-1 bg-indigo-500/20 rounded-md border border-indigo-500/30">
|
|
49
|
+
<%= post.category %>
|
|
50
|
+
</span>
|
|
51
|
+
</td>
|
|
52
|
+
<td class="p-4">
|
|
53
|
+
<% if post.published? %>
|
|
54
|
+
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-bold bg-emerald-500/20 text-emerald-300 border border-emerald-500/30">
|
|
55
|
+
<span class="w-2 h-2 rounded-full bg-emerald-400"></span> Aktif
|
|
56
|
+
</span>
|
|
57
|
+
<% else %>
|
|
58
|
+
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-bold bg-gray-500/20 text-gray-400 border border-gray-500/30">
|
|
59
|
+
<span class="w-2 h-2 rounded-full bg-gray-400"></span> Draft
|
|
60
|
+
</span>
|
|
61
|
+
<% end %>
|
|
62
|
+
</td>
|
|
63
|
+
<td class="p-4 text-right space-x-2">
|
|
64
|
+
<a href="/cms/edit/<%= post.slug %>" class="inline-flex items-center justify-center p-2 rounded-lg bg-yellow-500/20 hover:bg-yellow-500/40 text-yellow-300 transition border border-yellow-500/30" title="Edit Post">
|
|
65
|
+
<i data-lucide="edit" class="w-4 h-4"></i>
|
|
66
|
+
</a>
|
|
67
|
+
<a href="/posts/<%= post.slug %>" target="_blank" class="inline-flex items-center justify-center p-2 rounded-lg bg-white/5 hover:bg-white/10 text-white/70 transition border border-white/10" title="Lihat Post">
|
|
68
|
+
<i data-lucide="external-link" class="w-4 h-4"></i>
|
|
69
|
+
</a>
|
|
70
|
+
<a href="/cms/toggle/<%= post.slug %>" class="inline-flex items-center justify-center p-2 rounded-lg bg-indigo-500/20 hover:bg-indigo-500/40 text-indigo-300 transition border border-indigo-500/30" title="Toggle Status">
|
|
71
|
+
<i data-lucide="<%= post.published? ? 'eye-off' : 'eye' %>" class="w-4 h-4"></i>
|
|
72
|
+
</a>
|
|
73
|
+
<a href="/cms/delete/<%= post.slug %>" onclick="return confirm('Yakin ingin menghapus postingan ini selamanya?')" class="inline-flex items-center justify-center p-2 rounded-lg bg-red-500/20 hover:bg-red-500/40 text-red-300 transition border border-red-500/30" title="Hapus Permanen">
|
|
74
|
+
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
75
|
+
</a>
|
|
76
|
+
</td>
|
|
77
|
+
</tr>
|
|
78
|
+
<% end %>
|
|
79
|
+
<% end %>
|
|
80
|
+
</tbody>
|
|
81
|
+
</table>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
data/lib/eksa.rb
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
require 'rack'
|
|
2
|
+
require 'rack/session'
|
|
2
3
|
require 'json'
|
|
3
4
|
require_relative 'eksa/version'
|
|
4
5
|
require_relative 'eksa/controller'
|
|
5
6
|
require_relative 'eksa/model'
|
|
6
7
|
require_relative 'eksa/markdown_post'
|
|
8
|
+
require_relative 'eksa/user'
|
|
9
|
+
require_relative 'eksa/auth_controller'
|
|
10
|
+
require_relative 'eksa/cms_controller'
|
|
7
11
|
|
|
8
12
|
module Eksa
|
|
9
13
|
class Application
|
|
10
|
-
attr_reader :config, :middlewares
|
|
14
|
+
attr_reader :config, :middlewares, :features
|
|
11
15
|
|
|
12
16
|
def initialize
|
|
13
17
|
@routes = {}
|
|
14
18
|
@middlewares = []
|
|
19
|
+
@features = load_feature_flags
|
|
15
20
|
@config = {
|
|
16
|
-
db_path: File.expand_path("./db/eksa_app.db")
|
|
21
|
+
db_path: File.expand_path("./db/eksa_app.db"),
|
|
22
|
+
session_secret: ENV['SESSION_SECRET'] || 'eksa_super_secret_key_change_me_in_production_make_it_sixty_four_bytes_or_more'
|
|
17
23
|
}
|
|
18
24
|
yield self if block_given?
|
|
19
25
|
configure_framework
|
|
@@ -21,6 +27,40 @@ module Eksa
|
|
|
21
27
|
|
|
22
28
|
def configure_framework
|
|
23
29
|
Eksa::Model.database_path = @config[:db_path]
|
|
30
|
+
|
|
31
|
+
# Setup Session Middleware for Authentication
|
|
32
|
+
use Rack::Session::Cookie, secret: @config[:session_secret], key: 'eksa.session'
|
|
33
|
+
|
|
34
|
+
auto_mount_features
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def load_feature_flags
|
|
38
|
+
config_path = File.expand_path('./.eksa.json')
|
|
39
|
+
if File.exist?(config_path)
|
|
40
|
+
JSON.parse(File.read(config_path))
|
|
41
|
+
else
|
|
42
|
+
{ 'cms' => false, 'auth' => false }
|
|
43
|
+
end
|
|
44
|
+
rescue JSON::ParserError
|
|
45
|
+
{ 'cms' => false, 'auth' => false }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def auto_mount_features
|
|
49
|
+
if @features['auth']
|
|
50
|
+
add_route "/auth/login", Eksa::AuthController, :login
|
|
51
|
+
add_route "/auth/register", Eksa::AuthController, :register
|
|
52
|
+
add_route "/auth/logout", Eksa::AuthController, :logout
|
|
53
|
+
add_route "/auth/process_login", Eksa::AuthController, :process_login
|
|
54
|
+
add_route "/auth/process_register", Eksa::AuthController, :process_register
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if @features['cms']
|
|
58
|
+
add_route "/cms", Eksa::CmsController, :index
|
|
59
|
+
add_route "/cms/edit/:slug", Eksa::CmsController, :edit
|
|
60
|
+
add_route "/cms/update/:slug", Eksa::CmsController, :update_post
|
|
61
|
+
add_route "/cms/toggle/:slug", Eksa::CmsController, :toggle_status
|
|
62
|
+
add_route "/cms/delete/:slug", Eksa::CmsController, :delete_post
|
|
63
|
+
end
|
|
24
64
|
end
|
|
25
65
|
|
|
26
66
|
def add_route(path, controller_class, action)
|
|
@@ -82,6 +122,9 @@ module Eksa
|
|
|
82
122
|
else
|
|
83
123
|
response = Rack::Response.new
|
|
84
124
|
if controller_instance.status == 302
|
|
125
|
+
if controller_instance.flash[:notice] && !controller_instance.flash[:notice].empty?
|
|
126
|
+
response.set_cookie('eksa_flash', value: controller_instance.flash[:notice], path: '/')
|
|
127
|
+
end
|
|
85
128
|
response.redirect(controller_instance.redirect_url, 302)
|
|
86
129
|
else
|
|
87
130
|
response.write(response_data)
|
|
@@ -89,7 +132,9 @@ module Eksa
|
|
|
89
132
|
end
|
|
90
133
|
end
|
|
91
134
|
|
|
92
|
-
|
|
135
|
+
if flash_message && controller_instance.status != 302
|
|
136
|
+
response.delete_cookie('eksa_flash', path: '/')
|
|
137
|
+
end
|
|
93
138
|
response.finish
|
|
94
139
|
else
|
|
95
140
|
html = <<~HTML
|
data/public/img/logo.jpg
ADDED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: eksa-framework
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.3
|
|
4
|
+
version: 3.4.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- IshikawaUta
|
|
@@ -93,6 +93,34 @@ dependencies:
|
|
|
93
93
|
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
95
|
version: '1.1'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: bcrypt
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '3.1'
|
|
103
|
+
type: :runtime
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '3.1'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: rack-session
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '2.0'
|
|
117
|
+
type: :runtime
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '2.0'
|
|
96
124
|
description: Framework MVC ringan dengan tema modern, sistem routing, dan auto-database
|
|
97
125
|
SQLite.
|
|
98
126
|
email:
|
|
@@ -102,6 +130,7 @@ executables:
|
|
|
102
130
|
extensions: []
|
|
103
131
|
extra_rdoc_files: []
|
|
104
132
|
files:
|
|
133
|
+
- ".eksa.json"
|
|
105
134
|
- Gemfile
|
|
106
135
|
- Gemfile.lock
|
|
107
136
|
- LICENSE
|
|
@@ -123,12 +152,20 @@ files:
|
|
|
123
152
|
- db/setup.rb
|
|
124
153
|
- exe/eksa
|
|
125
154
|
- lib/eksa.rb
|
|
155
|
+
- lib/eksa/auth_controller.rb
|
|
156
|
+
- lib/eksa/cms_controller.rb
|
|
126
157
|
- lib/eksa/controller.rb
|
|
127
158
|
- lib/eksa/markdown_post.rb
|
|
128
159
|
- lib/eksa/model.rb
|
|
160
|
+
- lib/eksa/user.rb
|
|
129
161
|
- lib/eksa/version.rb
|
|
162
|
+
- lib/eksa/views/auth/login.html.erb
|
|
163
|
+
- lib/eksa/views/auth/register.html.erb
|
|
164
|
+
- lib/eksa/views/cms/edit.html.erb
|
|
165
|
+
- lib/eksa/views/cms/index.html.erb
|
|
130
166
|
- public/css/style.css
|
|
131
167
|
- public/img/favicon.ico
|
|
168
|
+
- public/img/logo.jpg
|
|
132
169
|
- public/img/logo.png
|
|
133
170
|
- spec/application_spec.rb
|
|
134
171
|
- spec/markdown_post_spec.rb
|