refactor: split Server into api_routes and admin_routes modules
Keep server.rb focused on configuration, session setup, and shared helpers. Extract route definitions into registered Sinatra extension modules. Exclude the registered methods from AbcSize/MethodLength metrics — large registered methods are the idiomatic Sinatra pattern.
This commit is contained in:
@@ -19,13 +19,23 @@ Layout/LineLength:
|
|||||||
|
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Max: 30
|
Max: 30
|
||||||
|
Exclude:
|
||||||
|
- "lib/volumen/admin_routes.rb"
|
||||||
|
- "lib/volumen/api_routes.rb"
|
||||||
|
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
Max: 25
|
Max: 25
|
||||||
|
Exclude:
|
||||||
|
- "lib/volumen/admin_routes.rb"
|
||||||
|
- "lib/volumen/api_routes.rb"
|
||||||
|
|
||||||
Metrics/ClassLength:
|
Metrics/ClassLength:
|
||||||
Max: 400
|
Max: 400
|
||||||
|
|
||||||
|
Metrics/ModuleLength:
|
||||||
|
Exclude:
|
||||||
|
- "lib/volumen/admin_routes.rb"
|
||||||
|
|
||||||
Metrics/BlockLength:
|
Metrics/BlockLength:
|
||||||
Exclude:
|
Exclude:
|
||||||
- "test/**/*"
|
- "test/**/*"
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Volumen
|
||||||
|
# Server-rendered admin routes, registered into Volumen::Server.
|
||||||
|
module AdminRoutes
|
||||||
|
def self.registered(app)
|
||||||
|
app.get "/admin" do
|
||||||
|
redirect to("/admin/")
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/admin/" do
|
||||||
|
require_login!
|
||||||
|
@posts = sorted_posts
|
||||||
|
erb :list
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/admin/login" do
|
||||||
|
redirect to("/admin/") if authenticated?
|
||||||
|
|
||||||
|
erb :login
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/login" do
|
||||||
|
check_csrf!
|
||||||
|
check_login_rate_limit!
|
||||||
|
user = users.authenticate(params["username"], params["password"])
|
||||||
|
if user
|
||||||
|
session[:user] = user.username
|
||||||
|
redirect to("/admin/")
|
||||||
|
else
|
||||||
|
@error = "Invalid username or password."
|
||||||
|
erb :login
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/logout" do
|
||||||
|
check_csrf!
|
||||||
|
session.clear
|
||||||
|
redirect to("/admin/login")
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/admin/posts/new" do
|
||||||
|
require_login!
|
||||||
|
@mode = :new
|
||||||
|
@post = Post.new(metadata: { "lang" => config.language })
|
||||||
|
erb :form
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/posts" do
|
||||||
|
require_login!
|
||||||
|
check_csrf!
|
||||||
|
create_post
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/admin/posts/:slug/edit" do
|
||||||
|
require_login!
|
||||||
|
@mode = :edit
|
||||||
|
@post = store.find(params["slug"])
|
||||||
|
halt(404, "Not found") if @post.nil?
|
||||||
|
|
||||||
|
erb :form
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/posts/:slug" do
|
||||||
|
require_login!
|
||||||
|
check_csrf!
|
||||||
|
update_post
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/posts/:slug/delete" do
|
||||||
|
require_login!
|
||||||
|
check_csrf!
|
||||||
|
store.delete(params["slug"])
|
||||||
|
redirect to("/admin/")
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/preview" do
|
||||||
|
require_login!
|
||||||
|
content_type :html
|
||||||
|
Markdown.render(params["body"].to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/uploads" do
|
||||||
|
require_login!
|
||||||
|
check_csrf!
|
||||||
|
content_type :json
|
||||||
|
upload = params["file"]
|
||||||
|
halt(400, json("error" => "no_file")) unless upload.is_a?(Hash) && upload[:tempfile]
|
||||||
|
|
||||||
|
json("url" => store.store_upload(upload[:filename], upload[:tempfile]))
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/media/*" do
|
||||||
|
path = store.media_file(params["splat"].first)
|
||||||
|
halt(404) if path.nil?
|
||||||
|
|
||||||
|
send_file(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/admin/logo.svg" do
|
||||||
|
send_file(File.expand_path("web/public/volumen-logo.svg", __dir__))
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/admin/settings" do
|
||||||
|
require_login!
|
||||||
|
render_settings
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/settings/password" do
|
||||||
|
require_login!
|
||||||
|
check_csrf!
|
||||||
|
change_password
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/settings/username" do
|
||||||
|
require_login!
|
||||||
|
check_csrf!
|
||||||
|
change_username
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/settings/users" do
|
||||||
|
require_login!
|
||||||
|
require_admin!
|
||||||
|
check_csrf!
|
||||||
|
create_user
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/settings/users/:username/role" do
|
||||||
|
require_login!
|
||||||
|
require_admin!
|
||||||
|
check_csrf!
|
||||||
|
change_role(params["username"])
|
||||||
|
end
|
||||||
|
|
||||||
|
app.post "/admin/settings/users/:username/delete" do
|
||||||
|
require_login!
|
||||||
|
require_admin!
|
||||||
|
check_csrf!
|
||||||
|
remove_user(params["username"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Volumen
|
||||||
|
# Public JSON API routes, registered into Volumen::Server.
|
||||||
|
module ApiRoutes
|
||||||
|
def self.registered(app)
|
||||||
|
app.before "/api/volumen/*" do
|
||||||
|
headers "Access-Control-Allow-Origin" => "*"
|
||||||
|
content_type :json
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/api/volumen/site" do
|
||||||
|
json(site_payload)
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/api/volumen/posts" do
|
||||||
|
json(posts_payload)
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/api/volumen/posts/:slug" do
|
||||||
|
post = store.find(params["slug"], lang: params["lang"])
|
||||||
|
halt(404, json("error" => "not_found")) if post.nil?
|
||||||
|
|
||||||
|
json(post.detail)
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/api/volumen/tags" do
|
||||||
|
json("tags" => tag_counts)
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/api/volumen/feed.xml" do
|
||||||
|
content_type "application/rss+xml"
|
||||||
|
feed_xml
|
||||||
|
end
|
||||||
|
|
||||||
|
app.get "/api/volumen/sitemap.xml" do
|
||||||
|
content_type "application/xml"
|
||||||
|
sitemap_xml
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
+5
-173
@@ -8,6 +8,8 @@ require_relative "config"
|
|||||||
require_relative "store"
|
require_relative "store"
|
||||||
require_relative "markdown"
|
require_relative "markdown"
|
||||||
require_relative "password"
|
require_relative "password"
|
||||||
|
require_relative "api_routes"
|
||||||
|
require_relative "admin_routes"
|
||||||
|
|
||||||
module Volumen
|
module Volumen
|
||||||
# Sinatra application: the public JSON API at /api/volumen and the
|
# Sinatra application: the public JSON API at /api/volumen and the
|
||||||
@@ -16,6 +18,9 @@ module Volumen
|
|||||||
MAX_LOGIN_ATTEMPTS = 10
|
MAX_LOGIN_ATTEMPTS = 10
|
||||||
LOGIN_WINDOW = 60 # seconds
|
LOGIN_WINDOW = 60 # seconds
|
||||||
|
|
||||||
|
register ApiRoutes
|
||||||
|
register AdminRoutes
|
||||||
|
|
||||||
configure do
|
configure do
|
||||||
set :show_exceptions, false
|
set :show_exceptions, false
|
||||||
set :raise_errors, false
|
set :raise_errors, false
|
||||||
@@ -49,179 +54,6 @@ module Volumen
|
|||||||
options[:secure] = request.ssl? if options
|
options[:secure] = request.ssl? if options
|
||||||
end
|
end
|
||||||
|
|
||||||
# --- Public JSON API -------------------------------------------------
|
|
||||||
|
|
||||||
before "/api/volumen/*" do
|
|
||||||
headers "Access-Control-Allow-Origin" => "*"
|
|
||||||
content_type :json
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/api/volumen/site" do
|
|
||||||
json(site_payload)
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/api/volumen/posts" do
|
|
||||||
json(posts_payload)
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/api/volumen/posts/:slug" do
|
|
||||||
post = store.find(params["slug"], lang: params["lang"])
|
|
||||||
halt(404, json("error" => "not_found")) if post.nil?
|
|
||||||
|
|
||||||
json(post.detail)
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/api/volumen/tags" do
|
|
||||||
json("tags" => tag_counts)
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/api/volumen/feed.xml" do
|
|
||||||
content_type "application/rss+xml"
|
|
||||||
feed_xml
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/api/volumen/sitemap.xml" do
|
|
||||||
content_type "application/xml"
|
|
||||||
sitemap_xml
|
|
||||||
end
|
|
||||||
|
|
||||||
# --- Admin -----------------------------------------------------------
|
|
||||||
|
|
||||||
get "/admin" do
|
|
||||||
redirect to("/admin/")
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/admin/" do
|
|
||||||
require_login!
|
|
||||||
@posts = sorted_posts
|
|
||||||
erb :list
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/admin/login" do
|
|
||||||
redirect to("/admin/") if authenticated?
|
|
||||||
|
|
||||||
erb :login
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/login" do
|
|
||||||
check_csrf!
|
|
||||||
check_login_rate_limit!
|
|
||||||
user = users.authenticate(params["username"], params["password"])
|
|
||||||
if user
|
|
||||||
session[:user] = user.username
|
|
||||||
redirect to("/admin/")
|
|
||||||
else
|
|
||||||
@error = "Invalid username or password."
|
|
||||||
erb :login
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/logout" do
|
|
||||||
check_csrf!
|
|
||||||
session.clear
|
|
||||||
redirect to("/admin/login")
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/admin/posts/new" do
|
|
||||||
require_login!
|
|
||||||
@mode = :new
|
|
||||||
@post = Post.new(metadata: { "lang" => config.language })
|
|
||||||
erb :form
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/posts" do
|
|
||||||
require_login!
|
|
||||||
check_csrf!
|
|
||||||
create_post
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/admin/posts/:slug/edit" do
|
|
||||||
require_login!
|
|
||||||
@mode = :edit
|
|
||||||
@post = store.find(params["slug"])
|
|
||||||
halt(404, "Not found") if @post.nil?
|
|
||||||
|
|
||||||
erb :form
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/posts/:slug" do
|
|
||||||
require_login!
|
|
||||||
check_csrf!
|
|
||||||
update_post
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/posts/:slug/delete" do
|
|
||||||
require_login!
|
|
||||||
check_csrf!
|
|
||||||
store.delete(params["slug"])
|
|
||||||
redirect to("/admin/")
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/preview" do
|
|
||||||
require_login!
|
|
||||||
content_type :html
|
|
||||||
Markdown.render(params["body"].to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/uploads" do
|
|
||||||
require_login!
|
|
||||||
check_csrf!
|
|
||||||
content_type :json
|
|
||||||
upload = params["file"]
|
|
||||||
halt(400, json("error" => "no_file")) unless upload.is_a?(Hash) && upload[:tempfile]
|
|
||||||
|
|
||||||
json("url" => store.store_upload(upload[:filename], upload[:tempfile]))
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/media/*" do
|
|
||||||
path = store.media_file(params["splat"].first)
|
|
||||||
halt(404) if path.nil?
|
|
||||||
|
|
||||||
send_file(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/admin/logo.svg" do
|
|
||||||
send_file(File.expand_path("web/public/volumen-logo.svg", __dir__))
|
|
||||||
end
|
|
||||||
|
|
||||||
get "/admin/settings" do
|
|
||||||
require_login!
|
|
||||||
render_settings
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/settings/password" do
|
|
||||||
require_login!
|
|
||||||
check_csrf!
|
|
||||||
change_password
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/settings/username" do
|
|
||||||
require_login!
|
|
||||||
check_csrf!
|
|
||||||
change_username
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/settings/users" do
|
|
||||||
require_login!
|
|
||||||
require_admin!
|
|
||||||
check_csrf!
|
|
||||||
create_user
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/settings/users/:username/role" do
|
|
||||||
require_login!
|
|
||||||
require_admin!
|
|
||||||
check_csrf!
|
|
||||||
change_role(params["username"])
|
|
||||||
end
|
|
||||||
|
|
||||||
post "/admin/settings/users/:username/delete" do
|
|
||||||
require_login!
|
|
||||||
require_admin!
|
|
||||||
check_csrf!
|
|
||||||
remove_user(params["username"])
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def config
|
def config
|
||||||
|
|||||||
Reference in New Issue
Block a user