# rubocop:disable Metrics/BlockLength module Vapid module Controllers # Admin routes module AdminController extend Sinatra::Extension # Custom form builder for records class RecordFormBuilder < Padrino::Helpers::FormBuilder::AbstractFormBuilder def vp_field(name, type, value = "") @directive = Directives[type] @name = name @value = @directive.new(name).send :deserialize_input, value label(name) + template.content_tag(:div) do form_field + preview + destroy end end private def form_field @directive.form_field(template, "record[content][#{@name}]", @value) end def preview return unless @value.present? && @directive.previewable? template.content_tag(:div, class: "preview") do @directive.new(@name).render(@value)[:inner_html].html_safe end end def destroy return unless @value.present? && @directive.destroyable? template.content_tag(:div, class: "ui checkbox destroy") do template.check_box_tag("_destroy[#{@name}]") + "Delete #{@name}" end end end # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, MethodLength def self.registered(app) # rubocop:disable Lint/NestedMethodDefinition app.helpers do def installed! if ActiveRecord::Migrator.current_version.zero? || !Models::User.any? redirect "/admin/install" unless admin_action == "install" false else redirect "/admin" if admin_action == "install" true end end def authenticated! if !current_user redirect "/admin/login" unless %w(login logout).include?(admin_action) false else true end end def admin_action request.path_info.split("/")[2] end def render_admin_template(template) render_view template, layout: :admin end def render_auth_template(template) render_view template, layout: :admin_form end def admin_partial(template, options = {}, &block) partial "admin/#{template}", options, &block end def record_form_for(name, *args, &block) options = args.extract_options! args << options.merge(builder: RecordFormBuilder) form_for(name, *args, &block) end def group_or_records_path(group) path = if group.records.empty? "/new" elsif group.repeating? "" else "/#{group.records.first.id}/edit" end "/admin/groups/#{group.id}/records#{path}" end def flash_class(level) case level when :success then "ui positive message" when :error then "ui negative message" when :notice then "ui warning message" end end def current_user @current_user ||= Vapid::Models::User.find_by(id: session[:user_id]) end def all_groups Models::Group.with_fields end def current_group Models::Group.find_by!(id: params[:group_id]) if params[:group_id] end def current_record Models::Record.joins(:group).find_by(id: params[:id]) if params[:id] end def livereload FileUtils.touch(settings.reload) if settings.development? end def run_builder CLI.new.invoke(:build) end end # rubocop:enable Lint/NestedMethodDefinition app.before("/admin/?*") do @groups = all_groups if installed! && authenticated! end app.namespace "/admin/?" do # TODO: Namespace before filters are currently broken on Sinatra 2.0 # before do # @groups = all_groups if installed! && authenticated! # @group = current_group # @record = current_record # end get do render_admin_template "admin/overview/index" end get "/login/?" do @user = Models::User.new render_auth_template "admin/login" end post "/login/?" do user = Models::User.authenticate(params[:vapid_models_user][:email], params[:vapid_models_user][:password]) if user session[:user_id] = user.id redirect "/admin" else flash[:error] = "Could not log in" redirect back end end get "/logout/?" do session.delete(:user_id) flash[:success] = "Successfully logged out" redirect "/admin/login" end get "/install/?" do @code = Settings.install_code render_auth_template "/admin/install" end post "/install/?" do Models.migrate! user = Models::User.new(email: params[:email], password: params[:password]) @code = Settings.install_code # TODO: Should display contextually-relevant error message if (@code.nil? || @code.casecmp(params[:code]) == 0) && user.save run_builder session[:user_id] = user.id flash[:success] = "Successfully created admin account" redirect "/admin" else flash.now[:error] = "Could not create admin account" render_auth_template "/admin/install" end end get "/build/?" do run_builder flash[:success] = "Site build complete" redirect "/admin" end get "/groups/:group_id/records/?" do @group = current_group @user = Vapid::Models::User.new render_admin_template "admin/records/index" end post "/groups/:group_id/records/?" do @group = current_group @record = @group.records.build(params[:record]) # TODO: Externalize this into a function (see update method below) params[:record]["content"].each do |key, val| content_type = current_group.fields[key] @record.content[key] = Directives[content_type].serialize_input(val) end if @record.save flash[:success] = "Record created" livereload else flash[:error] = "Problem creating record" end redirect group_or_records_path(@group) end get "/groups/:group_id/records/new/?" do @group = current_group @record = @group.records.build render_admin_template "admin/records/new" end post "/groups/:group_id/records/:id/?" do @group = current_group @record = current_record # TODO: Externalize this into a function (see create method above) params[:record]["content"].each do |key, val| # if val.is_a?(Hash) && val[:tempfile] # FileUtils.mkdir_p(settings.project_uploads) # File.open File.join(settings.project_uploads, val[:filename]), "wb" do |file| # file.write val[:tempfile].read # end # val = "/uploads/#{val[:filename]}" # end content_type = current_group.fields[key] @record.content[key] = Directives[content_type].serialize_input(val) end params[:_destroy] && params[:_destroy].each do |key, _val| @record.content[key] = nil end if @record.save flash[:success] = "Record updated" livereload else flash.now[:error] = "Problem updating record" end redirect group_or_records_path(@group) end delete "/groups/:group_id/records/:id/?" do @group = current_group @record = current_record if @record.destroy flash[:success] = "Record deleted" livereload else flash[:error] = "Problem deleting record" end redirect group_or_records_path(@group) end get "/groups/:group_id/records/:id/edit/?" do @group = current_group @record = current_record render_admin_template "admin/records/edit" end end end # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, MethodLength end end end