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:
|
||||
Max: 30
|
||||
Exclude:
|
||||
- "lib/volumen/admin_routes.rb"
|
||||
- "lib/volumen/api_routes.rb"
|
||||
|
||||
Metrics/MethodLength:
|
||||
Max: 25
|
||||
Exclude:
|
||||
- "lib/volumen/admin_routes.rb"
|
||||
- "lib/volumen/api_routes.rb"
|
||||
|
||||
Metrics/ClassLength:
|
||||
Max: 400
|
||||
|
||||
Metrics/ModuleLength:
|
||||
Exclude:
|
||||
- "lib/volumen/admin_routes.rb"
|
||||
|
||||
Metrics/BlockLength:
|
||||
Exclude:
|
||||
- "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 "markdown"
|
||||
require_relative "password"
|
||||
require_relative "api_routes"
|
||||
require_relative "admin_routes"
|
||||
|
||||
module Volumen
|
||||
# Sinatra application: the public JSON API at /api/volumen and the
|
||||
@@ -16,6 +18,9 @@ module Volumen
|
||||
MAX_LOGIN_ATTEMPTS = 10
|
||||
LOGIN_WINDOW = 60 # seconds
|
||||
|
||||
register ApiRoutes
|
||||
register AdminRoutes
|
||||
|
||||
configure do
|
||||
set :show_exceptions, false
|
||||
set :raise_errors, false
|
||||
@@ -49,179 +54,6 @@ module Volumen
|
||||
options[:secure] = request.ssl? if options
|
||||
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
|
||||
|
||||
def config
|
||||
|
||||
Reference in New Issue
Block a user