-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from jahseng-lee/feature/visa-information-v2
Visa Information v2
- Loading branch information
Showing
26 changed files
with
723 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.edit-visa-form { | ||
height: 100%; | ||
|
||
position: sticky; | ||
top: 5rem; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
class IssuesController < ApplicationController | ||
def index | ||
authorize(Issue) | ||
|
||
@issues = Issue.unresolved | ||
end | ||
|
||
def create | ||
@issue = Issue.new(create_params) | ||
authorize(@issue) | ||
|
||
respond_to do |format| | ||
format.turbo_stream do | ||
unless @issue.save | ||
render turbo_stream: turbo_stream.append( | ||
"modal-flash-error", | ||
partial: "issues/alert_error_create" | ||
) | ||
return | ||
end | ||
end | ||
end | ||
end | ||
|
||
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 | ||
|
||
def create_params | ||
params.require(:issue).permit( | ||
:reporter_id, | ||
:entity_id, | ||
:entity_type, | ||
:additional_information, | ||
:issue_type, | ||
:body | ||
) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,115 @@ | ||
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 | ||
|
||
if current_user && current_user.citizenships.any? | ||
@visa_information = VisaInformation.find_by( | ||
country: @location.country, | ||
# Assume only one citizenship for now | ||
citizenship: current_user.citizenships.first.country | ||
def edit | ||
@location = Location.find(params[:location_id]) | ||
@visa_information = params[:id].present? ? ( | ||
VisaInformation.find_by(id: params[:id]) | ||
) : ( | ||
VisaInformation.generic(country: @location.country) | ||
) | ||
@visa_informations = VisaInformation | ||
.includes(:citizenship) | ||
.where( | ||
country: @location.country | ||
) | ||
.order("countries.name") | ||
end | ||
|
||
def update | ||
@location = Location.find(params[:location_id]) | ||
@visa_information = VisaInformation.find(params[:id]) | ||
|
||
@visa_information.assign_attributes( | ||
body: update_params[:body] | ||
) | ||
|
||
if @visa_information.save | ||
flash.now[:success_update_visa] = "Updated visa info." | ||
else | ||
flash.now[:error_update_visa] = "Couldn't update visa info." \ | ||
" Please try again." | ||
end | ||
|
||
respond_to do |format| | ||
format.turbo_stream do | ||
render turbo_stream: turbo_stream.replace( | ||
"update-visa-info-form", | ||
partial: "visa_informations/update_visa_info_form", | ||
locals: { | ||
location: @location, | ||
visa_information: @visa_information | ||
} | ||
) | ||
end | ||
end | ||
end | ||
|
||
def content | ||
@location = Location.find(params[:location_id]) | ||
|
||
if @visa_information.nil? | ||
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: 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 | ||
|
||
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 | ||
|
||
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 | ||
|
||
private | ||
|
||
def update_params | ||
params.require(:visa_information).permit(:body) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
"<i class='bi bi-box-arrow-up-right'></i>\n" \ | ||
"Reported on visa page for #{location.name_utf8}".html_safe | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module VisaInformationsHelper | ||
def helper_edit_visa_info_heading(location:, visa_information:) | ||
heading = "Editing visa information for #{location.country.name}" | ||
if visa_information.citizenship.present? | ||
heading << " for citizens of #{visa_information.citizenship.name}" | ||
end | ||
|
||
heading | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
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 | ||
|
||
scope :unresolved, -> { where(resolved: false) } | ||
|
||
def self.visa_issue_types | ||
[ | ||
MISSING_VISA_INFO, | ||
INCORRECT_VISA_INFO, | ||
ERROR_VISA_INFO, | ||
OTHER | ||
] | ||
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 | ||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
class IssuePolicy < ApplicationPolicy | ||
def index? | ||
user.admin? | ||
end | ||
|
||
def create? | ||
record.reporter == user | ||
end | ||
|
||
def update? | ||
index? | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<div class="alert alert-danger alert-dismissible fade show" role="alert"> | ||
Oops, looks like something went wrong on our end. We're looking into it | ||
ASAP. | ||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<div class="alert alert-success alert-dismissible fade show" role="alert"> | ||
Thanks for reporting the issue. Our team will look into it ASAP. | ||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<div class="alert alert-success alert-dismissible fade show" role="alert"> | ||
Issue resolved | ||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> | ||
</div> |
Oops, something went wrong.