Allow admins to enable and disable holidays (#283)
* DEV: Add backend functionality to enable/disable holidays This will add two backend endpoints, one to disable holidays and another to enable holidays. I also introduced a new `Holiday` service that is responsible for getting the holidays and attaching a new `disabled` attribute to the holidays. The `#index` action has been updated to use this new service, so it will return this new `disabled` attribute. * DEV: Only add enabled holidays to the calendar I updated this job so that it will use the new `Holiday` service, which will return the holidays like before but with a new `disabled` field, which this job will use to only add enabled holidays to the calendar. * FEATURE: Allow admins to disable/enable holidays The main thing I added here is a new component `admin-holiday-list-item` that is responsible for displaying a holiday, and an enable or disable button and the corresponding functionality.
This commit is contained in:
parent
e771e7c01b
commit
d31e07c01c
|
|
@ -1,19 +1,41 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "holidays"
|
|
||||||
|
|
||||||
module Admin::DiscourseCalendar
|
module Admin::DiscourseCalendar
|
||||||
class AdminHolidaysController < AdminDiscourseCalendarController
|
class AdminHolidaysController < AdminDiscourseCalendarController
|
||||||
def index
|
def index
|
||||||
region_code = params[:region_code]
|
region_code = params[:region_code]
|
||||||
|
|
||||||
begin
|
begin
|
||||||
holidays = Holidays.year_holidays([region_code], Time.current.beginning_of_year)
|
holidays = DiscourseCalendar::Holiday.find_holidays_for(region_code: region_code)
|
||||||
rescue Holidays::InvalidRegion
|
rescue Holidays::InvalidRegion
|
||||||
return render_json_error(I18n.t("system_messages.discourse_calendar_holiday_region_invalid"), 422)
|
return render_json_error(I18n.t("system_messages.discourse_calendar_holiday_region_invalid"), 422)
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: { region_code: region_code, holidays: holidays }
|
render json: { region_code: region_code, holidays: holidays }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def disable
|
||||||
|
DiscourseCalendar::DisabledHoliday.create!(disabled_holiday_params)
|
||||||
|
CalendarEvent.destroy_by(
|
||||||
|
description: disabled_holiday_params[:holiday_name],
|
||||||
|
region: disabled_holiday_params[:region_code]
|
||||||
|
)
|
||||||
|
|
||||||
|
render json: success_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable
|
||||||
|
if DiscourseCalendar::DisabledHoliday.destroy_by(disabled_holiday_params).present?
|
||||||
|
render json: success_json
|
||||||
|
else
|
||||||
|
render_json_error(I18n.t("system_messages.discourse_calendar_enable_holiday_failed"), 422)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def disabled_holiday_params
|
||||||
|
params.require(:disabled_holiday).permit(:holiday_name, :region_code)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module DiscourseCalendar
|
||||||
|
class DisabledHoliday < ActiveRecord::Base
|
||||||
|
validates :holiday_name, presence: true
|
||||||
|
validates :region_code, presence: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: discourse_calendar_disabled_holidays
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# holiday_name :string not null
|
||||||
|
# region_code :string not null
|
||||||
|
# disabled :boolean default(TRUE), not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_disabled_holidays_on_holiday_name_and_region_code (holiday_name,region_code)
|
||||||
|
#
|
||||||
|
|
@ -371,3 +371,21 @@ module DiscoursePostEvent
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: discourse_post_event_events
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# status :integer default(0), not null
|
||||||
|
# original_starts_at :datetime not null
|
||||||
|
# original_ends_at :datetime
|
||||||
|
# deleted_at :datetime
|
||||||
|
# raw_invitees :string is an Array
|
||||||
|
# name :string
|
||||||
|
# url :string(1000)
|
||||||
|
# custom_fields :jsonb not null
|
||||||
|
# reminders :string
|
||||||
|
# recurrence :string
|
||||||
|
# timezone :string
|
||||||
|
#
|
||||||
|
|
|
||||||
|
|
@ -69,3 +69,20 @@ module DiscoursePostEvent
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: discourse_post_event_invitees
|
||||||
|
#
|
||||||
|
# id :bigint not null, primary key
|
||||||
|
# post_id :integer not null
|
||||||
|
# user_id :integer not null
|
||||||
|
# status :integer
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# notified :boolean default(FALSE), not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# discourse_post_event_invitees_post_id_user_id_idx (post_id,user_id) UNIQUE
|
||||||
|
#
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "holidays"
|
||||||
|
|
||||||
|
module DiscourseCalendar
|
||||||
|
class Holiday
|
||||||
|
def self.find_holidays_for(
|
||||||
|
region_code:,
|
||||||
|
start_date: Date.current.beginning_of_year,
|
||||||
|
end_date: Date.current.end_of_year,
|
||||||
|
show_holiday_observed_on_dates: false)
|
||||||
|
|
||||||
|
holidays = Holidays.between(
|
||||||
|
start_date,
|
||||||
|
end_date,
|
||||||
|
[region_code],
|
||||||
|
show_holiday_observed_on_dates ? :observed : [])
|
||||||
|
|
||||||
|
holidays.map do |holiday|
|
||||||
|
holiday[:disabled] = DiscourseCalendar::DisabledHoliday
|
||||||
|
.where(region_code: region_code)
|
||||||
|
.exists?(holiday_name: holiday[:name])
|
||||||
|
end
|
||||||
|
|
||||||
|
holidays
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
import Component from "@ember/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
tagName: "tr",
|
||||||
|
classNameBindings: ["isHolidayDisabled:disabled"],
|
||||||
|
loading: false,
|
||||||
|
isHolidayDisabled: false,
|
||||||
|
|
||||||
|
@action
|
||||||
|
disableHoliday(holiday, region_code) {
|
||||||
|
if (this.loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set("loading", true);
|
||||||
|
|
||||||
|
return ajax({
|
||||||
|
url: `/admin/discourse-calendar/holidays/disable`,
|
||||||
|
type: "POST",
|
||||||
|
data: { disabled_holiday: { holiday_name: holiday.name, region_code } },
|
||||||
|
})
|
||||||
|
.then(() => this.set("isHolidayDisabled", true))
|
||||||
|
.catch(popupAjaxError)
|
||||||
|
.finally(() => this.set("loading", false));
|
||||||
|
},
|
||||||
|
|
||||||
|
@action
|
||||||
|
enableHoliday(holiday, region_code) {
|
||||||
|
if (this.loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set("loading", true);
|
||||||
|
|
||||||
|
return ajax({
|
||||||
|
url: `/admin/discourse-calendar/holidays/enable`,
|
||||||
|
type: "DELETE",
|
||||||
|
data: { disabled_holiday: { holiday_name: holiday.name, region_code } },
|
||||||
|
})
|
||||||
|
.then(() => this.set("isHolidayDisabled", false))
|
||||||
|
.catch(popupAjaxError)
|
||||||
|
.finally(() => this.set("loading", false));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -1,12 +1,23 @@
|
||||||
<h3>{{i18n "discourse_calendar.holidays"}}</h3>
|
<h3>
|
||||||
|
{{i18n "discourse_calendar.holidays.header_title"}}
|
||||||
|
</h3>
|
||||||
|
|
||||||
{{region-input
|
{{region-input
|
||||||
value=this.selectedRegion
|
value=this.selectedRegion
|
||||||
onChange=(action "getHolidays")
|
onChange=(action "getHolidays")
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
<p class="desc">
|
||||||
|
{{i18n "discourse_calendar.holidays.pick_region_description"}}
|
||||||
|
<br><br>
|
||||||
|
{{i18n "discourse_calendar.holidays.disabled_holidays_description"}}
|
||||||
|
</p>
|
||||||
|
|
||||||
{{conditional-loading-spinner condition=loading}}
|
{{conditional-loading-spinner condition=loading}}
|
||||||
|
|
||||||
{{#if model.holidays}}
|
{{#if model.holidays}}
|
||||||
{{admin-holidays-list holidays=model.holidays}}
|
{{admin-holidays-list
|
||||||
|
holidays=model.holidays
|
||||||
|
region_code=this.selectedRegion
|
||||||
|
}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
<td>{{holiday.date}}</td>
|
||||||
|
<td>{{holiday.name}}</td>
|
||||||
|
<td>
|
||||||
|
{{#if isHolidayDisabled}}
|
||||||
|
{{d-button
|
||||||
|
action=(action "enableHoliday" holiday region_code)
|
||||||
|
label="discourse_calendar.enable_holiday"
|
||||||
|
}}
|
||||||
|
{{else}}
|
||||||
|
{{d-button
|
||||||
|
action=(action "disableHoliday" holiday region_code)
|
||||||
|
label="discourse_calendar.disable_holiday"
|
||||||
|
}}
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
|
@ -2,16 +2,17 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{i18n "discourse_calendar.date"}}</td>
|
<td>{{i18n "discourse_calendar.date"}}</td>
|
||||||
<td>{{i18n "discourse_calendar.holiday"}}</td>
|
<td colspan="2">{{i18n "discourse_calendar.holiday"}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#each @holidays as |holiday|}}
|
{{#each @holidays as |holiday|}}
|
||||||
<tr>
|
{{admin-holidays-list-item
|
||||||
<td>{{holiday.date}}</td>
|
holiday=holiday
|
||||||
<td>{{holiday.name}}</td>
|
isHolidayDisabled=holiday.disabled
|
||||||
</tr>
|
region_code=region_code
|
||||||
|
}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
.region-input {
|
.region-input {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disabled td {
|
||||||
|
background-color: var(--primary-very-low);
|
||||||
|
color: var(--primary-medium);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,13 @@ en:
|
||||||
discourse_calendar:
|
discourse_calendar:
|
||||||
invite_user_notification: "%{username} invited you to: %{description}"
|
invite_user_notification: "%{username} invited you to: %{description}"
|
||||||
on_holiday: "On Holiday"
|
on_holiday: "On Holiday"
|
||||||
|
disable_holiday: "Disable"
|
||||||
|
enable_holiday: "Enable"
|
||||||
holiday: "Holiday"
|
holiday: "Holiday"
|
||||||
holidays: "Holidays"
|
holidays:
|
||||||
|
header_title: "Holidays"
|
||||||
|
pick_region_description: "Pick a region to see the holidays for that region."
|
||||||
|
disabled_holidays_description: "Disabled holidays will be excluded from the staff holiday calendar."
|
||||||
date: "Date"
|
date: "Date"
|
||||||
add_to_calendar: "Add to Google Calendar"
|
add_to_calendar: "Add to Google Calendar"
|
||||||
region:
|
region:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ en:
|
||||||
title: Event started
|
title: Event started
|
||||||
system_messages:
|
system_messages:
|
||||||
discourse_calendar_holiday_region_invalid: "The holiday region you provided does not exist."
|
discourse_calendar_holiday_region_invalid: "The holiday region you provided does not exist."
|
||||||
|
discourse_calendar_enable_holiday_failed: "This holiday could not be enabled, it's already enabled or it's not disabled."
|
||||||
discourse_post_event_bulk_invite_succeeded:
|
discourse_post_event_bulk_invite_succeeded:
|
||||||
title: "Event - Bulk Invite Succeeded"
|
title: "Event - Bulk Invite Succeeded"
|
||||||
subject_template: "Bulk invite processed successfully"
|
subject_template: "Bulk invite processed successfully"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class CreateDisabledHolidays < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
create_table :discourse_calendar_disabled_holidays do |t|
|
||||||
|
t.string :holiday_name, null: false
|
||||||
|
t.string :region_code, null: false
|
||||||
|
t.boolean :disabled, null: false, default: true
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :discourse_calendar_disabled_holidays, [:holiday_name, :region_code], name: 'index_disabled_holidays_on_holiday_name_and_region_code'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -40,9 +40,13 @@ module Jobs
|
||||||
.delete_all
|
.delete_all
|
||||||
|
|
||||||
regions_and_user_ids.each do |region, user_ids|
|
regions_and_user_ids.each do |region, user_ids|
|
||||||
Holidays
|
DiscourseCalendar::Holiday.find_holidays_for(
|
||||||
.between(Date.today, 6.months.from_now, [region], :observed)
|
region_code: region,
|
||||||
.filter { |holiday| (1..5) === holiday[:date].wday }
|
start_date: Date.today,
|
||||||
|
end_date: 6.months.from_now,
|
||||||
|
show_holiday_observed_on_dates: true
|
||||||
|
)
|
||||||
|
.filter { |holiday| (1..5) === holiday[:date].wday && holiday[:disabled] === false }
|
||||||
.each do |holiday|
|
.each do |holiday|
|
||||||
|
|
||||||
user_ids.each do |user_id|
|
user_ids.each do |user_id|
|
||||||
|
|
|
||||||
|
|
@ -85,13 +85,15 @@ after_initialize do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# DISCOURSE CALENDAR
|
# DISCOURSE CALENDAR HOLIDAYS
|
||||||
|
|
||||||
add_admin_route 'admin.calendar', 'calendar'
|
add_admin_route 'admin.calendar', 'calendar'
|
||||||
|
|
||||||
%w[
|
%w[
|
||||||
../app/controllers/admin/admin_discourse_calendar_controller.rb
|
../app/controllers/admin/admin_discourse_calendar_controller.rb
|
||||||
../app/controllers/admin/discourse_calendar/admin_holidays_controller.rb
|
../app/controllers/admin/discourse_calendar/admin_holidays_controller.rb
|
||||||
|
../app/models/discourse_calendar/disabled_holiday.rb
|
||||||
|
../app/services/discourse_calendar/holiday.rb
|
||||||
].each { |path| load File.expand_path(path, __FILE__) }
|
].each { |path| load File.expand_path(path, __FILE__) }
|
||||||
|
|
||||||
Discourse::Application.routes.append do
|
Discourse::Application.routes.append do
|
||||||
|
|
@ -99,6 +101,8 @@ after_initialize do
|
||||||
|
|
||||||
get '/admin/plugins/calendar' => 'admin/plugins#index', constraints: StaffConstraint.new
|
get '/admin/plugins/calendar' => 'admin/plugins#index', constraints: StaffConstraint.new
|
||||||
get '/admin/discourse-calendar/holiday-regions/:region_code/holidays' => 'admin/discourse_calendar/admin_holidays#index', constraints: StaffConstraint.new
|
get '/admin/discourse-calendar/holiday-regions/:region_code/holidays' => 'admin/discourse_calendar/admin_holidays#index', constraints: StaffConstraint.new
|
||||||
|
post '/admin/discourse-calendar/holidays/disable' => 'admin/discourse_calendar/admin_holidays#disable', constraints: StaffConstraint.new
|
||||||
|
delete '/admin/discourse-calendar/holidays/enable' => 'admin/discourse_calendar/admin_holidays#enable', constraints: StaffConstraint.new
|
||||||
end
|
end
|
||||||
|
|
||||||
# DISCOURSE POST EVENT
|
# DISCOURSE POST EVENT
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,37 @@ describe DiscourseCalendar::CreateHolidayEvents do
|
||||||
expect(CalendarEvent.exists?(username: frenchy.username)).to eq(false)
|
expect(CalendarEvent.exists?(username: frenchy.username)).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when there are disabled holidays" do
|
||||||
|
let(:france_assomption) { { holiday_name: "Assomption", region_code: "fr" } }
|
||||||
|
let(:france_toussaint) { { holiday_name: "Toussaint", region_code: "fr" } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
DiscourseCalendar::DisabledHoliday.create!(france_assomption)
|
||||||
|
DiscourseCalendar::DisabledHoliday.create!(france_toussaint)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "only adds enabled holidays to the calendar" do
|
||||||
|
frenchy
|
||||||
|
freeze_time Time.zone.local(2019, 7, 1)
|
||||||
|
subject.execute(nil)
|
||||||
|
|
||||||
|
expect(CalendarEvent.pluck(:region, :description, :start_date, :username)).to eq([
|
||||||
|
["fr", "Armistice 1918", "2019-11-11", frenchy.username],
|
||||||
|
["fr", "Noël", "2019-12-25", frenchy.username],
|
||||||
|
["fr", "Jour de l'an", "2020-01-01", frenchy.username]
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't add disabled holidays to the calendar" do
|
||||||
|
frenchy
|
||||||
|
freeze_time Time.zone.local(2019, 7, 1)
|
||||||
|
subject.execute(nil)
|
||||||
|
|
||||||
|
expect(CalendarEvent.pluck(:description)).not_to include(france_assomption[:holiday_name])
|
||||||
|
expect(CalendarEvent.pluck(:description)).not_to include(france_toussaint[:holiday_name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "when user_options.timezone column exists" do
|
context "when user_options.timezone column exists" do
|
||||||
it "uses the user TZ when available" do
|
it "uses the user TZ when available" do
|
||||||
frenchy.user_option.update!(timezone: "Europe/Paris")
|
frenchy.user_option.update!(timezone: "Europe/Paris")
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ module Admin::DiscourseCalendar
|
||||||
get "/admin/discourse-calendar/holiday-regions/mx/holidays.json"
|
get "/admin/discourse-calendar/holiday-regions/mx/holidays.json"
|
||||||
|
|
||||||
expect(response.parsed_body["holidays"]).to include(
|
expect(response.parsed_body["holidays"]).to include(
|
||||||
{ "date" => "2022-01-01", "name" => "Año nuevo", "regions" => ["mx"] },
|
{ "date" => "2022-01-01", "name" => "Año nuevo", "regions" => ["mx"], "disabled" => false },
|
||||||
{ "date" => "2022-09-16", "name" => "Día de la Independencia", "regions" => ["mx"] }
|
{ "date" => "2022-09-16", "name" => "Día de la Independencia", "regions" => ["mx"], "disabled" => false }
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -65,5 +65,126 @@ module Admin::DiscourseCalendar
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#disable" do
|
||||||
|
context "when the calendar plugin is enabled" do
|
||||||
|
let(:calendar_enabled) { true }
|
||||||
|
let(:dia_de_la_independencia) do
|
||||||
|
{ holiday_name: "Día de la Independencia", region_code: "mx" }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when an admin is signed in" do
|
||||||
|
before do
|
||||||
|
sign_in(admin)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "disables the holiday in the specified region and returns a 200 status code" do
|
||||||
|
post "/admin/discourse-calendar/holidays/disable.json",
|
||||||
|
params: {
|
||||||
|
disabled_holiday: dia_de_la_independencia
|
||||||
|
}
|
||||||
|
|
||||||
|
disabled_holiday = DiscourseCalendar::DisabledHoliday.last
|
||||||
|
|
||||||
|
expect(disabled_holiday.holiday_name).to eq(dia_de_la_independencia[:holiday_name])
|
||||||
|
expect(disabled_holiday.region_code).to eq(dia_de_la_independencia[:region_code])
|
||||||
|
expect(disabled_holiday.disabled).to eq(true)
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 400 (bad request) status code when the parameters are not valid" do
|
||||||
|
post "/admin/discourse-calendar/holidays/disable.json",
|
||||||
|
params: { disabled_holiday: {} }
|
||||||
|
|
||||||
|
expect(response.status).to eq(400)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when a holiday has been added to the calendar" do
|
||||||
|
let(:calendar_post) { create_post(raw: "[calendar]\n[/calendar]") }
|
||||||
|
let(:australia_new_years_day) do
|
||||||
|
{ holiday_name: "New Year's Day", date: "2022-01-01", region_code: "au" }
|
||||||
|
end
|
||||||
|
let(:australia_day) do
|
||||||
|
{ holiday_name: "Australia Day", date: "2022-01-26", region_code: "au" }
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
CalendarEvent.create!(
|
||||||
|
topic_id: calendar_post.topic_id,
|
||||||
|
description: australia_new_years_day[:holiday_name],
|
||||||
|
start_date: australia_new_years_day[:date],
|
||||||
|
region: australia_new_years_day[:region_code]
|
||||||
|
)
|
||||||
|
|
||||||
|
CalendarEvent.create!(
|
||||||
|
topic_id: calendar_post.topic_id,
|
||||||
|
description: australia_day[:holiday_name],
|
||||||
|
start_date: australia_day[:date],
|
||||||
|
region: australia_day[:region_code]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "removes disabled holidays from the calendar" do
|
||||||
|
post "/admin/discourse-calendar/holidays/disable.json",
|
||||||
|
params: {
|
||||||
|
disabled_holiday: {
|
||||||
|
holiday_name: australia_new_years_day[:holiday_name],
|
||||||
|
region_code: australia_new_years_day[:region_code],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(CalendarEvent.where(
|
||||||
|
description: australia_new_years_day[:holiday_name],
|
||||||
|
region: australia_new_years_day[:region_code]
|
||||||
|
).count).to eq(0)
|
||||||
|
|
||||||
|
expect(CalendarEvent.where(
|
||||||
|
description: australia_day[:holiday_name],
|
||||||
|
region: australia_day[:region_code]
|
||||||
|
).count).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#enable" do
|
||||||
|
context "when the calendar plugin is enabled" do
|
||||||
|
let(:calendar_enabled) { true }
|
||||||
|
|
||||||
|
context "when an admin is signed in" do
|
||||||
|
before do
|
||||||
|
sign_in(admin)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when there is a disabled holiday" do
|
||||||
|
let(:hong_kong_labour_day) { { holiday_name: "Labour Day", region_code: "hk" } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
DiscourseCalendar::DisabledHoliday.create!(hong_kong_labour_day)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "enables a holiday (by deleting its 'disabled' record) and returns a 200 status code" do
|
||||||
|
expect(DiscourseCalendar::DisabledHoliday.count).to eq(1)
|
||||||
|
|
||||||
|
delete "/admin/discourse-calendar/holidays/enable.json",
|
||||||
|
params: {
|
||||||
|
disabled_holiday: hong_kong_labour_day
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(DiscourseCalendar::DisabledHoliday.count).to eq(0)
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a 422 (unprocessable enity) status code when a holiday can't be enabled" do
|
||||||
|
delete "/admin/discourse-calendar/holidays/enable.json",
|
||||||
|
params: { disabled_holiday: { holiday_name: "Not disabled holiday", region_code: "NA" } }
|
||||||
|
|
||||||
|
expect(response.status).to eq(422)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
module DiscourseCalendar
|
||||||
|
describe Holiday do
|
||||||
|
describe ".find_holidays_for" do
|
||||||
|
before do
|
||||||
|
DisabledHoliday.create!(holiday_name: "New Year's Day", region_code: "sg")
|
||||||
|
DisabledHoliday.create!(holiday_name: "Chinese New Year", region_code: "sg")
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:holidays) do
|
||||||
|
Holiday.find_holidays_for(
|
||||||
|
region_code: "sg",
|
||||||
|
start_date: "2022-01-01",
|
||||||
|
end_date: "2022-04-30"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a list of holidays indicating whether a holiday is disabled or not" do
|
||||||
|
expect(holidays).to include(a_hash_including(
|
||||||
|
{ name: "New Year's Day", regions: [:sg], disabled: true }
|
||||||
|
))
|
||||||
|
|
||||||
|
expect(holidays).to include(a_hash_including(
|
||||||
|
{ name: "Chinese New Year", regions: [:sg], disabled: true }
|
||||||
|
))
|
||||||
|
|
||||||
|
expect(holidays).to include(a_hash_including(
|
||||||
|
{ name: "Good Friday", regions: [:sg], disabled: false }
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "dates holidays are observed on" do
|
||||||
|
let(:holidays) { Holiday.find_holidays_for(
|
||||||
|
region_code: "sg",
|
||||||
|
start_date: "2021-12-31",
|
||||||
|
end_date: "2022-05-31",
|
||||||
|
show_holiday_observed_on_dates: show_holiday_observed_on_dates) }
|
||||||
|
|
||||||
|
context "when `show_holiday_observed_on_dates` is set to true" do
|
||||||
|
let(:show_holiday_observed_on_dates) { true }
|
||||||
|
|
||||||
|
it "returns the holidays with the date the holidays are observed on" do
|
||||||
|
expect(holidays).to include(a_hash_including(
|
||||||
|
{ name: "New Year's Day", date: Date.new(2021, 12, 31), regions: [:sg] }
|
||||||
|
))
|
||||||
|
|
||||||
|
expect(holidays).to include(a_hash_including(
|
||||||
|
{ name: "Labour Day", date: Date.new(2022, 5, 2), regions: [:sg] }
|
||||||
|
))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when `show_holiday_observed_on_dates` is set to false" do
|
||||||
|
let(:show_holiday_observed_on_dates) { false }
|
||||||
|
|
||||||
|
it "returns the holidays with the actual holiday dates" do
|
||||||
|
expect(holidays).to include(a_hash_including(
|
||||||
|
{ name: "New Year's Day", date: Date.new(2022, 1, 1), regions: [:sg] }
|
||||||
|
))
|
||||||
|
|
||||||
|
expect(holidays).to include(a_hash_including(
|
||||||
|
{ name: "Labour Day", date: Date.new(2022, 5, 1), regions: [:sg] }
|
||||||
|
))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
|
import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
|
||||||
import { test } from "qunit";
|
import { test } from "qunit";
|
||||||
import { visit } from "@ember/test-helpers";
|
import { click, visit } from "@ember/test-helpers";
|
||||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||||
|
|
||||||
acceptance("Admin - Calendar", function (needs) {
|
acceptance("Admin - Discourse Calendar - Holidays", function (needs) {
|
||||||
needs.user();
|
needs.user();
|
||||||
needs.settings({
|
needs.settings({
|
||||||
calendar_enabled: true,
|
calendar_enabled: true,
|
||||||
|
|
@ -19,6 +19,14 @@ acceptance("Admin - Calendar", function (needs) {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.post("/admin/discourse-calendar/holidays/disable", () => {
|
||||||
|
return helper.response({ success: "OK" });
|
||||||
|
});
|
||||||
|
|
||||||
|
server.delete("/admin/discourse-calendar/holidays/enable", () => {
|
||||||
|
return helper.response({ success: "OK" });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("viewing holidays for a selected region", async (assert) => {
|
test("viewing holidays for a selected region", async (assert) => {
|
||||||
|
|
@ -46,4 +54,24 @@ acceptance("Admin - Calendar", function (needs) {
|
||||||
"it displays holiday dates"
|
"it displays holiday dates"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("disabling and enabling a holiday", async (assert) => {
|
||||||
|
const regions = selectKit(".region-input");
|
||||||
|
|
||||||
|
await visit("/admin/plugins/calendar");
|
||||||
|
await regions.expand();
|
||||||
|
await regions.selectRowByValue("ca");
|
||||||
|
|
||||||
|
await click("table tr:first-child button");
|
||||||
|
assert.ok(
|
||||||
|
query("table tr.disabled:first-child"),
|
||||||
|
"after clicking the disable button, it adds a .disabled CSS class"
|
||||||
|
);
|
||||||
|
|
||||||
|
await click("table tr.disabled:first-child button");
|
||||||
|
assert.ok(
|
||||||
|
query("table tr:first-child"),
|
||||||
|
"after clicking the enable button, it removes the .disabled CSS class"
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import componentTest, {
|
||||||
|
setupRenderingTest,
|
||||||
|
} from "discourse/tests/helpers/component-test";
|
||||||
|
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import hbs from "htmlbars-inline-precompile";
|
||||||
|
|
||||||
|
discourseModule(
|
||||||
|
"Integration | Component | admin-holidays-list-item",
|
||||||
|
function (hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
const template = hbs`{{admin-holidays-list-item
|
||||||
|
holiday=holiday
|
||||||
|
region_code=region_code
|
||||||
|
isHolidayDisabled=holiday.disabled
|
||||||
|
}}`;
|
||||||
|
|
||||||
|
componentTest(
|
||||||
|
"when a holiday is disabled, it displays an enable button and adds a disabled CSS class",
|
||||||
|
{
|
||||||
|
template,
|
||||||
|
|
||||||
|
beforeEach() {
|
||||||
|
this.set("holiday", {
|
||||||
|
date: "2022-01-01",
|
||||||
|
name: "New Year's Day",
|
||||||
|
disabled: true,
|
||||||
|
});
|
||||||
|
this.set("region_code", "sg");
|
||||||
|
},
|
||||||
|
|
||||||
|
async test(assert) {
|
||||||
|
assert.equal(
|
||||||
|
query("button").innerText,
|
||||||
|
"Enable",
|
||||||
|
"it displays an enable button"
|
||||||
|
);
|
||||||
|
assert.ok(query(".disabled"), "it adds a 'disabled' CSS class");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
componentTest(
|
||||||
|
"when a holiday is enabled, it displays a disable button and does not add a disabled CSS class",
|
||||||
|
{
|
||||||
|
template,
|
||||||
|
|
||||||
|
beforeEach() {
|
||||||
|
this.set("holiday", {
|
||||||
|
date: "2022-01-01",
|
||||||
|
name: "New Year's Day",
|
||||||
|
disabled: false,
|
||||||
|
});
|
||||||
|
this.set("region_code", "au");
|
||||||
|
},
|
||||||
|
|
||||||
|
async test(assert) {
|
||||||
|
assert.equal(
|
||||||
|
query("button").innerText,
|
||||||
|
"Disable",
|
||||||
|
"it displays a disable button"
|
||||||
|
);
|
||||||
|
assert.notOk(
|
||||||
|
query(".disabled"),
|
||||||
|
"it does not add a 'disabled' CSS class"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
Loading…
Reference in New Issue