diff --git a/app/controllers/overlays_controller.rb b/app/controllers/overlays_controller.rb index f5ffb91..d31b5fc 100644 --- a/app/controllers/overlays_controller.rb +++ b/app/controllers/overlays_controller.rb @@ -1,46 +1,77 @@ class OverlaysController < ApplicationController before_action :set_overlay, only: [ :destroy ] - before_action :set_server_template, only: [ :create ] + before_action :set_server_template, only: [ :create, :destroy ] def index @system_overlays = Overlay.system_overlays @custom_overlays = current_user.overlays.custom_overlays.order(:name) end + def new + @overlay = current_user.overlays.build + end + def create - @server_template = current_user.server_templates.find(params[:server_template_id]) - @overlay = Overlay.find(params[:overlay_id]) + if @server_template.present? + # Attach existing overlay to a template + @overlay = Overlay.find(params[:overlay_id]) - position = @server_template.template_overlays.maximum(:position).to_i + 1 - @template_overlay = @server_template.template_overlays.build(overlay_id: @overlay.id, position: position) + position = @server_template.template_overlays.maximum(:position).to_i + 1 + @template_overlay = @server_template.template_overlays.build(overlay_id: @overlay.id, position: position) - if @template_overlay.save - Activity.log(current_user, "added_overlay", "ServerTemplate", @server_template.id, { overlay: @overlay.name }) - redirect_to @server_template, notice: "Overlay added successfully!" + if @template_overlay.save + Activity.log(current_user, "added_overlay", "ServerTemplate", @server_template.id, { overlay: @overlay.name }) + redirect_to @server_template, notice: "Overlay added successfully!" + else + redirect_to @server_template, alert: "Failed to add overlay" + end else - redirect_to @server_template, alert: "Failed to add overlay" + # Create a new custom overlay for the current user + @overlay = current_user.overlays.build(overlay_params.merge(overlay_type: "custom")) + + if @overlay.save + Activity.log(current_user, "created_overlay", "Overlay", @overlay.id, { name: @overlay.name, slug: @overlay.slug }) + redirect_to overlays_path, notice: "Overlay created" + else + render :new, status: :unprocessable_entity + end end end def destroy - authorize_user! - server_template = @overlay.server_templates.find(params[:server_template_id]) - @overlay.template_overlays.where(server_template_id: server_template.id).destroy_all - Activity.log(current_user, "removed_overlay", "ServerTemplate", server_template.id, { overlay: @overlay.name }) - redirect_to server_template, notice: "Overlay removed successfully!" + if @server_template.present? + authorize_user_for_template_overlay! + @overlay.template_overlays.where(server_template_id: @server_template.id).destroy_all + Activity.log(current_user, "removed_overlay", "ServerTemplate", @server_template.id, { overlay: @overlay.name }) + redirect_to @server_template, notice: "Overlay removed successfully!" + else + authorize_owner! + name = @overlay.name + @overlay.destroy + redirect_to overlays_path, notice: "Overlay '#{name}' deleted" + end end private def set_overlay - @overlay = Overlay.find(params[:id]) + @overlay = Overlay.find(params[:id]) if params[:id].present? end def set_server_template + return unless params[:server_template_id].present? @server_template = current_user.server_templates.find(params[:server_template_id]) end - def authorize_user! + def overlay_params + params.require(:overlay).permit(:name, :slug) + end + + def authorize_user_for_template_overlay! redirect_to dashboard_path, alert: "Not authorized" unless @overlay.user_id.nil? || @overlay.user_id == current_user.id end + + def authorize_owner! + redirect_to overlays_path, alert: "Not authorized" unless @overlay.user_id == current_user.id + end end diff --git a/app/models/config_option.rb b/app/models/config_option.rb index bebda14..16ccfbd 100644 --- a/app/models/config_option.rb +++ b/app/models/config_option.rb @@ -1,6 +1,6 @@ class ConfigOption < ApplicationRecord belongs_to :server_template - validates :config_key, :config_value, presence: true + validates :config_key, presence: true validates :config_key, uniqueness: { scope: :server_template_id } end diff --git a/app/models/overlay.rb b/app/models/overlay.rb index de6542e..bb299d4 100644 --- a/app/models/overlay.rb +++ b/app/models/overlay.rb @@ -3,11 +3,37 @@ class Overlay < ApplicationRecord has_many :template_overlays, dependent: :destroy has_many :server_templates, through: :template_overlays - validates :name, :overlay_type, :path, presence: true + validates :name, :overlay_type, :slug, presence: true validates :overlay_type, inclusion: { in: %w[system custom] } validates :name, uniqueness: { scope: :user_id, message: "must be unique per user" } + validate :slug_is_single_directory + + before_validation :normalize_slug scope :system_overlays, -> { where(overlay_type: "system").where(user_id: nil) } scope :custom_overlays, -> { where(overlay_type: "custom") } scope :for_user, ->(user) { where("user_id IS NULL OR user_id = ?", user.id) } + + private + + def normalize_slug + return if slug.blank? && name.blank? + + # Use provided slug or derive from name + source = slug.presence || name + self.slug = source.to_s.strip + .downcase + .gsub(%r{[^\w\-.]}, "_") # Replace non-word chars (except - and .) with underscore + .gsub(%r{_+}, "_") # Collapse multiple underscores + .sub(%r{^_+}, "") # Strip leading underscores + .sub(%r{_+$}, "") # Strip trailing underscores + end + + def slug_is_single_directory + return if slug.blank? + + if slug.match?(%r{[\\/]}) + errors.add(:slug, "must be a single directory name (no slashes)") + end + end end diff --git a/app/models/startup_param.rb b/app/models/startup_param.rb index a30e065..bf223bd 100644 --- a/app/models/startup_param.rb +++ b/app/models/startup_param.rb @@ -1,6 +1,6 @@ class StartupParam < ApplicationRecord belongs_to :server_template - validates :param_key, :param_value, presence: true + validates :param_key, presence: true validates :param_key, uniqueness: { scope: :server_template_id } end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000..4bbdc0f --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,44 @@ + + +
+