From c388e7c9e7dfaad2e06d32059a1fddd0058dc561 Mon Sep 17 00:00:00 2001 From: Jah Seng Lee Date: Sun, 31 Mar 2024 17:56:56 +0900 Subject: [PATCH 1/5] Create VisaInformation on the fly if it doesn't exist --- .../locations/citizenships_controller.rb | 12 ++--- .../visa_informations_controller.rb | 44 ++++++++++++++++--- app/lib/chat_gpt.rb | 5 +++ .../citizenships/create.turbo_stream.erb | 28 ++++++++---- .../_loading_visa_information.html.erb | 20 +++++++++ app/views/visa_informations/show.html.erb | 5 +-- config/routes.rb | 6 ++- 7 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 app/views/visa_informations/_loading_visa_information.html.erb diff --git a/app/controllers/locations/citizenships_controller.rb b/app/controllers/locations/citizenships_controller.rb index 58139e7..eb49a89 100644 --- a/app/controllers/locations/citizenships_controller.rb +++ b/app/controllers/locations/citizenships_controller.rb @@ -1,5 +1,5 @@ # Controller responsible for adding citizenships from the -# VisaInforation#show page. This differs from the CitizenshipsController +# VisaInformation#show page. This differs from the CitizenshipsController # which is used on the Profile#show page module Locations class CitizenshipsController < ApplicationController @@ -19,13 +19,9 @@ def create ) if @citizenship.save - @visa_information = ( - VisaInformation.find_by( - country: @location.country, - citizenship: @citizenship.country - ) - ) || ( - VisaInforation.generic(country: @location.country) + @visa_information = VisaInformation.find_by( + country: @location.country, + citizenship: @citizenship.country ) flash.now[:success_save_citizenship] = "Added citizenship!" \ diff --git a/app/controllers/visa_informations_controller.rb b/app/controllers/visa_informations_controller.rb index d5f8645..4e684b1 100644 --- a/app/controllers/visa_informations_controller.rb +++ b/app/controllers/visa_informations_controller.rb @@ -1,22 +1,52 @@ class VisaInformationsController < ApplicationController before_action :initialize_markdown_renderer - skip_before_action :authenticate_user!, only: [:show] + skip_before_action :authenticate_user!, only: [:show, :content] def show @location = Location.find(params[:location_id]) + end + + def content + @location = Location.find(params[:location_id]) - if current_user && current_user.citizenships.any? + if current_user.nil? || current_user.citizenship.nil? + @visa_information = VisaInformation.generic( + country: @location.country + ) + else + citizenship_country = current_user.citizenship.country @visa_information = VisaInformation.find_by( country: @location.country, # Assume only one citizenship for now - citizenship: current_user.citizenships.first.country + citizenship: citizenship_country ) + + # Couldn't find VisaInformation for the @location.country and the + # current_user.citizenship.country - create one instead + if @visa_information.nil? + @visa_information = VisaInformation.create!( + country: @location.country, + # Assume only one citizenship for now + citizenship: citizenship_country, + body: ChatGpt.generate_visa_info( + country: @location.country, + citizenship_country: citizenship_country + ) + ) + end end - if @visa_information.nil? - @visa_information = VisaInformation.generic( - country: @location.country - ) + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "location-visa-information", + partial: "visa_informations/location_visa_information", + locals: { + user: current_user, + visa_information: @visa_information + } + ) + end end end end diff --git a/app/lib/chat_gpt.rb b/app/lib/chat_gpt.rb index 53958ff..08724d5 100644 --- a/app/lib/chat_gpt.rb +++ b/app/lib/chat_gpt.rb @@ -66,6 +66,11 @@ def self.generate_generic_visa_info(country:) end def self.generate_visa_info(country:, citizenship_country:) + unless Rails.env.production? + return "Visa info. for citizenship: #{citizenship_country.name}," \ + " country: #{country.name}." + end + prompt = "Could you write me an informational article that explains" \ " the visa options for a digital nomad who is a" \ " #{citizenship_country.name} citizen visiting #{country.name}?" \ diff --git a/app/views/locations/citizenships/create.turbo_stream.erb b/app/views/locations/citizenships/create.turbo_stream.erb index b6390f4..0771049 100644 --- a/app/views/locations/citizenships/create.turbo_stream.erb +++ b/app/views/locations/citizenships/create.turbo_stream.erb @@ -2,11 +2,23 @@ "modal-new-citizenship" ) %> -<%= turbo_stream.replace( - "location-visa-information", - partial: "visa_informations/location_visa_information", - locals: { - user: @user, - visa_information: @visa_information - } -) %> +<%= + if @visa_information.nil? + turbo_stream.replace( + "location-visa-information", + partial: "visa_informations/loading_visa_information", + locals: { + location: @location + } + ) + else + turbo_stream.replace( + "location-visa-information", + partial: "visa_informations/location_visa_information", + locals: { + user: @user, + visa_information: @visa_information + } + ) + end +%> diff --git a/app/views/visa_informations/_loading_visa_information.html.erb b/app/views/visa_informations/_loading_visa_information.html.erb new file mode 100644 index 0000000..bbc3cbe --- /dev/null +++ b/app/views/visa_informations/_loading_visa_information.html.erb @@ -0,0 +1,20 @@ +<%= turbo_frame_tag( + "location-visa-information", + src: content_location_visa_information_path( + location: location, + format: :turbo_stream + ) +) do %> + <%= render partial: "shared/citizenship_alerts" %> + +
+
+ Loading... +
+ Finding visa information... +
+

+ This may take up to a minute +

+<% end %> + diff --git a/app/views/visa_informations/show.html.erb b/app/views/visa_informations/show.html.erb index e903eb7..4c9a18e 100644 --- a/app/views/visa_informations/show.html.erb +++ b/app/views/visa_informations/show.html.erb @@ -11,10 +11,9 @@ } %> - <%= render partial: "visa_informations/location_visa_information", + <%= render partial: "visa_informations/loading_visa_information", locals: { - user: current_user, - visa_information: @visa_information + location: @location } %> diff --git a/config/routes.rb b/config/routes.rb index 25a5d2e..c021490 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -33,7 +33,11 @@ resources :banner_images, only: [:create, :update] resources :countries, only: [:edit, :update] resources :reviews, only: [:index, :show, :new, :create, :edit, :update] - resource :visa_information, only: [:show] + resource :visa_information, only: [:show] do + collection do + get :content + end + end end resource :profile, only: [:show] do collection do From 4861743ab67b2e2302aafd8cde4f3a10c31ff9fa Mon Sep 17 00:00:00 2001 From: Jah Seng Lee Date: Tue, 2 Apr 2024 19:33:59 +0900 Subject: [PATCH 2/5] Users can log issues on visa information page --- app/controllers/issues_controller.rb | 50 +++++++++++++ .../visa_informations_controller.rb | 13 ++++ app/models/issue.rb | 73 +++++++++++++++++++ app/policies/issue_policy.rb | 5 ++ app/views/issues/_alert_error_create.html.erb | 5 ++ .../issues/_alert_success_create.html.erb | 4 + app/views/issues/create.turbo_stream.erb | 16 ++++ .../_report_issue_modal.html.erb | 49 +++++++++++++ app/views/visa_informations/show.html.erb | 32 ++++++-- config/routes.rb | 2 + db/migrate/20240402082443_create_issues.rb | 20 +++++ db/schema.rb | 16 +++- spec/features/location_visas_spec.rb | 49 +++++++++++++ 13 files changed, 328 insertions(+), 6 deletions(-) create mode 100644 app/controllers/issues_controller.rb create mode 100644 app/models/issue.rb create mode 100644 app/policies/issue_policy.rb create mode 100644 app/views/issues/_alert_error_create.html.erb create mode 100644 app/views/issues/_alert_success_create.html.erb create mode 100644 app/views/issues/create.turbo_stream.erb create mode 100644 app/views/visa_informations/_report_issue_modal.html.erb create mode 100644 db/migrate/20240402082443_create_issues.rb diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb new file mode 100644 index 0000000..96f6573 --- /dev/null +++ b/app/controllers/issues_controller.rb @@ -0,0 +1,50 @@ +class IssuesController < ApplicationController + def index + raise NotImplementedError, "TODO" + end + + def show + raise NotImplementedError, "TODO" + end + + def create + @issue = Issue.new(create_params) + + authorize(@issue) + + respond_to do |format| + format.turbo_stream do + unless @issue.save + # TODO create a issues/create.turbo_stream.erb which: + # * removes the modal + # * inserts an alert + # * can do this by making the existing alerts a turbo + # frame and refreshing that; OR + # * creating a new frame and just inserting + render turbo_stream: turbo_stream.append( + "modal-flash-error", + partial: "issues/alert_error_create" + ) + return + end + end + end + end + + def update + raise NotImplementedError, "TODO" + end + + private + + def create_params + params.require(:issue).permit( + :reporter_id, + :entity_id, + :entity_type, + :additional_information, + :issue_type, + :body + ) + end +end diff --git a/app/controllers/visa_informations_controller.rb b/app/controllers/visa_informations_controller.rb index 4e684b1..e75c30f 100644 --- a/app/controllers/visa_informations_controller.rb +++ b/app/controllers/visa_informations_controller.rb @@ -49,4 +49,17 @@ def content end end end + + def report_issue_modal + @location = Location.find(params[:location_id]) + + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.append( + "site-modals", + partial: "visa_informations/report_issue_modal" + ) + end + end + end end diff --git a/app/models/issue.rb b/app/models/issue.rb new file mode 100644 index 0000000..d8dccdd --- /dev/null +++ b/app/models/issue.rb @@ -0,0 +1,73 @@ +class Issue < ApplicationRecord + belongs_to :reporter, + foreign_key: :reporter_id, + optional: true, + class_name: "User" + + # It may seem like we're replicating string enums here, and it is. + # But for some reason, string enums aren't playing nice. + # enum issue_type: { other: "Other" } is actually saving it to the + # DB as "other", with the capitalised string doing... nothing. + # This contradicts the docs, so leaving for now... + MISSING_VISA_INFO = "Missing visa information", + INCORRECT_VISA_INFO = "Incorrect visa information", + ERROR_VISA_INFO = "Visa information is not loading/causing error", + OTHER = "Other" + ISSUE_TYPES = [ + MISSING_VISA_INFO, + INCORRECT_VISA_INFO, + ERROR_VISA_INFO, + OTHER, + ] + + validate :issue_type_exists + validate :issue_type_entity_match + validate :entity_exists + + def self.visa_issue_types + [ + MISSING_VISA_INFO, + INCORRECT_VISA_INFO, + ERROR_VISA_INFO, + OTHER + ] + end + + private + + def issue_type_exists + unless ISSUE_TYPES.include?(issue_type) + errors.add( + :issue_type, "must be declared in Issue::ISSUE_TYPES." + ) + end + end + + def issue_type_entity_match + if entity_type == "Country" && + !Issue.visa_issue_types.include?(issue_type) + errors.add( + :issue_type, + "must be in Issue.visa_issue_types if the entity_type is" \ + " 'Country'." + ) + end + end + + def entity_exists + return if entity_type.nil? + + if entity_id.nil? + errors.add(:entity_id, "can't be empty if entity_type is specified") + return + end + + if entity_type.constantize.find_by(id: entity_id).nil? + errors.add( + :entity_id, + "can't find entity with entity_type: #{entity_type}," \ + " id: #{entity_id}" + ) + end + end +end diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb new file mode 100644 index 0000000..1f2c5dc --- /dev/null +++ b/app/policies/issue_policy.rb @@ -0,0 +1,5 @@ +class IssuePolicy < ApplicationPolicy + def create? + record.reporter == user + end +end diff --git a/app/views/issues/_alert_error_create.html.erb b/app/views/issues/_alert_error_create.html.erb new file mode 100644 index 0000000..af8c04a --- /dev/null +++ b/app/views/issues/_alert_error_create.html.erb @@ -0,0 +1,5 @@ + diff --git a/app/views/issues/_alert_success_create.html.erb b/app/views/issues/_alert_success_create.html.erb new file mode 100644 index 0000000..35e753c --- /dev/null +++ b/app/views/issues/_alert_success_create.html.erb @@ -0,0 +1,4 @@ + diff --git a/app/views/issues/create.turbo_stream.erb b/app/views/issues/create.turbo_stream.erb new file mode 100644 index 0000000..426bf05 --- /dev/null +++ b/app/views/issues/create.turbo_stream.erb @@ -0,0 +1,16 @@ +<% + # TODO create a issues/create.turbo_stream.erb which: + # * inserts an alert + # * can do this by making the existing alerts a turbo + # frame and refreshing that; OR + # * creating a new frame and just inserting +%> + +<%= turbo_stream.remove( + "report-issue-modal" +) %> + +<%= turbo_stream.append( + "success-report-issue", + partial: "issues/alert_success_create" +) %> diff --git a/app/views/visa_informations/_report_issue_modal.html.erb b/app/views/visa_informations/_report_issue_modal.html.erb new file mode 100644 index 0000000..3cd24cb --- /dev/null +++ b/app/views/visa_informations/_report_issue_modal.html.erb @@ -0,0 +1,49 @@ +<%= turbo_frame_tag "report-issue-modal" do %> + +<% end %> diff --git a/app/views/visa_informations/show.html.erb b/app/views/visa_informations/show.html.erb index 4c9a18e..64607d7 100644 --- a/app/views/visa_informations/show.html.erb +++ b/app/views/visa_informations/show.html.erb @@ -5,15 +5,37 @@ %>
+ <%= turbo_frame_tag "success-report-issue" %> + <%= render partial: "locations/tabs", locals: { location: @location, } %> - <%= render partial: "visa_informations/loading_visa_information", - locals: { - location: @location - } - %> +
+
+ <%= render partial: "visa_informations/loading_visa_information", + locals: { + location: @location + } + %> +
+ +
+ <% if current_user.present? %> + <%= link_to "Report issue", + report_issue_modal_location_visa_information_path, + method: :get, + class: "btn btn-danger" + %> + <% else %> + <%= link_to "Report issue", + # HACK: non-turbo link so non-users get redirected to sign_in + profile_path, + class: "btn btn-danger" + %> + <% end %> +
+
diff --git a/config/routes.rb b/config/routes.rb index c021490..72eff58 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,6 +22,7 @@ end end #resource :choose_plan, only: [:show] + resources :issues, only: [:index, :show, :create, :update] resources :locations, only: [:show, :edit, :update, :destroy] do member do get :upload_banner_image_modal @@ -36,6 +37,7 @@ resource :visa_information, only: [:show] do collection do get :content + get :report_issue_modal end end end diff --git a/db/migrate/20240402082443_create_issues.rb b/db/migrate/20240402082443_create_issues.rb new file mode 100644 index 0000000..731ca02 --- /dev/null +++ b/db/migrate/20240402082443_create_issues.rb @@ -0,0 +1,20 @@ +class CreateIssues < ActiveRecord::Migration[7.0] + def change + create_table :issues do |t| + t.text :issue_type, null: false + t.text :body + t.jsonb :additional_information # i.e. user's citizenship + + t.bigint :entity_id + t.text :entity_type # i.e. "Location" + t.boolean :resolved, null: false, default: true + + t.references :reporter, + null: true, + foreign_key: { to_table: :users }, + index: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 940b17f..e48d61e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_03_26_073845) do +ActiveRecord::Schema[7.0].define(version: 2024_04_02_082443) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -72,6 +72,19 @@ t.index ["region_id"], name: "index_countries_on_region_id" end + create_table "issues", force: :cascade do |t| + t.text "issue_type", null: false + t.text "body" + t.jsonb "additional_information" + t.bigint "entity_id" + t.text "entity_type" + t.boolean "resolved", default: true, null: false + t.bigint "reporter_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["reporter_id"], name: "index_issues_on_reporter_id" + end + create_table "locations", force: :cascade do |t| t.text "name", null: false t.text "name_utf8", null: false @@ -180,5 +193,6 @@ add_foreign_key "banner_images", "locations" add_foreign_key "channel_messages", "channel_messages", column: "reply_to_id" + add_foreign_key "issues", "users", column: "reporter_id" add_foreign_key "visa_informations", "countries", column: "citizenship_id" end diff --git a/spec/features/location_visas_spec.rb b/spec/features/location_visas_spec.rb index de699f3..80217a5 100644 --- a/spec/features/location_visas_spec.rb +++ b/spec/features/location_visas_spec.rb @@ -71,6 +71,16 @@ expect(page).to have_current_path(new_user_registration_path) end end + + context "clicking on the link to 'Report issue'" do + before do + click_link "Report issue" + end + + it "takes them to the sign up page" do + expect(page).to have_current_path(new_user_registration_path) + end + end end end @@ -129,6 +139,45 @@ " citizenship." end end + + context "clicking on the link to 'Report issue'" do + before do + click_link "Report issue" + end + + it "opens a modal to report an issue" do + within ".modal" do + expect(page).to have_content "Report issue" + end + end + + context "filling out the form and submitting" do + before do + select "Incorrect visa information", from: + "issue_issue_type" + fill_in "issue_body", with: + "I'm the US president. I can travel anywhere" + + click_button "Report" + end + + it "logs an issue" do + expect(page).to have_content "Thanks for reporting the" \ + " issue. Our team will look into it ASAP." + + sign_out :user + + # Sign in as user + admin = create(:user, admin: true) + sign_in user + visit root_path + + click_link "Issues" + + expect(page).to have_content "Incorrect visa information" + end + end + end end end end From e4632abb43060d3a39b61f3e343d02c09041ae1b Mon Sep 17 00:00:00 2001 From: Jah Seng Lee Date: Thu, 4 Apr 2024 17:06:27 +0900 Subject: [PATCH 3/5] Admin's can resolve issues --- app/controllers/issues_controller.rb | 32 +++++---- app/helpers/issues_helper.rb | 23 +++++++ app/models/issue.rb | 20 +++++- app/policies/issue_policy.rb | 8 +++ .../issues/_alert_success_resolve.html.erb | 4 ++ app/views/issues/index.html.erb | 67 +++++++++++++++++++ app/views/layouts/_navbar.html.erb | 19 +++++- .../_report_issue_modal.html.erb | 4 +- config/routes.rb | 2 +- db/migrate/20240402082443_create_issues.rb | 2 +- db/schema.rb | 3 +- spec/features/location_visas_spec.rb | 2 +- 12 files changed, 164 insertions(+), 22 deletions(-) create mode 100644 app/helpers/issues_helper.rb create mode 100644 app/views/issues/_alert_success_resolve.html.erb create mode 100644 app/views/issues/index.html.erb diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 96f6573..ab9b7c4 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -1,26 +1,17 @@ class IssuesController < ApplicationController def index - raise NotImplementedError, "TODO" - end + authorize(Issue) - def show - raise NotImplementedError, "TODO" + @issues = Issue.unresolved end def create @issue = Issue.new(create_params) - authorize(@issue) respond_to do |format| format.turbo_stream do unless @issue.save - # TODO create a issues/create.turbo_stream.erb which: - # * removes the modal - # * inserts an alert - # * can do this by making the existing alerts a turbo - # frame and refreshing that; OR - # * creating a new frame and just inserting render turbo_stream: turbo_stream.append( "modal-flash-error", partial: "issues/alert_error_create" @@ -31,8 +22,23 @@ def create end end - def update - raise NotImplementedError, "TODO" + def update # a.k.a. "Resolve" + # Weird update - just resolves the issue. + # The policy _should_ check the user is admin. Assume that no admins + # are trying to maliciously resolve all issues + @issue = Issue.find(params[:id]) + authorize(@issue) + + @issue.update!(resolved: true) + + respond_to do |format| + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "issue-#{@issue.id}", + partial: "issues/alert_success_resolve" + ) + end + end end private diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb new file mode 100644 index 0000000..89a7082 --- /dev/null +++ b/app/helpers/issues_helper.rb @@ -0,0 +1,23 @@ +module IssuesHelper + def helper_issue_entity_link(issue:) + return "No entity" if issue.entity.nil? + + if issue.entity_type.constantize == Country + # We don't have a Country page, so link to the Visa page + # found in additional information Location#name + location = Location.find_by( + name: issue.additional_information["location"] + ) + + return link_to( + location_visa_information_path( + location_id: location.id + ), + target: "_blank" + ) do + "\n" \ + "Reported on visa page for #{location.name_utf8}".html_safe + end + end + end +end diff --git a/app/models/issue.rb b/app/models/issue.rb index d8dccdd..6b44f96 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -9,9 +9,9 @@ class Issue < ApplicationRecord # enum issue_type: { other: "Other" } is actually saving it to the # DB as "other", with the capitalised string doing... nothing. # This contradicts the docs, so leaving for now... - MISSING_VISA_INFO = "Missing visa information", - INCORRECT_VISA_INFO = "Incorrect visa information", - ERROR_VISA_INFO = "Visa information is not loading/causing error", + MISSING_VISA_INFO = "Missing visa information" + INCORRECT_VISA_INFO = "Incorrect visa information" + ERROR_VISA_INFO = "Visa information is not loading/causing error" OTHER = "Other" ISSUE_TYPES = [ MISSING_VISA_INFO, @@ -24,6 +24,8 @@ class Issue < ApplicationRecord validate :issue_type_entity_match validate :entity_exists + scope :unresolved, -> { where(resolved: false) } + def self.visa_issue_types [ MISSING_VISA_INFO, @@ -33,6 +35,18 @@ def self.visa_issue_types ] end + def additional_information + JSON.parse(self[:additional_information]) + end + + def entity + return nil if entity_type.nil? || entity_id.nil? + + if entity_type.constantize == Country + "Country: #{Country.find(entity_id).name}" + end + end + private def issue_type_exists diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb index 1f2c5dc..3152153 100644 --- a/app/policies/issue_policy.rb +++ b/app/policies/issue_policy.rb @@ -1,5 +1,13 @@ class IssuePolicy < ApplicationPolicy + def index? + user.admin? + end + def create? record.reporter == user end + + def update? + index? + end end diff --git a/app/views/issues/_alert_success_resolve.html.erb b/app/views/issues/_alert_success_resolve.html.erb new file mode 100644 index 0000000..622f3af --- /dev/null +++ b/app/views/issues/_alert_success_resolve.html.erb @@ -0,0 +1,4 @@ + diff --git a/app/views/issues/index.html.erb b/app/views/issues/index.html.erb new file mode 100644 index 0000000..a5d529a --- /dev/null +++ b/app/views/issues/index.html.erb @@ -0,0 +1,67 @@ +
+

+ Issues +

+ + + <% if @issues.any? %> +
+
+ Type +
+
+ Descrpition +
+
+ Entity +
+
+ Link +
+
+ +
+
+ + <% @issues.each do |issue| %> + <%= turbo_frame_tag "issue-#{issue.id}" do %> +
+
+
+
+ <%= issue.issue_type %> +
+
+ <%= issue.body || "No description" %> +
+
+ <%= issue.entity %> +
+
+ <%= helper_issue_entity_link(issue: issue) %> +
+
+ <%= button_to( + issue_path(issue), + method: :put, + class: "btn btn-success" + ) do %> + + <% end %> +
+
+
+
+ <% end %> + <% end %> + <% else %> + No issues at this time + <% end %> + + <% + set_meta_tags( + index: false, + follow: false + ) + %> +
diff --git a/app/views/layouts/_navbar.html.erb b/app/views/layouts/_navbar.html.erb index 4e9eb6a..8400fc0 100644 --- a/app/views/layouts/_navbar.html.erb +++ b/app/views/layouts/_navbar.html.erb @@ -34,7 +34,7 @@ + + <% if current_user&.admin? %> + + <% end %>