diff --git a/app/controllers/servers_controller.rb b/app/controllers/servers_controller.rb index 7e4c427..05460d3 100644 --- a/app/controllers/servers_controller.rb +++ b/app/controllers/servers_controller.rb @@ -10,12 +10,18 @@ class ServersController < ApplicationController end def new - @server_template = current_user.server_templates.find(params[:server_template_id]) - @server = current_user.servers.build(server_template: @server_template) + @server_templates = current_user.server_templates.order(:name) + if params[:server_template_id].present? + @server_template = current_user.server_templates.find(params[:server_template_id]) + @server = current_user.servers.build(server_template: @server_template) + else + @server = current_user.servers.build + end end def create - @server_template = current_user.server_templates.find(params[:server_template_id]) + template_id = params[:server_template_id] || server_params[:server_template_id] + @server_template = current_user.server_templates.find(template_id) @server = current_user.servers.build(server_params) @server.server_template = @server_template @server.status = :stopped @@ -25,6 +31,7 @@ class ServersController < ApplicationController SpawnServerJob.perform_later(@server.id) redirect_to @server, notice: "Server spawning..." else + @server_templates = current_user.server_templates.order(:name) render :new, status: :unprocessable_entity end end @@ -68,7 +75,7 @@ class ServersController < ApplicationController end def server_params - params.require(:server).permit(:name, :port) + params.require(:server).permit(:name, :port, :server_template_id) end def authorize_user! diff --git a/app/models/server.rb b/app/models/server.rb index 58c8305..9ae5f6f 100644 --- a/app/models/server.rb +++ b/app/models/server.rb @@ -4,18 +4,31 @@ class Server < ApplicationRecord enum :status, { stopped: 0, starting: 1, running: 2, failed: 3 } - validates :name, :port, presence: true + validates :name, presence: true validates :name, uniqueness: { scope: :user_id } - validates :port, uniqueness: true + validates :port, presence: true, uniqueness: true, numericality: { only_integer: true, greater_than_or_equal_to: 27016, less_than_or_equal_to: 27999 } validates :status, presence: true + before_validation :assign_port, if: -> { port.blank? } + scope :for_user, ->(user) { where(user_id: user.id) } scope :active, -> { where(status: [ :starting, :running ]) } after_destroy :cleanup_server + def self.next_available_port + (27016..27999).each do |port| + return port unless exists?(port: port) + end + nil + end + private + def assign_port + self.port = self.class.next_available_port + end + def cleanup_server L4dServer::SystemdManager.cleanup(self) L4dServer::Launcher.cleanup(self) diff --git a/app/views/servers/new.html.slim b/app/views/servers/new.html.slim index d47cc72..4b044b6 100644 --- a/app/views/servers/new.html.slim +++ b/app/views/servers/new.html.slim @@ -1,11 +1,6 @@ .server_form h2 Spawn New Server - - if @server_template - p - strong Template: - = @server_template.name - = form_with model: @server, local: true do |f| = hidden_field_tag :server_template_id, @server_template.id if @server_template - if @server.errors.any? @@ -15,13 +10,18 @@ - @server.errors.full_messages.each do |msg| li = msg + - unless @server_template + .form-group + = f.label :server_template_id, "Template" + = f.select :server_template_id, options_from_collection_for_select(@server_templates, :id, :name, @server.server_template_id), { prompt: "Select a template" }, class: "form-control", required: true + .form-group = f.label :name = f.text_field :name, placeholder: "e.g., server1" .form-group - = f.label :port - = f.number_field :port, placeholder: "e.g., 27015" + = f.label :port, "Port (optional, auto-assigned if blank)" + = f.number_field :port, placeholder: "Auto: 27016-27999", min: 27016, max: 27999 - if @server_template .template-preview