├── .gitignore
├── .npmrc
├── .prettierignore
├── vendor
└── holidays
│ ├── Gemfile
│ ├── lib
│ ├── holidays
│ │ ├── version.rb
│ │ ├── errors.rb
│ │ ├── definition
│ │ │ ├── entity
│ │ │ │ ├── custom_method.rb
│ │ │ │ └── test.rb
│ │ │ ├── decorator
│ │ │ │ ├── custom_method_proc.rb
│ │ │ │ ├── custom_method_source.rb
│ │ │ │ └── test.rb
│ │ │ ├── validator
│ │ │ │ ├── custom_method.rb
│ │ │ │ └── region.rb
│ │ │ ├── context
│ │ │ │ ├── merger.rb
│ │ │ │ └── load.rb
│ │ │ └── repository
│ │ │ │ ├── custom_methods.rb
│ │ │ │ ├── regions.rb
│ │ │ │ └── cache.rb
│ │ ├── core_extensions
│ │ │ └── time.rb
│ │ ├── finder
│ │ │ └── rules
│ │ │ │ └── in_region.rb
│ │ └── factory
│ │ │ └── date_calculator.rb
│ └── generated_definitions
│ │ ├── vi.rb
│ │ ├── ecbtarget.rb
│ │ ├── tn.rb
│ │ ├── ma.rb
│ │ └── nerc.rb
│ ├── bin
│ ├── setup
│ └── console
│ ├── definitions
│ ├── spec
│ │ ├── spec_helper.rb
│ │ ├── data
│ │ │ ├── invalid
│ │ │ │ └── months
│ │ │ │ │ ├── missing
│ │ │ │ │ └── no_months.yaml
│ │ │ │ │ └── malformed
│ │ │ │ │ └── bad.yaml
│ │ │ └── valid
│ │ │ │ └── simple.yaml
│ │ └── coverage_report.rb
│ ├── Makefile
│ ├── Gemfile
│ ├── lib
│ │ └── validation
│ │ │ ├── error.rb
│ │ │ ├── definition_validator.rb
│ │ │ └── custom_method_validator.rb
│ ├── doc
│ │ └── architecture
│ │ │ └── README.md
│ ├── README.md
│ ├── LICENSE
│ └── vi.yaml
│ ├── test
│ ├── data
│ │ ├── test_custom_govt_holiday_defs.yaml
│ │ ├── test_invalid_region.rb
│ │ ├── test_region.rb
│ │ ├── test_single_custom_holiday_defs.yaml
│ │ ├── test_custom_informal_holidays_defs.yaml
│ │ ├── test_multiple_custom_holiday_defs.yaml
│ │ ├── test_single_custom_holiday_with_custom_procs.yaml
│ │ ├── test_custom_year_range_holiday_defs.yaml
│ │ ├── test_multiple_regions_with_conflicts_region_1.yaml
│ │ └── test_multiple_regions_with_conflicts_region_2.yaml
│ ├── defs
│ │ ├── test_defs_in.rb
│ │ ├── test_defs_sa.rb
│ │ ├── test_defs_sg.rb
│ │ ├── test_defs_unitednations.rb
│ │ ├── test_defs_id.rb
│ │ ├── test_defs_ae.rb
│ │ ├── test_defs_fed_ex.rb
│ │ ├── test_defs_vi.rb
│ │ ├── test_defs_tn.rb
│ │ ├── test_defs_ecbtarget.rb
│ │ ├── test_defs_ph.rb
│ │ ├── test_defs_ng.rb
│ │ ├── test_defs_cr.rb
│ │ ├── test_defs_ke.rb
│ │ ├── test_defs_nerc.rb
│ │ ├── test_defs_ups.rb
│ │ ├── test_defs_fedex.rb
│ │ ├── test_defs_ma.rb
│ │ └── test_defs_at.rb
│ ├── integration
│ │ ├── README.md
│ │ ├── test_custom_informal_holidays.rb
│ │ ├── test_available_regions.rb
│ │ ├── test_nonstandard_regions.rb
│ │ └── test_multiple_regions_with_conflict.rb
│ ├── holidays
│ │ ├── date_calculator
│ │ │ └── test_day_of_month.rb
│ │ ├── definition
│ │ │ ├── context
│ │ │ │ ├── test_merger.rb
│ │ │ │ └── test_load.rb
│ │ │ └── repository
│ │ │ │ └── test_custom_methods.rb
│ │ └── finder
│ │ │ └── rules
│ │ │ └── test_in_region.rb
│ ├── coverage_report.rb
│ └── test_helper.rb
│ ├── doc
│ └── REFERENCES
│ ├── Gemfile.lock
│ ├── Makefile
│ ├── LICENSE
│ └── holidays.gemspec
├── .prettierrc.cjs
├── .template-lintrc.cjs
├── stylelint.config.mjs
├── .streerc
├── assets
├── stylesheets
│ ├── common
│ │ ├── user-preferences.scss
│ │ ├── discourse-calendar-holidays.scss
│ │ ├── discourse-post-event-upcoming-events.scss
│ │ ├── discourse-post-event-preview.scss
│ │ ├── discourse-post-event-bulk-invite-modal.scss
│ │ └── discourse-post-event-core-ext.scss
│ ├── mobile
│ │ ├── discourse-post-event-invitees.scss
│ │ ├── discourse-post-event-core-ext.scss
│ │ ├── discourse-post-event.scss
│ │ └── discourse-calendar.scss
│ ├── desktop
│ │ ├── discourse-post-event-invitees.scss
│ │ └── discourse-calendar.scss
│ └── colors.scss
└── javascripts
│ └── discourse
│ ├── admin-calendar-route-map.js
│ ├── templates
│ ├── discourse-post-event-upcoming-events.gjs
│ ├── discourse-post-event-upcoming-events-index.gjs
│ ├── discourse-post-event-upcoming-events-mine.gjs
│ └── admin-plugins-calendar.gjs
│ ├── controllers
│ ├── discourse-post-event-upcoming-events-mine.js
│ ├── discourse-post-event-upcoming-events-index.js
│ └── admin-plugins-calendar.js
│ ├── adapters
│ ├── discourse-post-event-adapter.js
│ ├── discourse-post-event-invitee.js
│ ├── discourse-post-event-reminder.js
│ └── discourse-post-event-event.js
│ ├── connectors
│ ├── header-topic-title-suffix
│ │ └── event-date-container.gjs
│ ├── before-topic-list-body
│ │ └── category-calendar.gjs
│ ├── discovery-list-container-top
│ │ └── category-events-calendar.gjs
│ └── topic-list-after-title
│ │ └── event-badge.gjs
│ ├── models
│ ├── discourse-post-event-reminder.js
│ ├── discourse-post-event-event-stats.js
│ ├── discourse-post-event-invitee.js
│ └── discourse-post-event-invitees.js
│ ├── discourse-event-upcoming-events-route-map.js
│ ├── helpers
│ ├── format-future-date.js
│ └── format-event-name.js
│ ├── pre-initializers
│ └── transformers.js
│ ├── components
│ ├── discourse-post-event
│ │ ├── description.gjs
│ │ ├── location.gjs
│ │ ├── chat-channel.gjs
│ │ ├── url.gjs
│ │ ├── creator.gjs
│ │ └── event-status.gjs
│ ├── group-timezones
│ │ └── new-day.gjs
│ ├── modal
│ │ └── post-event-invitees
│ │ │ └── user.gjs
│ ├── event-field.gjs
│ ├── admin-holidays-list.gjs
│ ├── bulk-invite-sample-csv-file.gjs
│ ├── toggle-invitees.gjs
│ └── region-input.js
│ ├── lib
│ ├── guess-best-date-format.js
│ ├── calendar-locale.js
│ ├── full-calendar-default-options.js
│ ├── colors.js
│ ├── add-recurrent-events.js
│ ├── popover.js
│ └── discourse-markdown
│ │ └── discourse-post-event-block.js
│ ├── services
│ └── discourse-post-event-service.js
│ ├── routes
│ ├── discourse-post-event-upcoming-events-index.js
│ └── discourse-post-event-upcoming-events-mine.gjs
│ ├── initializers
│ ├── disable-sort.js
│ ├── add-upcoming-events-to-sidebar.js
│ └── event-relative-date.js
│ └── api-initializers
│ └── discourse-group-timezones.gjs
├── .rubocop.yml
├── Gemfile
├── eslint.config.mjs
├── lib
├── discourse_calendar
│ ├── engine.rb
│ └── site_settings
│ │ ├── map_events_title_json_schema.rb
│ │ └── map_event_tag_colors_json_schema.rb
├── discourse_post_event
│ ├── engine.rb
│ ├── post_extension.rb
│ ├── export_csv_file_extension.rb
│ ├── rrule_generator.rb
│ └── export_csv_controller_extension.rb
├── calendar_settings_validator.rb
├── group_timezones.rb
├── calendar_validator.rb
├── event_validator.rb
├── holiday_status.rb
└── tasks
│ └── javascript.rake
├── spec
├── system
│ ├── core_features_spec.rb
│ ├── page_objects
│ │ └── discourse_calendar
│ │ │ ├── upcoming_events.rb
│ │ │ ├── post_event_form.rb
│ │ │ └── bulk_invite_modal.rb
│ ├── disable_sort_spec.rb
│ ├── group_timezones_spec.rb
│ └── category_calendar_spec.rb
├── fabricators
│ ├── calendar_event_fabricator.rb
│ └── event_fabricator.rb
├── lib
│ ├── calendar_settings_validator_spec.rb
│ └── group_timezones_spec.rb
├── integration
│ ├── topic_spec.rb
│ ├── curently_away_report_spec.rb
│ └── invitee_spec.rb
├── requests
│ └── site_spec.rb
├── serializers
│ ├── user_serializer_spec.rb
│ └── discourse_post_event
│ │ └── post_serializer_spec.rb
├── services
│ └── discourse_post_event
│ │ └── chat_channel_sync_spec.rb
└── jobs
│ └── regular
│ └── discourse_post_event
│ └── bump_topic_spec.rb
├── app
├── controllers
│ └── discourse_post_event
│ │ ├── upcoming_events_controller.rb
│ │ └── discourse_post_event_controller.rb
├── serializers
│ ├── user_timezone_serializer.rb
│ └── discourse_post_event
│ │ ├── invitee_list_serializer.rb
│ │ ├── invitee_serializer.rb
│ │ └── event_stats_serializer.rb
├── models
│ └── discourse_calendar
│ │ └── disabled_holiday.rb
└── services
│ └── discourse_calendar
│ └── holiday.rb
├── translator.yml
├── .github
└── workflows
│ └── discourse-plugin.yml
├── config
└── locales
│ ├── server.en_GB.yml
│ ├── server.te.yml
│ ├── server.bs_BA.yml
│ ├── server.lv.yml
│ ├── server.th.yml
│ ├── server.bg.yml
│ ├── server.sq.yml
│ ├── server.sr.yml
│ ├── client.en_GB.yml
│ ├── server.zh_TW.yml
│ ├── server.gl.yml
│ ├── server.vi.yml
│ ├── server.et.yml
│ ├── server.sw.yml
│ ├── server.ug.yml
│ ├── server.nb_NO.yml
│ ├── server.be.yml
│ ├── server.ca.yml
│ ├── server.hy.yml
│ ├── server.hr.yml
│ ├── server.el.yml
│ ├── server.sk.yml
│ ├── server.ur.yml
│ ├── server.id.yml
│ ├── server.pt.yml
│ ├── server.ko.yml
│ ├── server.ro.yml
│ ├── client.sr.yml
│ ├── client.sq.yml
│ ├── server.fa_IR.yml
│ └── client.be.yml
├── db
└── migrate
│ ├── 20211216124303_add_timezone_to_calendar_events.rb
│ ├── 20250526154632_add_recurrence_until.rb
│ ├── 20250616101944_add_location_to_event.rb
│ ├── 20250616101945_add_description_to_event.rb
│ ├── 20221223210225_add_minimal_option_to_calendar_event.rb
│ ├── 20250602114410_add_show_local_time.rb
│ ├── 20220228163400_adds_timezone_to_discourse_post_event_event.rb
│ ├── 20240513140542_add_closed_to_discourse_post_event.rb
│ ├── 20200810190429_drop_reminders_table.rb
│ ├── 20200810185432_refactor_reminders.rb
│ ├── 20200409181607_remove_display_invitees.rb
│ ├── 20200729094848_add_url_column_to_event.rb
│ ├── 20200310200000_remove_timezone_custom_field.rb
│ ├── 20200812193122_add_recurrence_to_events.rb
│ ├── 20250520042223_add_chat_fields_to_events.rb
│ ├── 20200805133257_add_custom_fields_to_event.rb
│ ├── 20200809154642_create_reminders_table.rb
│ ├── 20200409102642_rename_setting_to_discourse_post_event.rb
│ ├── 20200327195549_add_topic_custom_field_post_event_date_index.rb
│ ├── 20200926144256_add_unique_index_to_topic_event_ends_at_custom_field.rb
│ ├── 20231123233308_delete_duplicated_holidays.rb
│ ├── 20200805073343_drop_old_discourse_calendar_tables.rb
│ ├── 20200409102639_drop_incorrect_future_schema_migrations.rb
│ ├── 20220604200919_create_disabled_holidays.rb
│ ├── 20200409120815_rename_topic_custom_field_topic_post_event_starts_at_index.rb
│ ├── 20200409102641_create_invitees_table.rb
│ ├── 20201110225115_create_post_event_dates_table.rb
│ ├── 20190724181542_add_on_holiday_index.rb
│ ├── 20200409102640_create_post_events_table.rb
│ ├── 20231124021939_delete_similar_holidays.rb
│ ├── 20221121165352_add_type_field_to_events_reminders.rb
│ └── 20220724130519_fix_post_event_timezones.rb
├── test
└── javascripts
│ ├── helpers
│ └── get-event-by-text.js
│ ├── acceptance
│ ├── sort-event-topics-test.js
│ └── topic-calendar-events-test.js
│ └── lib
│ └── raw-event-helper-test.js
├── package.json
├── jobs
└── regular
│ └── discourse_post_event
│ ├── bump_topic.rb
│ └── event_started.rb
├── .discourse-compatibility
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | /gems
3 | /auto_generated
4 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict = true
2 | auto-install-peers = false
3 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | assets/stylesheets/vendor/*.scss
2 | public/
3 |
--------------------------------------------------------------------------------
/vendor/holidays/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec
4 |
--------------------------------------------------------------------------------
/.prettierrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = require("@discourse/lint-configs/prettier");
2 |
--------------------------------------------------------------------------------
/.template-lintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = require("@discourse/lint-configs/template-lint");
2 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/version.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | VERSION = '8.4.1'
3 | end
4 |
--------------------------------------------------------------------------------
/stylelint.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | extends: ["@discourse/lint-configs/stylelint"],
3 | };
4 |
--------------------------------------------------------------------------------
/vendor/holidays/bin/setup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -euo pipefail
3 | IFS=$'\n\t'
4 | set -vx
5 |
6 | bundle install
7 |
--------------------------------------------------------------------------------
/.streerc:
--------------------------------------------------------------------------------
1 | --print-width=100
2 | --plugins=plugin/trailing_comma,plugin/disable_auto_ternary
3 | --ignore-files=vendor/*
4 |
--------------------------------------------------------------------------------
/assets/stylesheets/common/user-preferences.scss:
--------------------------------------------------------------------------------
1 | .user-preferences {
2 | .region details {
3 | min-width: 175px;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | inherit_gem:
2 | rubocop-discourse: stree-compat.yml
3 | AllCops:
4 | Exclude:
5 | - vendor/**/*
6 | - gems/**/*
7 |
--------------------------------------------------------------------------------
/vendor/holidays/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "bundler/setup"
4 | require "holidays"
5 |
6 | require "irb"
7 | IRB.start
8 |
--------------------------------------------------------------------------------
/assets/stylesheets/mobile/discourse-post-event-invitees.scss:
--------------------------------------------------------------------------------
1 | .post-event-invitees-modal {
2 | .modal-inner-container {
3 | min-width: 90vw;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/assets/stylesheets/desktop/discourse-post-event-invitees.scss:
--------------------------------------------------------------------------------
1 | .post-event-invitees-modal {
2 | .modal-inner-container {
3 | min-width: 350px;
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | $: << '../lib'
2 |
3 | require 'coverage_report'
4 |
5 | RSpec.configure do |c|
6 | c.order = :random
7 | end
8 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | group :development do
6 | gem "rubocop-discourse"
7 | gem "syntax_tree"
8 | end
9 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_custom_govt_holiday_defs.yaml:
--------------------------------------------------------------------------------
1 | months:
2 | 3:
3 | - name: Yaaay Government Day
4 | regions: [custom_multiple_files, custom_multiple_files_govt]
5 | mday: 1
--------------------------------------------------------------------------------
/assets/javascripts/discourse/admin-calendar-route-map.js:
--------------------------------------------------------------------------------
1 | export default {
2 | resource: "admin.adminPlugins",
3 | path: "/plugins",
4 | map() {
5 | this.route("calendar");
6 | },
7 | };
8 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import DiscourseRecommended from "@discourse/lint-configs/eslint";
2 |
3 | export default [
4 | ...DiscourseRecommended,
5 | {
6 | ignores: ["public/**/*"],
7 | },
8 | ];
9 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/Makefile:
--------------------------------------------------------------------------------
1 | default: validate
2 |
3 | validate:
4 | bundle exec ruby lib/validation/run.rb
5 |
6 | test:
7 | bundle exec rspec
8 |
9 | .PHONY: validate,test
10 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/templates/discourse-post-event-upcoming-events.gjs:
--------------------------------------------------------------------------------
1 | import RouteTemplate from "ember-route-template";
2 |
3 | export default RouteTemplate({{outlet}});
4 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/spec/data/invalid/months/missing/no_months.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | methods:
3 | test:
4 | arguments: year
5 | source: |
6 | true
7 |
8 | tests: |
9 | test
10 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'rspec', '~> 3'
4 | gem 'pry', :require => false
5 | gem 'spoon', :require => false
6 | gem 'simplecov-rcov', :require => false
7 |
--------------------------------------------------------------------------------
/lib/discourse_calendar/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module ::DiscourseCalendar
4 | class Engine < ::Rails::Engine
5 | engine_name PLUGIN_NAME
6 | isolate_namespace DiscourseCalendar
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/spec/system/core_features_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | RSpec.describe "Core features", type: :system do
4 | before { enable_current_plugin }
5 |
6 | it_behaves_like "having working core features"
7 | end
8 |
--------------------------------------------------------------------------------
/lib/discourse_post_event/engine.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | class Engine < ::Rails::Engine
5 | engine_name PLUGIN_NAME
6 | isolate_namespace DiscoursePostEvent
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/app/controllers/discourse_post_event/upcoming_events_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | class UpcomingEventsController < DiscoursePostEventController
5 | def index
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/assets/stylesheets/common/discourse-calendar-holidays.scss:
--------------------------------------------------------------------------------
1 | .region-input {
2 | width: 50%;
3 | }
4 |
5 | .disabled td {
6 | background-color: var(--primary-very-low);
7 | color: var(--primary-medium);
8 | font-style: italic;
9 | }
10 |
--------------------------------------------------------------------------------
/translator.yml:
--------------------------------------------------------------------------------
1 | # Configuration file for discourse-translator-bot
2 |
3 | files:
4 | - source_path: config/locales/client.en.yml
5 | destination_path: client.yml
6 | - source_path: config/locales/server.en.yml
7 | destination_path: server.yml
8 |
--------------------------------------------------------------------------------
/.github/workflows/discourse-plugin.yml:
--------------------------------------------------------------------------------
1 | name: Discourse Plugin
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 |
9 | jobs:
10 | ci:
11 | uses: discourse/.github/.github/workflows/discourse-plugin.yml@v1
12 |
--------------------------------------------------------------------------------
/config/locales/server.en_GB.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | en_GB:
8 |
--------------------------------------------------------------------------------
/db/migrate/20211216124303_add_timezone_to_calendar_events.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddTimezoneToCalendarEvents < ActiveRecord::Migration[6.1]
4 | def change
5 | add_column :calendar_events, :timezone, :string
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20250526154632_add_recurrence_until.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | #
3 | class AddRecurrenceUntil < ActiveRecord::Migration[7.2]
4 | def change
5 | add_column :discourse_post_event_events, :recurrence_until, :datetime
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/controllers/discourse-post-event-upcoming-events-mine.js:
--------------------------------------------------------------------------------
1 | import Controller from "@ember/controller";
2 |
3 | export default class DiscoursePostEventUpcomingEventsMineController extends Controller {
4 | queryParams = ["view"];
5 | }
6 |
--------------------------------------------------------------------------------
/db/migrate/20250616101944_add_location_to_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddLocationToEvent < ActiveRecord::Migration[7.2]
4 | def change
5 | add_column :discourse_post_event_events, :location, :string, limit: 1000
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/serializers/user_timezone_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class UserTimezoneSerializer < BasicUserSerializer
4 | attributes :timezone, :on_holiday
5 |
6 | def on_holiday
7 | @options[:on_holiday] || false
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/controllers/discourse-post-event-upcoming-events-index.js:
--------------------------------------------------------------------------------
1 | import Controller from "@ember/controller";
2 |
3 | export default class DiscoursePostEventUpcomingEventsIndexController extends Controller {
4 | queryParams = ["view"];
5 | }
6 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/adapters/discourse-post-event-adapter.js:
--------------------------------------------------------------------------------
1 | import RestAdapter from "discourse/adapters/rest";
2 |
3 | export default class DiscoursePostEventAdapter extends RestAdapter {
4 | basePath() {
5 | return "/discourse-post-event/";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/db/migrate/20250616101945_add_description_to_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddDescriptionToEvent < ActiveRecord::Migration[7.2]
4 | def change
5 | add_column :discourse_post_event_events, :description, :string, limit: 1000
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20221223210225_add_minimal_option_to_calendar_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddMinimalOptionToCalendarEvent < ActiveRecord::Migration[7.0]
4 | def change
5 | add_column :discourse_post_event_events, :minimal, :boolean
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/spec/data/valid/simple.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | months:
3 | 1:
4 | - name: Test Holiday
5 | regions: [test]
6 | mday: 1
7 |
8 | methods:
9 | test:
10 | arguments: year
11 | source: |
12 | true
13 |
14 | tests: |
15 | test
16 |
--------------------------------------------------------------------------------
/db/migrate/20250602114410_add_show_local_time.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddShowLocalTime < ActiveRecord::Migration[7.2]
4 | def change
5 | add_column :discourse_post_event_events, :show_local_time, :boolean, default: false, null: false
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20220228163400_adds_timezone_to_discourse_post_event_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddsTimezoneToDiscoursePostEventEvent < ActiveRecord::Migration[6.1]
4 | def change
5 | add_column :discourse_post_event_events, :timezone, :string
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/spec/data/invalid/months/malformed/bad.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | months:
3 | 1:
4 | - name: Test Holiday
5 | regions: [test]
6 | mday: 1
7 |
8 | methods:
9 | test:
10 | arguments: year
11 | source: |
12 | true
13 |
14 | tests: |
15 | test
16 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/connectors/header-topic-title-suffix/event-date-container.gjs:
--------------------------------------------------------------------------------
1 | import EventDate from "../../components/event-date";
2 |
3 | const EventDateContainer =
4 |
5 | ;
6 |
7 | export default EventDateContainer;
8 |
--------------------------------------------------------------------------------
/db/migrate/20240513140542_add_closed_to_discourse_post_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddClosedToDiscoursePostEvent < ActiveRecord::Migration[7.0]
4 | def change
5 | add_column :discourse_post_event_events, :closed, :boolean, default: false, null: false
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/adapters/discourse-post-event-invitee.js:
--------------------------------------------------------------------------------
1 | import DiscoursePostEventNestedAdapter from "./discourse-post-event-nested-adapter";
2 |
3 | export default class DiscoursePostEventInvitee extends DiscoursePostEventNestedAdapter {
4 | apiNameFor() {
5 | return "invitee";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/adapters/discourse-post-event-reminder.js:
--------------------------------------------------------------------------------
1 | import DiscoursePostEventNestedAdapter from "./discourse-post-event-nested-adapter";
2 |
3 | export default class DiscoursePostEventReminder extends DiscoursePostEventNestedAdapter {
4 | apiNameFor() {
5 | return "reminder";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/assets/stylesheets/desktop/discourse-calendar.scss:
--------------------------------------------------------------------------------
1 | .calendar.fc {
2 | table {
3 | width: 100%;
4 | }
5 |
6 | .fc-list-item-add-to-calendar {
7 | float: right;
8 | margin-right: 5px;
9 | }
10 |
11 | .fc-list-item:hover td {
12 | background: var(--highlight-medium);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/db/migrate/20200810190429_drop_reminders_table.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DropRemindersTable < ActiveRecord::Migration[6.0]
4 | def up
5 | drop_table :discourse_post_event_reminders
6 | end
7 |
8 | def down
9 | raise ActiveRecord::IrreversibleMigration
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_invalid_region.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module BAD_REGION_NAME
3 | def self.defined_regions
4 | [:test_region]
5 | end
6 |
7 | def self.holidays_by_month
8 | {}
9 | end
10 |
11 | def self.custom_methods
12 | {}
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/models/discourse-post-event-reminder.js:
--------------------------------------------------------------------------------
1 | import RestModel from "discourse/models/rest";
2 |
3 | export default class DiscoursePostEventReminder extends RestModel {
4 | init() {
5 | super.init(...arguments);
6 |
7 | this.__type = "discourse-post-event-reminder";
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_region.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module TEST_REGION
3 | def self.defined_regions
4 | [:test_region, :test_region2]
5 | end
6 |
7 | def self.holidays_by_month
8 | {}
9 | end
10 |
11 | def self.custom_methods
12 | {}
13 | end
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_single_custom_holiday_defs.yaml:
--------------------------------------------------------------------------------
1 | months:
2 | 6:
3 | - name: Company Founding
4 | regions: [custom_single_file]
5 | mday: 20
6 |
7 | tests:
8 | - given:
9 | date: '2013-06-20'
10 | regions: [custom_single_file]
11 | expect:
12 | name: "Company Founding"
13 |
--------------------------------------------------------------------------------
/assets/stylesheets/mobile/discourse-post-event-core-ext.scss:
--------------------------------------------------------------------------------
1 | .link-top-line {
2 | .event-date-container {
3 | display: block;
4 | margin-top: 0.25em;
5 |
6 | .event-date {
7 | margin: 0;
8 | }
9 | }
10 | }
11 |
12 | .header-title {
13 | .event-date {
14 | display: none;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/db/migrate/20200810185432_refactor_reminders.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class RefactorReminders < ActiveRecord::Migration[6.0]
4 | def up
5 | add_column :discourse_post_event_events, :reminders, :string
6 | end
7 |
8 | def down
9 | raise ActiveRecord::IrreversibleMigration
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/spec/coverage_report.rb:
--------------------------------------------------------------------------------
1 | require 'simplecov'
2 | require 'simplecov-rcov'
3 | SimpleCov.minimum_coverage 100
4 | SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
5 | SimpleCov.coverage_dir 'reports/coverage'
6 | SimpleCov.start do
7 | add_filter "/spec/"
8 | add_filter "/.bundle/"
9 | end
10 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_custom_informal_holidays_defs.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | months:
3 | 1:
4 | - name: informal day with type as string
5 | regions: [custom_informal]
6 | mday: 1
7 | type: informal
8 | - name: informal day with type as symbol
9 | regions: [custom_informal]
10 | mday: 5
11 | type: :informal
--------------------------------------------------------------------------------
/assets/javascripts/discourse/discourse-event-upcoming-events-route-map.js:
--------------------------------------------------------------------------------
1 | export default function () {
2 | this.route(
3 | "discourse-post-event-upcoming-events",
4 | { path: "/upcoming-events" },
5 | function () {
6 | this.route("index", { path: "/" });
7 | this.route("mine");
8 | }
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/db/migrate/20200409181607_remove_display_invitees.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class RemoveDisplayInvitees < ActiveRecord::Migration[6.0]
4 | def up
5 | remove_column :discourse_post_event_events, :display_invitees
6 | end
7 |
8 | def down
9 | raise ActiveRecord::IrreversibleMigration
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_multiple_custom_holiday_defs.yaml:
--------------------------------------------------------------------------------
1 | months:
2 | 10:
3 | - name: Company Founding!
4 | regions: [custom_multiple_files]
5 | mday: 5
6 |
7 | tests:
8 | - given:
9 | date: "2013-10-5"
10 | regions: ["custom_multiple_files"]
11 | expect:
12 | name: "Company Founding!"
13 |
--------------------------------------------------------------------------------
/config/locales/server.te.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | te:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: సభ్యనామం
12 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/errors.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | class Error < StandardError; end
3 |
4 | class FunctionNotFound < Error; end
5 | class InvalidFunctionResponse < Error; end
6 |
7 | class UnknownRegionError < Error ; end
8 | class InvalidRegion < Error; end
9 |
10 | class DefinitionTestError < Error; end
11 | end
12 |
--------------------------------------------------------------------------------
/config/locales/server.bs_BA.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | bs_BA:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Nadimak
12 |
--------------------------------------------------------------------------------
/config/locales/server.lv.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | lv:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Lietotājvārds
12 |
--------------------------------------------------------------------------------
/config/locales/server.th.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | th:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: ชื่อผู้ใช้
12 |
--------------------------------------------------------------------------------
/db/migrate/20200729094848_add_url_column_to_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddUrlColumnToEvent < ActiveRecord::Migration[6.0]
4 | def up
5 | add_column :discourse_post_event_events, :url, :string, limit: 1000
6 | end
7 |
8 | def down
9 | remove_column :discourse_post_event_events, :url
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/entity/custom_method.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Entity
4 | CustomMethod = Struct.new(:name, :arguments, :source) do
5 | def initialize(fields = {})
6 | super(*fields.values_at(*members))
7 | end
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/entity/test.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Entity
4 | Test = Struct.new(:dates, :regions, :options, :name, :holiday?) do
5 | def initialize(fields = {})
6 | super(*fields.values_at(*members))
7 | end
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/helpers/format-future-date.js:
--------------------------------------------------------------------------------
1 | import { htmlSafe } from "@ember/template";
2 | import guessDateFormat from "../lib/guess-best-date-format";
3 |
4 | export default function (date) {
5 | date = moment.utc(date).tz(moment.tz.guess());
6 | const format = guessDateFormat(date);
7 | return htmlSafe(date.format(format));
8 | }
9 |
--------------------------------------------------------------------------------
/config/locales/server.bg.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | bg:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Потребителско име
12 |
--------------------------------------------------------------------------------
/config/locales/server.sq.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sq:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Emri i përdoruesit
12 |
--------------------------------------------------------------------------------
/config/locales/server.sr.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sr:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Korisničko Ime
12 |
--------------------------------------------------------------------------------
/db/migrate/20200310200000_remove_timezone_custom_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class RemoveTimezoneCustomField < ActiveRecord::Migration[5.2]
4 | def up
5 | execute "DELETE FROM user_custom_fields WHERE name = 'timezone'"
6 | end
7 |
8 | def down
9 | raise ActiveRecord::IrreversibleMigration
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20200812193122_add_recurrence_to_events.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddRecurrenceToEvents < ActiveRecord::Migration[6.0]
4 | def up
5 | add_column :discourse_post_event_events, :recurrence, :string
6 | end
7 |
8 | def down
9 | remove_column :discourse_post_event_events, :recurrence
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20250520042223_add_chat_fields_to_events.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | class AddChatFieldsToEvents < ActiveRecord::Migration[7.2]
3 | def change
4 | add_column :discourse_post_event_events, :chat_enabled, :boolean, default: false, null: false
5 | add_column :discourse_post_event_events, :chat_channel_id, :bigint
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_in.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/in.yaml
7 | class InDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_in
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_sa.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/sa.yaml
7 | class SaDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_sa
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_sg.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/sg.yaml
7 | class SgDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_sg
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/spec/fabricators/calendar_event_fabricator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Fabricator(:calendar_event) do
4 | user
5 | username { |attrs| attrs[:user].username }
6 |
7 | topic { |attrs| Fabricate(:topic, user: attrs[:user]) }
8 | post { |attrs| Fabricate(:post, user: attrs[:user], topic: attrs[:topic]) }
9 |
10 | start_date "2000-01-01"
11 | end
12 |
--------------------------------------------------------------------------------
/config/locales/client.en_GB.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | en_GB:
8 | js:
9 | discourse_post_event:
10 | builder_modal:
11 | description:
12 | label: "Description"
13 |
--------------------------------------------------------------------------------
/db/migrate/20200805133257_add_custom_fields_to_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddCustomFieldsToEvent < ActiveRecord::Migration[6.0]
4 | def up
5 | add_column :discourse_post_event_events, :custom_fields, :jsonb, null: false, default: {}
6 | end
7 |
8 | def down
9 | remove_column :discourse_post_event_events, :custom_fields
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/assets/stylesheets/common/discourse-post-event-upcoming-events.scss:
--------------------------------------------------------------------------------
1 | .discourse-post-event-upcoming-events {
2 | height: 100%;
3 |
4 | .upcoming-events-table {
5 | width: 100%;
6 |
7 | thead {
8 | tr th {
9 | text-align: left;
10 | }
11 | }
12 |
13 | tbody {
14 | tr td {
15 | padding: 0.5em;
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_unitednations.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/unitednations.yaml
7 | class UnitednationsDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_unitednations
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/lib/validation/error.rb:
--------------------------------------------------------------------------------
1 | module Definitions
2 | module Errors
3 | class Error < StandardError; end
4 | class NoMonths < Error ; end
5 | class InvalidMonth < Error; end
6 | class InvalidMethod < Error; end
7 | class InvalidRegions < Error; end
8 | class InvalidCustomMethod < Error; end
9 | class InvalidTest < Error; end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/pre-initializers/transformers.js:
--------------------------------------------------------------------------------
1 | import { withPluginApi } from "discourse/lib/plugin-api";
2 |
3 | export default {
4 | before: "freeze-valid-transformers",
5 | initialize() {
6 | withPluginApi("1.33.0", (api) => {
7 | api.addValueTransformerName(
8 | "discourse-calendar-event-more-menu-should-show-participants"
9 | );
10 | });
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/test/javascripts/helpers/get-event-by-text.js:
--------------------------------------------------------------------------------
1 | export default function getEventByText(text) {
2 | const events = [...document.querySelectorAll(".fc-day-grid-event")].filter(
3 | (event) => event.textContent.includes(text)
4 | );
5 |
6 | switch (events.length) {
7 | case 0:
8 | return;
9 | case 1:
10 | return events[0];
11 | default:
12 | return events;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/discourse-post-event/description.gjs:
--------------------------------------------------------------------------------
1 | import CookText from "discourse/components/cook-text";
2 |
3 | const DiscoursePostEventDescription =
4 | {{#if @description}}
5 |
8 | {{/if}}
9 | ;
10 |
11 | export default DiscoursePostEventDescription;
12 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/templates/discourse-post-event-upcoming-events-index.gjs:
--------------------------------------------------------------------------------
1 | import RouteTemplate from "ember-route-template";
2 | import UpcomingEventsCalendar from "../components/upcoming-events-calendar";
3 |
4 | export default RouteTemplate(
5 |
6 |
7 |
8 |
9 |
10 | );
11 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/templates/discourse-post-event-upcoming-events-mine.gjs:
--------------------------------------------------------------------------------
1 | import RouteTemplate from "ember-route-template";
2 | import UpcomingEventsCalendar from "../components/upcoming-events-calendar";
3 |
4 | export default RouteTemplate(
5 |
6 |
7 |
8 |
9 |
10 | );
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "devDependencies": {
4 | "@discourse/lint-configs": "2.25.0",
5 | "ember-template-lint": "7.8.1",
6 | "eslint": "9.28.0",
7 | "prettier": "3.5.3",
8 | "stylelint": "16.20.0"
9 | },
10 | "engines": {
11 | "node": ">= 22",
12 | "npm": "please-use-pnpm",
13 | "yarn": "please-use-pnpm",
14 | "pnpm": "9.x"
15 | },
16 | "packageManager": "pnpm@9.15.5"
17 | }
18 |
--------------------------------------------------------------------------------
/config/locales/server.zh_TW.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | zh_TW:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: 使用者名稱
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "上傳檔案有錯誤,請再試一次。"
16 |
--------------------------------------------------------------------------------
/db/migrate/20200809154642_create_reminders_table.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateRemindersTable < ActiveRecord::Migration[6.0]
4 | def change
5 | create_table :discourse_post_event_reminders do |t|
6 | t.integer :post_id, null: false
7 | t.integer :value, null: false, default: 0
8 | t.integer :mean, null: false, default: 0
9 | t.string :unit, null: false, default: "minutes"
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/spec/system/page_objects/discourse_calendar/upcoming_events.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module PageObjects
4 | module Pages
5 | module DiscourseCalendar
6 | class UpcomingEvents < PageObjects::Pages::Base
7 | def visit
8 | super("/upcoming-events")
9 | end
10 |
11 | def open_year_list
12 | find(".fc-listNextYear-button").click
13 | end
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/group-timezones/new-day.gjs:
--------------------------------------------------------------------------------
1 | import icon from "discourse/helpers/d-icon";
2 |
3 | const NewDay =
4 |
5 |
6 | {{icon "chevron-left"}}
7 | {{@beforeDate}}
8 |
9 |
10 | {{@afterDate}}
11 | {{icon "chevron-right"}}
12 |
13 |
14 | ;
15 |
16 | export default NewDay;
17 |
--------------------------------------------------------------------------------
/db/migrate/20200409102642_rename_setting_to_discourse_post_event.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class RenameSettingToDiscoursePostEvent < ActiveRecord::Migration[6.0]
4 | def up
5 | execute "UPDATE site_settings SET name = 'discourse_post_event_enabled' WHERE name = 'post_event_enabled'"
6 | end
7 |
8 | def down
9 | execute "UPDATE site_settings SET name = 'post_event_enabled' WHERE name = 'discourse_post_event_enabled'"
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/connectors/before-topic-list-body/category-calendar.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@glimmer/component";
2 |
3 | export default class CategoryCalendar extends Component {
4 | static shouldRender(_, ctx) {
5 | return (
6 | ctx.siteSettings.calendar_categories_outlet === "before-topic-list-body"
7 | );
8 | }
9 |
10 |
11 |
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/connectors/discovery-list-container-top/category-events-calendar.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@glimmer/component";
2 |
3 | export default class CategoryEventsCalendar extends Component {
4 | static shouldRender(_, ctx) {
5 | return (
6 | ctx.siteSettings.calendar_categories_outlet ===
7 | "discovery-list-container-top"
8 | );
9 | }
10 |
11 |
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/config/locales/server.gl.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | gl:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Nome de usuario
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Houbo un erro ao cargar o ficheiro. Ténteo máis tarde."
16 |
--------------------------------------------------------------------------------
/config/locales/server.vi.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | vi:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Tên tài khoản
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Đã xảy ra lỗi khi tải lên tệp đó. Vui lòng thử lại sau."
16 |
--------------------------------------------------------------------------------
/db/migrate/20200327195549_add_topic_custom_field_post_event_date_index.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddTopicCustomFieldPostEventDateIndex < ActiveRecord::Migration[6.0]
4 | def change
5 | add_index :topic_custom_fields,
6 | %i[name topic_id],
7 | name: :idx_topic_custom_fields_post_event_starts_at,
8 | unique: true,
9 | where: "name = '#{DiscoursePostEvent::TOPIC_POST_EVENT_STARTS_AT}'"
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/discourse-post-event/location.gjs:
--------------------------------------------------------------------------------
1 | import CookText from "discourse/components/cook-text";
2 | import icon from "discourse/helpers/d-icon";
3 |
4 | const DiscoursePostEventLocation =
5 | {{#if @location}}
6 |
7 | {{icon "location-pin"}}
8 |
9 |
10 |
11 | {{/if}}
12 | ;
13 |
14 | export default DiscoursePostEventLocation;
15 |
--------------------------------------------------------------------------------
/config/locales/server.et.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | et:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Kasutajanimi
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Selle faili üleslaadimisel tekkis viga. Palun proovi hiljem uuesti."
16 |
--------------------------------------------------------------------------------
/config/locales/server.sw.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sw:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Jina la mtumiaji
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Tatizo limetokea wakati wa kupakia faili. Tafadhali jaribu tena."
16 |
--------------------------------------------------------------------------------
/config/locales/server.ug.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ug:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: ئىشلەتكۈچى ئاتى
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "ھۆججەتنى يۈكلەۋاتقاندا خاتالىق كۆرۈلدى. سەل تۇرۇپ قايتا سىناڭ."
16 |
--------------------------------------------------------------------------------
/app/controllers/discourse_post_event/discourse_post_event_controller.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | class DiscoursePostEventController < ::ApplicationController
5 | requires_plugin DiscourseCalendar::PLUGIN_NAME
6 | before_action :ensure_discourse_post_event_enabled
7 |
8 | private
9 |
10 | def ensure_discourse_post_event_enabled
11 | raise Discourse::NotFound if !SiteSetting.discourse_post_event_enabled
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/config/locales/server.nb_NO.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | nb_NO:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Brukernavn
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Det skjedde en feil når filen ble lastet opp. Prøv igjen senere. "
16 |
--------------------------------------------------------------------------------
/config/locales/server.be.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | be:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Імя карыстальніка
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Была памылка загрузкі гэтага файла. Калі ласка паспрабуйце зноў пазней."
16 |
--------------------------------------------------------------------------------
/config/locales/server.ca.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ca:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Nom d'usuari
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Hi ha hagut un error en carregar aquest fitxer. Proveu-ho de nou més tard."
16 |
--------------------------------------------------------------------------------
/config/locales/server.hy.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | hy:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Օգտանուն
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Այդ ֆայլը վերբեռնելիս տեղի է ունեցել սխալ: Խնդրում ենք փորձել կրկին ավելի ուշ: "
16 |
--------------------------------------------------------------------------------
/config/locales/server.hr.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | hr:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Korisničko ime
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Dogodila se greška pri učitavanju te datoteke. Molimo kasnije pokušajte ponovno."
16 |
--------------------------------------------------------------------------------
/config/locales/server.el.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | el:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Όνομα Χρήστη
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Παρουσίαστηκε ένα σφάλμα κατά το ανέβασμα του αρχείου σας, Παρακαλώ δοκιμάστε αργότερα."
16 |
--------------------------------------------------------------------------------
/config/locales/server.sk.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sk:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Používateľské meno
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "Počas nahrávanie súboru sa vyskytla chyba. Prosím, vyskúšajte ho nahraď znovu neskôr."
16 |
--------------------------------------------------------------------------------
/config/locales/server.ur.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ur:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: صارف نام
12 | discourse_post_event:
13 | errors:
14 | bulk_invite:
15 | error: "یہ فائل اَپ لوڈ کرنے میں ایک خرابی کا سامنا کرنا پڑا۔ براہ مہربانی کچھ دیر بعد دوبارہ کوشش کریں۔"
16 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/lib/guess-best-date-format.js:
--------------------------------------------------------------------------------
1 | export function isNotFullDayEvent(startsAt, endsAt) {
2 | return (
3 | startsAt.hours() > 0 ||
4 | startsAt.minutes() > 0 ||
5 | (endsAt && (moment(endsAt).hours() > 0 || moment(endsAt).minutes() > 0))
6 | );
7 | }
8 |
9 | export default function guessDateFormat(startsAt, endsAt) {
10 | let format;
11 | if (!isNotFullDayEvent(startsAt, endsAt)) {
12 | format = "LL";
13 | } else {
14 | format = "LLL";
15 | }
16 |
17 | return format;
18 | }
19 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/services/discourse-post-event-service.js:
--------------------------------------------------------------------------------
1 | import Service, { service } from "@ember/service";
2 |
3 | export default class DiscoursePostEventService extends Service {
4 | @service siteSettings;
5 | @service discoursePostEventApi;
6 |
7 | async fetchEvents(params = {}) {
8 | if (this.siteSettings.include_expired_events_on_calendar) {
9 | params.include_expired = true;
10 | }
11 | const events = await this.discoursePostEventApi.events(params);
12 | return await events;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/assets/stylesheets/colors.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable scss/no-global-function-names */
2 | :root {
3 | --calendar-normal: #{dark-light-choose(
4 | lighten($tertiary, 55%),
5 | darken($tertiary, 25%)
6 | )};
7 | --calendar-close-to-working-hours: #{dark-light-choose(
8 | desaturate(lighten($tertiary, 45%), 15%),
9 | darken($tertiary, 15%)
10 | )};
11 | --calendar-in-working-hours: #{dark-light-choose(
12 | desaturate(lighten($tertiary, 40%), 20%),
13 | darken($tertiary, 10%)
14 | )};
15 | }
16 |
--------------------------------------------------------------------------------
/lib/discourse_post_event/post_extension.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | module PostExtension
5 | extend ActiveSupport::Concern
6 |
7 | prepended do
8 | has_one :event, dependent: :destroy, class_name: "DiscoursePostEvent::Event", foreign_key: :id
9 |
10 | validate :valid_event
11 | end
12 |
13 | def valid_event
14 | return unless self.raw_changed?
15 |
16 | validator = DiscoursePostEvent::EventValidator.new(self)
17 | validator.validate_event
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/connectors/topic-list-after-title/event-badge.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@glimmer/component";
2 | import { service } from "@ember/service";
3 | import EventDate from "../../components/event-date";
4 |
5 | export default class EventBadge extends Component {
6 | @service siteSettings;
7 |
8 |
9 | {{~#if this.siteSettings.discourse_post_event_enabled~}}
10 | {{~#if @outletArgs.topic.event_starts_at~}}
11 |
12 | {{~/if~}}
13 | {{~/if~}}
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/adapters/discourse-post-event-event.js:
--------------------------------------------------------------------------------
1 | import { underscore } from "@ember/string";
2 | import DiscoursePostEventAdapter from "./discourse-post-event-adapter";
3 |
4 | export default class DiscoursePostEventEvent extends DiscoursePostEventAdapter {
5 | pathFor(store, type, findArgs) {
6 | const path =
7 | this.basePath(store, type, findArgs) +
8 | underscore(store.pluralize(this.apiNameFor(type)));
9 | return this.appendQueryParams(path, findArgs);
10 | }
11 |
12 | apiNameFor() {
13 | return "event";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/db/migrate/20200926144256_add_unique_index_to_topic_event_ends_at_custom_field.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddUniqueIndexToTopicEventEndsAtCustomField < ActiveRecord::Migration[6.0]
4 | def up
5 | add_index :topic_custom_fields,
6 | %i[name topic_id],
7 | name: :idx_topic_custom_fields_topic_post_event_ends_at,
8 | unique: true,
9 | where: "name = '#{DiscoursePostEvent::TOPIC_POST_EVENT_ENDS_AT}'"
10 | end
11 |
12 | def down
13 | raise ActiveRecord::IrreversibleMigration
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/modal/post-event-invitees/user.gjs:
--------------------------------------------------------------------------------
1 | import avatar from "discourse/helpers/avatar";
2 | import { userPath } from "discourse/lib/url";
3 | import { formatUsername } from "discourse/lib/utilities";
4 |
5 | const User =
6 |
7 |
8 | {{avatar @user imageSize="medium"}}
9 |
10 | {{formatUsername @user.username}}
11 |
12 |
13 |
14 | ;
15 |
16 | export default User;
17 |
--------------------------------------------------------------------------------
/jobs/regular/discourse_post_event/bump_topic.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Jobs
4 | class DiscoursePostEventBumpTopic < ::Jobs::Base
5 | sidekiq_options retry: false
6 |
7 | def execute(args)
8 | return unless topic = Topic.find_by(id: args[:topic_id].to_i)
9 | return if args[:date].blank?
10 |
11 | event_user = User.find_by(id: topic.user_id)
12 | timer = TopicTimer.find_by(topic_id: args[:topic_id].to_i)
13 |
14 | topic.set_or_create_timer(TopicTimer.types[:bump], args[:date], by_user: event_user)
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/jobs/regular/discourse_post_event/event_started.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Jobs
4 | class DiscoursePostEventEventStarted < ::Jobs::Base
5 | sidekiq_options retry: false
6 |
7 | def execute(args)
8 | raise Discourse::InvalidParameters.new(:event_id) if args[:event_id].blank?
9 | event = DiscoursePostEvent::Event.find(args[:event_id])
10 | MessageBus.publish("/topic/#{event.post.topic_id}", reload_topic: true, refresh_stream: true)
11 | DiscourseEvent.trigger(:discourse_post_event_event_started, event)
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/event-field.gjs:
--------------------------------------------------------------------------------
1 | import { notEq } from "truth-helpers";
2 | import { i18n } from "discourse-i18n";
3 |
4 | const EventField =
5 | {{#if (notEq @enabled false)}}
6 |
7 | {{#if @label}}
8 |
9 | {{i18n @label}}
10 |
11 | {{/if}}
12 |
13 |
14 | {{yield}}
15 |
16 |
17 | {{/if}}
18 | ;
19 |
20 | export default EventField;
21 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/models/discourse-post-event-event-stats.js:
--------------------------------------------------------------------------------
1 | import { tracked } from "@glimmer/tracking";
2 |
3 | export default class DiscoursePostEventEventStats {
4 | static create(args = {}) {
5 | return new DiscoursePostEventEventStats(args);
6 | }
7 |
8 | @tracked going = 0;
9 | @tracked interested = 0;
10 | @tracked invited = 0;
11 | @tracked notGoing = 0;
12 |
13 | constructor(args = {}) {
14 | this.going = args.going;
15 | this.invited = args.invited;
16 | this.interested = args.interested;
17 | this.notGoing = args.not_going;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/config/locales/server.id.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | id:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Nama Pengguna
12 | discourse_calendar:
13 | invite_user_notification: "%{username} mengundang Anda ke: %{description}"
14 | discourse_post_event:
15 | errors:
16 | bulk_invite:
17 | error: "Terjadi kesalahan saat mengunggah file itu. Coba lagi nanti."
18 |
--------------------------------------------------------------------------------
/db/migrate/20231123233308_delete_duplicated_holidays.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DeleteDuplicatedHolidays < ActiveRecord::Migration[7.0]
4 | def up
5 | execute <<~SQL
6 | DELETE
7 | FROM calendar_events ce
8 | WHERE
9 | ce.id IN (SELECT ce2.id FROM calendar_events ce2
10 | INNER JOIN users ON users.id = ce2.user_id
11 | WHERE ce2.post_id IS NULL
12 | AND ce2.username != users.username)
13 | SQL
14 | end
15 |
16 | def down
17 | raise ActiveRecord::IrreversibleMigration
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/lib/calendar-locale.js:
--------------------------------------------------------------------------------
1 | import I18n, { i18n } from "discourse-i18n";
2 |
3 | export function getCurrentBcp47Locale() {
4 | return I18n.currentLocale().replace("_", "-").toLowerCase();
5 | }
6 |
7 | export function getCalendarButtonsText() {
8 | return {
9 | today: i18n("discourse_calendar.toolbar_button.today"),
10 | month: i18n("discourse_calendar.toolbar_button.month"),
11 | week: i18n("discourse_calendar.toolbar_button.week"),
12 | day: i18n("discourse_calendar.toolbar_button.day"),
13 | list: i18n("discourse_calendar.toolbar_button.list"),
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/vendor/holidays/test/integration/README.md:
--------------------------------------------------------------------------------
1 | # Integration tests
2 |
3 | These tests are dependent on the files in /definitions (and, by proxy, /lib/generated_definitions).
4 | It is possible that these tests will break because of 'unrelated' definition changes. The code
5 | behind these changes could still be good but since the definitions changed we could see failures.
6 |
7 | These are not unit tests. This is not testing whether specific internal code is working. These are
8 | tests from the consumer perspective. You must recognize that this could fail because of code
9 | changes unrelated to definition changes.
10 |
--------------------------------------------------------------------------------
/config/locales/server.pt.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | pt:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Nome de Utilizador
12 | discourse_automation:
13 | triggerables:
14 | event_started:
15 | title: Evento iniciado
16 | discourse_post_event:
17 | errors:
18 | bulk_invite:
19 | error: "Ocorreu um erro ao carregar esse ficheiro. Por favor tente mais tarde."
20 |
--------------------------------------------------------------------------------
/db/migrate/20200805073343_drop_old_discourse_calendar_tables.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "migration/table_dropper"
4 |
5 | class DropOldDiscourseCalendarTables < ActiveRecord::Migration[6.0]
6 | def up
7 | if table_exists?(:discourse_calendar_post_events)
8 | Migration::TableDropper.execute_drop(:discourse_calendar_post_events)
9 | end
10 |
11 | if table_exists?(:discourse_calendar_invitees)
12 | Migration::TableDropper.execute_drop(:discourse_calendar_invitees)
13 | end
14 | end
15 |
16 | def down
17 | raise ActiveRecord::IrrelversibleMigration
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/assets/stylesheets/common/discourse-post-event-preview.scss:
--------------------------------------------------------------------------------
1 | .discourse-post-event-preview {
2 | background: var(--secondary);
3 | align-items: center;
4 | flex-direction: column;
5 | padding: 0.5em;
6 | border: 1px solid var(--primary-low);
7 | display: flex;
8 | flex: 1 0 auto;
9 |
10 | .event-preview-status {
11 | margin: 0 0 0.5em 0;
12 | }
13 |
14 | .event-preview-dates {
15 | font-weight: 700;
16 | }
17 |
18 | &.alert-error {
19 | border-color: var(--danger-low-mid);
20 | }
21 | }
22 |
23 | .discourse-post-event-preview + .discourse-post-event-preview {
24 | margin-top: 1em;
25 | }
26 |
--------------------------------------------------------------------------------
/db/migrate/20200409102639_drop_incorrect_future_schema_migrations.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DropIncorrectFutureSchemaMigrations < ActiveRecord::Migration[5.2]
4 | def up
5 | execute <<-SQL
6 | DELETE FROM schema_migrations WHERE version = '20201303000001';
7 | DELETE FROM schema_migration_details WHERE version = '20201303000001';
8 | DELETE FROM schema_migrations WHERE version = '20201303000002';
9 | DELETE FROM schema_migration_details WHERE version = '20201303000002';
10 | SQL
11 | end
12 |
13 | def down
14 | raise ActiveRecord::IrreversibleMigration
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/db/migrate/20220604200919_create_disabled_holidays.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateDisabledHolidays < ActiveRecord::Migration[7.0]
4 | def change
5 | create_table :discourse_calendar_disabled_holidays do |t|
6 | t.string :holiday_name, null: false
7 | t.string :region_code, null: false
8 | t.boolean :disabled, null: false, default: true
9 |
10 | t.timestamps
11 | end
12 |
13 | add_index :discourse_calendar_disabled_holidays,
14 | %i[holiday_name region_code],
15 | name: "index_disabled_holidays_on_holiday_name_and_region_code"
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/config/locales/server.ko.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ko:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: 사용자명
12 | discourse_automation:
13 | triggerables:
14 | event_started:
15 | title: 이벤트 시작됨
16 | discourse_calendar:
17 | invite_user_notification: "%{username}님이 사용자님을 초대했습니다: %{description}"
18 | discourse_post_event:
19 | errors:
20 | bulk_invite:
21 | error: "해당 파일을 업로드하는 중에 오류가 발생했습니다. 나중에 다시 시도하십시오."
22 |
--------------------------------------------------------------------------------
/assets/stylesheets/mobile/discourse-post-event.scss:
--------------------------------------------------------------------------------
1 | .discourse-post-event {
2 | .discourse-post-event-widget {
3 | border-width: 1px;
4 | }
5 |
6 | .event-dates {
7 | .date {
8 | max-width: 75vw;
9 | }
10 | }
11 |
12 | .event-actions {
13 | .event-status {
14 | width: 100%;
15 | display: flex;
16 | justify-content: space-between;
17 |
18 | button {
19 | padding: 0 0.6em;
20 | height: 2.5em;
21 | }
22 | }
23 | }
24 |
25 | .event-invitees-status {
26 | font-size: var(--font-down-1);
27 | }
28 |
29 | .creators {
30 | .created-by {
31 | display: none;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_id.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/id.yaml
7 | class IdDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_id
10 | assert_equal "Chinese New Year", (Holidays.on(Date.civil(2025, 1, 29), [:id])[0] || {})[:name]
11 |
12 | assert_equal "Good Friday", (Holidays.on(Date.civil(2025, 4, 18), [:id])[0] || {})[:name]
13 |
14 | assert_equal "Ascension Day of Jesus Christ", (Holidays.on(Date.civil(2025, 5, 29), [:id])[0] || {})[:name]
15 |
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/routes/discourse-post-event-upcoming-events-index.js:
--------------------------------------------------------------------------------
1 | import { action } from "@ember/object";
2 | import { service } from "@ember/service";
3 | import DiscourseURL from "discourse/lib/url";
4 | import DiscourseRoute from "discourse/routes/discourse";
5 |
6 | export default class PostEventUpcomingEventsIndexRoute extends DiscourseRoute {
7 | @service discoursePostEventService;
8 |
9 | @action
10 | activate() {
11 | if (!this.siteSettings.discourse_post_event_enabled) {
12 | DiscourseURL.redirectTo("/404");
13 | }
14 | }
15 |
16 | async model(params) {
17 | return await this.discoursePostEventService.fetchEvents(params);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/db/migrate/20200409120815_rename_topic_custom_field_topic_post_event_starts_at_index.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class RenameTopicCustomFieldTopicPostEventStartsAtIndex < ActiveRecord::Migration[6.0]
4 | def up
5 | remove_index :topic_custom_fields, name: "idx_topic_custom_fields_post_event_starts_at"
6 |
7 | add_index :topic_custom_fields,
8 | %i[name topic_id],
9 | name: :idx_topic_custom_fields_topic_post_event_starts_at,
10 | unique: true,
11 | where: "name = '#{DiscoursePostEvent::TOPIC_POST_EVENT_STARTS_AT}'"
12 | end
13 |
14 | def down
15 | raise ActiveRecord::IrreversibleMigration
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/models/discourse-post-event-invitee.js:
--------------------------------------------------------------------------------
1 | import { tracked } from "@glimmer/tracking";
2 | import User from "discourse/models/user";
3 |
4 | export default class DiscoursePostEventInvitee {
5 | static create(args = {}) {
6 | return new DiscoursePostEventInvitee(args);
7 | }
8 |
9 | @tracked status;
10 |
11 | constructor(args = {}) {
12 | this.id = args.id;
13 | this.post_id = args.post_id;
14 | this.status = args.status;
15 | this.user = this.#initUserModel(args.user);
16 | }
17 |
18 | #initUserModel(user) {
19 | if (!user || user instanceof User) {
20 | return user;
21 | }
22 |
23 | return User.create(user);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/vendor/holidays/test/integration/test_custom_informal_holidays.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
2 |
3 | class CustomHolidaysTest < Test::Unit::TestCase
4 |
5 | def test_custom_region_informal_day_parsing
6 | Holidays.load_custom('test/data/test_custom_informal_holidays_defs.yaml')
7 |
8 | assert_not_equal [], Holidays.on(Date.new(2018,1,1), :custom_informal, :informal)
9 | assert_equal [], Holidays.on(Date.new(2018,1,1), :custom_informal, :observed)
10 |
11 | assert_not_equal [], Holidays.on(Date.new(2018,1,5), :custom_informal, :informal)
12 | assert_equal [], Holidays.on(Date.new(2018,1,5), :custom_informal, :observed)
13 | end
14 |
15 | end
16 |
--------------------------------------------------------------------------------
/lib/calendar_settings_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CalendarSettingsValidator
4 | def initialize(opts = {})
5 | @opts = opts
6 | end
7 |
8 | def valid_value?(val)
9 | return true if val == ""
10 |
11 | split = val.split(":")
12 | return false if split.count != 2
13 |
14 | hour = split.first
15 | return false if hour.length != 2
16 | return false if hour.to_i < 0 || hour.to_i >= 24
17 |
18 | minutes = split.second
19 | return false if minutes.length != 2
20 | return false if minutes.to_i < 0 || minutes.to_i >= 60
21 | true
22 | end
23 |
24 | def error_message
25 | I18n.t("site_settings.all_day_event_time_error")
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/db/migrate/20200409102641_create_invitees_table.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreateInviteesTable < ActiveRecord::Migration[5.2]
4 | def up
5 | unless ActiveRecord::Base.connection.table_exists?("discourse_calendar_invitees")
6 | create_table :discourse_calendar_invitees do |t|
7 | t.integer :post_id, null: false
8 | t.integer :user_id, null: false
9 | t.integer :status
10 | t.timestamps null: false
11 | t.boolean :notified, null: false, default: false
12 | end
13 |
14 | add_index :discourse_calendar_invitees, %i[post_id user_id], unique: true
15 | end
16 | end
17 |
18 | def down
19 | drop_table :discourse_calendar_invitees
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/doc/architecture/README.md:
--------------------------------------------------------------------------------
1 | # Architecture Decision Records
2 |
3 | Here we document decisions we made regarding high level architecture/design of this repository.
4 |
5 | For details on what ADR is and why it's important, please reference the following blog posts:
6 |
7 | - https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0
8 | - http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions
9 |
10 | Please note that we only began keeping ADRs for this project in October of 2018. Decisions made before that are not covered.
11 |
12 | ## Table of contents
13 |
14 | 1. [Language specific custom methods](adr-001.md)
15 | 1. [Year ranges syntax update](adr-002.md)
16 |
--------------------------------------------------------------------------------
/lib/group_timezones.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseCalendar
4 | class GroupTimezones
5 | def self.update(post)
6 | groups = []
7 |
8 | Nokogiri
9 | .HTML(post.cooked)
10 | .css("div.group-timezones")
11 | .map do |group_timezones|
12 | group_timezones.attributes.values.each do |attribute|
13 | if attribute.name == "data-group"
14 | group_name = CGI.escapeHTML(attribute.value || "")
15 | groups << group_name if group_name.present?
16 | end
17 | end
18 | end
19 |
20 | post.group_timezones = groups.present? ? { groups: groups } : nil
21 | post.save_custom_fields
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/core_extensions/time.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module CoreExtensions
3 | module Time
4 | def self.included(base)
5 | base.extend ClassMethods
6 | end
7 |
8 | module ClassMethods
9 | COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
10 |
11 | # Returns the number of days in the given month.
12 | # If no year is specified, it will use the current year.
13 | def days_in_month(month, year = current.year)
14 | if month == 2 && ::Date.gregorian_leap?(year)
15 | 29
16 | else
17 | COMMON_YEAR_DAYS_IN_MONTH[month]
18 | end
19 | end
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_single_custom_holiday_with_custom_procs.yaml:
--------------------------------------------------------------------------------
1 | months:
2 | 0:
3 | - name: Custom Holiday
4 | regions: [custom_single_file]
5 | function: custom_method(year, month)
6 | function_modifier: 5
7 | 6:
8 | - name: Company Founding
9 | regions: [custom_single_file]
10 | mday: 20
11 | methods:
12 | custom_method:
13 | arguments: year, month
14 | source: |
15 | d = Date.civil(year, month, 1)
16 | d + 2
17 |
18 | tests:
19 | - given:
20 | date: '2013-06-20'
21 | regions: [custom_single_file]
22 | expect:
23 | name: "Company Founding"
24 | - given:
25 | date: '2015-01-01'
26 | regions: [custom_single_file]
27 | expect:
28 | name: "Custom Holiday"
29 |
--------------------------------------------------------------------------------
/lib/calendar_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseCalendar
4 | class CalendarValidator
5 | def initialize(post)
6 | @post = post
7 | end
8 |
9 | def validate_calendar
10 | extracted_calendars = DiscourseCalendar::Calendar.extract(@post)
11 |
12 | return false if extracted_calendars.count == 0
13 |
14 | if extracted_calendars.count > 1
15 | @post.errors.add(:base, I18n.t("discourse_calendar.more_than_one_calendar"))
16 | return false
17 | end
18 |
19 | if !@post.is_first_post?
20 | @post.errors.add(:base, I18n.t("discourse_calendar.calendar_must_be_in_first_post"))
21 | return false
22 | end
23 |
24 | true
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/initializers/disable-sort.js:
--------------------------------------------------------------------------------
1 | import { withPluginApi } from "discourse/lib/plugin-api";
2 |
3 | export default {
4 | name: "disable-sort",
5 |
6 | initialize(container) {
7 | withPluginApi("0.8", (api) => {
8 | api.registerValueTransformer(
9 | "topic-list-header-sortable-column",
10 | ({ value, context }) => {
11 | if (!value) {
12 | return value;
13 | }
14 |
15 | const siteSettings = container.lookup("service:site-settings");
16 | return !(
17 | siteSettings.disable_resorting_on_categories_enabled &&
18 | context.category?.custom_fields?.disable_topic_resorting
19 | );
20 | }
21 | );
22 | });
23 | },
24 | };
25 |
--------------------------------------------------------------------------------
/db/migrate/20201110225115_create_post_event_dates_table.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreatePostEventDatesTable < ActiveRecord::Migration[6.0]
4 | def up
5 | create_table :discourse_calendar_post_event_dates do |t|
6 | t.integer :event_id
7 | t.datetime :starts_at
8 | t.datetime :ends_at
9 | t.integer :reminder_counter, default: 0
10 | t.datetime :event_will_start_sent_at
11 | t.datetime :event_started_sent_at
12 | t.datetime :finished_at
13 | t.timestamps
14 | end
15 | add_index :discourse_calendar_post_event_dates, :event_id
16 | add_index :discourse_calendar_post_event_dates, :finished_at
17 | end
18 |
19 | def down
20 | raise ActiveRecord::IrreversibleMigration
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/vendor/holidays/doc/REFERENCES:
--------------------------------------------------------------------------------
1 | === References
2 |
3 | We are eternally grateful to the following sources.
4 |
5 | ==== Date calculations
6 | * http://michaelthompson.org/technikos/holidays.php
7 |
8 | ==== Easter calculations
9 | * http://www.assa.org.au/edm.html
10 | * http://www.smart.net/~mmontes/ec-cal.html
11 | * https://github.com/Loyolny/when_easter - graciously allowed by Michał Nierebiński
12 |
13 | ==== World dates
14 | * http://www.un.org/geninfo/faq/factsheets/FS18.HTM
15 | * http://en.wikipedia.org/wiki/List_of_holidays_by_country
16 |
17 | Other sources for specific regions are noted in the definitions files themselves.
18 |
19 | If a commit sneaks past the maintainers without attribution then please, let us know immediately! It was entirely unintentional.
20 |
--------------------------------------------------------------------------------
/db/migrate/20190724181542_add_on_holiday_index.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddOnHolidayIndex < ActiveRecord::Migration[5.2]
4 | def up
5 | execute <<~SQL
6 | DELETE
7 | FROM user_custom_fields a
8 | USING user_custom_fields b
9 | WHERE a.name = 'on_holiday'
10 | AND a.name = b.name
11 | AND a.user_id = b.user_id
12 | AND a.id > b.id
13 | SQL
14 |
15 | add_index :user_custom_fields,
16 | %i[name user_id],
17 | unique: true,
18 | name: :idx_user_custom_fields_on_holiday,
19 | where: "name = 'on_holiday'"
20 | end
21 |
22 | def down
23 | remove_index :user_custom_fields, name: :idx_user_custom_fields_on_holiday
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/spec/lib/calendar_settings_validator_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 | require "rails_helper"
3 |
4 | describe CalendarSettingsValidator do
5 | def expect_invalid(val)
6 | expect(subject.valid_value?(val)).to eq(false)
7 | end
8 |
9 | def expect_valid(val)
10 | expect(subject.valid_value?(val)).to eq(true)
11 | end
12 |
13 | it "only allows valid HH:mm formats" do
14 | expect_invalid "markvanlan"
15 | expect_invalid "000:00"
16 | expect_invalid "00:000"
17 | expect_invalid "24:00"
18 | expect_invalid "00:60"
19 | expect_invalid "002:30"
20 |
21 | expect_valid ""
22 | expect_valid "00:00"
23 | expect_valid "23:00"
24 | expect_valid "00:59"
25 | expect_valid "23:59"
26 | expect_valid "06:40"
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/discourse-post-event/chat-channel.gjs:
--------------------------------------------------------------------------------
1 | import { LinkTo } from "@ember/routing";
2 | import { and } from "truth-helpers";
3 | import { optionalRequire } from "discourse/lib/utilities";
4 |
5 | const ChannelTitle = optionalRequire(
6 | "discourse/plugins/chat/discourse/components/channel-title"
7 | );
8 |
9 | const DiscoursePostEventChatChannel =
10 | {{#if (and @event.channel ChannelTitle)}}
11 |
17 | {{/if}}
18 | ;
19 |
20 | export default DiscoursePostEventChatChannel;
21 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/discourse-post-event/url.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@glimmer/component";
2 | import icon from "discourse/helpers/d-icon";
3 |
4 | export default class DiscoursePostEventUrl extends Component {
5 | get url() {
6 | return this.args.url.includes("://") || this.args.url.includes("mailto:")
7 | ? this.args.url
8 | : `https://${this.args.url}`;
9 | }
10 |
11 |
12 | {{#if @url}}
13 |
24 | {{/if}}
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/vendor/holidays/test/integration/test_available_regions.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
2 |
3 | class AvailableRegionsTests < Test::Unit::TestCase
4 | def setup
5 | @date = Date.civil(2008,1,1)
6 | end
7 |
8 | def test_available_regions_returns_array
9 | assert Holidays.available_regions.is_a?(Array)
10 | end
11 |
12 | def test_available_regions_returns_array_of_symbols
13 | Holidays.available_regions.each do |r|
14 | assert r.is_a?(Symbol)
15 | end
16 | end
17 |
18 | # This test might fail if we add new regions. Since this is an integration test
19 | # I am fine with that!
20 | def test_available_regions_returns_correct_number_of_regions
21 | assert_equal 258, Holidays.available_regions.count
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/admin-holidays-list.gjs:
--------------------------------------------------------------------------------
1 | import { i18n } from "discourse-i18n";
2 | import AdminHolidaysListItem from "./admin-holidays-list-item";
3 |
4 | const AdminHolidaysList =
5 |
6 |
7 |
8 | | {{i18n "discourse_calendar.date"}} |
9 | {{i18n "discourse_calendar.holiday"}} |
10 |
11 |
12 |
13 |
14 | {{#each @holidays as |holiday|}}
15 |
20 | {{/each}}
21 |
22 |
23 | ;
24 |
25 | export default AdminHolidaysList;
26 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_custom_year_range_holiday_defs.yaml:
--------------------------------------------------------------------------------
1 | months:
2 | 6:
3 | - name: after_year
4 | regions: [custom_year_range_file]
5 | mday: 1
6 | year_ranges:
7 | from: 2016
8 | - name: before_year
9 | regions: [custom_year_range_file]
10 | mday: 2
11 | year_ranges:
12 | until: 2017
13 | - name: between_year
14 | regions: [custom_year_range_file]
15 | mday: 3
16 | year_ranges:
17 | between:
18 | start: 2016
19 | end: 2018
20 | - name: limited_year
21 | regions: [custom_year_range_file]
22 | mday: 4
23 | year_ranges:
24 | limited: [2016,2018,2019]
25 |
26 | tests:
27 | - given:
28 | date: '2017-01-01'
29 | regions: [custom_year_range_file]
30 | expect:
31 | name: "after_year"
32 |
--------------------------------------------------------------------------------
/app/models/discourse_calendar/disabled_holiday.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseCalendar
4 | class DisabledHoliday < ActiveRecord::Base
5 | validates :holiday_name, presence: true
6 | validates :region_code, presence: true
7 | end
8 | end
9 |
10 | # == Schema Information
11 | #
12 | # Table name: discourse_calendar_disabled_holidays
13 | #
14 | # id :bigint not null, primary key
15 | # holiday_name :string not null
16 | # region_code :string not null
17 | # disabled :boolean default(TRUE), not null
18 | # created_at :datetime not null
19 | # updated_at :datetime not null
20 | #
21 | # Indexes
22 | #
23 | # index_disabled_holidays_on_holiday_name_and_region_code (holiday_name,region_code)
24 | #
25 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/lib/full-calendar-default-options.js:
--------------------------------------------------------------------------------
1 | import { escape } from "pretty-text/sanitizer";
2 | import {
3 | getCalendarButtonsText,
4 | getCurrentBcp47Locale,
5 | } from "./calendar-locale";
6 | import { buildPopover, destroyPopover } from "./popover";
7 |
8 | export default function fullCalendarDefaultOptions() {
9 | return {
10 | eventClick: function () {
11 | destroyPopover();
12 | },
13 | locale: getCurrentBcp47Locale(),
14 | buttonText: getCalendarButtonsText(),
15 | eventMouseEnter: function ({ event, jsEvent }) {
16 | destroyPopover();
17 |
18 | const htmlContent = escape(event.title);
19 | buildPopover(jsEvent, htmlContent);
20 | },
21 | eventMouseLeave: function () {
22 | destroyPopover();
23 | },
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/routes/discourse-post-event-upcoming-events-mine.gjs:
--------------------------------------------------------------------------------
1 | import { action } from "@ember/object";
2 | import { service } from "@ember/service";
3 | import DiscourseURL from "discourse/lib/url";
4 | import DiscourseRoute from "discourse/routes/discourse";
5 |
6 | export default class PostEventUpcomingEventsIndexRoute extends DiscourseRoute {
7 | @service discoursePostEventApi;
8 | @service discoursePostEventService;
9 | @service currentUser;
10 |
11 | @action
12 | activate() {
13 | if (!this.siteSettings.discourse_post_event_enabled) {
14 | DiscourseURL.redirectTo("/404");
15 | }
16 | }
17 |
18 | async model(params) {
19 | params.attending_user = this.currentUser?.username;
20 | return await this.discoursePostEventService.fetchEvents(params);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/serializers/discourse_post_event/invitee_list_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | class InviteeListSerializer < ApplicationSerializer
5 | root false
6 | attributes :meta
7 | has_many :invitees, serializer: InviteeSerializer, embed: :objects
8 |
9 | def invitees
10 | object[:invitees]
11 | end
12 |
13 | def meta
14 | {
15 | suggested_users:
16 | ActiveModel::ArraySerializer.new(
17 | suggested_users,
18 | each_serializer: BasicUserSerializer,
19 | scope: scope,
20 | ),
21 | }
22 | end
23 |
24 | def include_meta?
25 | suggested_users.present?
26 | end
27 |
28 | def suggested_users
29 | object[:suggested_users]
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_ae.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/ae.yaml
7 | class AeDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_ae
10 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2024, 1, 1), [:ae], [:informal])[0] || {})[:name]
11 |
12 | assert_equal "Commemoration Day", (Holidays.on(Date.civil(2024, 12, 1), [:ae], [:informal])[0] || {})[:name]
13 |
14 | assert_equal "National Day", (Holidays.on(Date.civil(2024, 12, 2), [:ae], [:informal])[0] || {})[:name]
15 |
16 | assert_equal "National Day (Day 2)", (Holidays.on(Date.civil(2024, 12, 3), [:ae], [:informal])[0] || {})[:name]
17 |
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/decorator/custom_method_proc.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Decorator
4 | class CustomMethodProc
5 | def call(proc)
6 | validate!(proc)
7 |
8 | eval("Proc.new { |#{parse_arguments(proc.arguments)}|
9 | #{proc.source}
10 | }")
11 | end
12 |
13 | private
14 |
15 | def validate!(proc)
16 | raise ArgumentError if proc.name.nil? || proc.name.empty?
17 | raise ArgumentError if proc.arguments.nil? || proc.arguments.empty?
18 | raise ArgumentError if proc.source.nil? || proc.source.empty?
19 | end
20 |
21 | def parse_arguments(args)
22 | a = args.join(", ")
23 | a[0..-1]
24 | end
25 | end
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/spec/lib/group_timezones_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe DiscourseCalendar::GroupTimezones do
6 | before do
7 | Jobs.run_immediately!
8 | SiteSetting.calendar_enabled = true
9 | end
10 |
11 | let(:calendar_post) { create_post(raw: '[timezones group="admins"]\n[/timezones]') }
12 |
13 | it "converts the Markdown to HTML" do
14 | expect(calendar_post.cooked.rstrip).to match_html(<<~HTML.rstrip)
15 |
18 | HTML
19 | end
20 |
21 | it "creates correct custom fields" do
22 | calendar_post.reload
23 | expect(calendar_post.has_group_timezones?).to eq(true)
24 | expect(calendar_post.group_timezones).to eq("groups" => ["admins"])
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/helpers/format-event-name.js:
--------------------------------------------------------------------------------
1 | import { i18n } from "discourse-i18n";
2 |
3 | function sameTimezoneOffset(timezone1, timezone2) {
4 | if (!timezone1 || !timezone2) {
5 | return false;
6 | }
7 |
8 | const offset1 = moment.tz(timezone1).utcOffset();
9 | const offset2 = moment.tz(timezone2).utcOffset();
10 | return offset1 === offset2;
11 | }
12 |
13 | export function formatEventName(event, userTimezone) {
14 | let output = event.name || event.post.topic.title;
15 |
16 | if (
17 | event.showLocalTime &&
18 | event.timezone &&
19 | !sameTimezoneOffset(event.timezone, userTimezone)
20 | ) {
21 | output +=
22 | ` (${i18n("discourse_calendar.local_time")}: ` +
23 | moment(event.startsAt).tz(event.timezone).format("H:mma") +
24 | ")";
25 | }
26 |
27 | return output;
28 | }
29 |
--------------------------------------------------------------------------------
/db/migrate/20200409102640_create_post_events_table.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class CreatePostEventsTable < ActiveRecord::Migration[5.2]
4 | def up
5 | unless ActiveRecord::Base.connection.table_exists?("discourse_calendar_post_events")
6 | create_table :discourse_calendar_post_events, id: false do |t|
7 | t.bigint :id, null: false, primary_key: true
8 | t.integer :status, default: 0, null: false
9 | t.integer :display_invitees, default: 0, null: false
10 | t.datetime :starts_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
11 | t.datetime :ends_at
12 | t.datetime :deleted_at
13 | t.string :raw_invitees, array: true
14 | t.string :name
15 | end
16 | end
17 | end
18 |
19 | def down
20 | drop_table :discourse_calendar_post_events
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/serializers/discourse_post_event/invitee_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | class InviteeSerializer < ApplicationSerializer
5 | attributes :id, :status, :user, :post_id, :meta
6 |
7 | def status
8 | object.status ? Invitee.statuses[object.status] : nil
9 | end
10 |
11 | def include_id?
12 | object.id
13 | end
14 |
15 | def user
16 | BasicUserSerializer.new(object.user, embed: :objects, root: false)
17 | end
18 |
19 | def meta
20 | {
21 | event_should_display_invitees:
22 | (object.event.public? && object.event.invitees.count > 0) ||
23 | (object.event.private? && object.event.raw_invitees.count > 0),
24 | event_stats: EventStatsSerializer.new(object.event, root: false),
25 | }
26 | end
27 | end
28 | end
29 |
--------------------------------------------------------------------------------
/app/services/discourse_calendar/holiday.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "holidays"
4 |
5 | module DiscourseCalendar
6 | class Holiday
7 | def self.find_holidays_for(
8 | region_code:,
9 | start_date: Date.current.beginning_of_year,
10 | end_date: Date.current.end_of_year,
11 | show_holiday_observed_on_dates: false
12 | )
13 | holidays =
14 | Holidays.between(
15 | start_date,
16 | end_date,
17 | [region_code],
18 | show_holiday_observed_on_dates ? :observed : [],
19 | )
20 |
21 | holidays.map do |holiday|
22 | holiday[:disabled] = DiscourseCalendar::DisabledHoliday.where(
23 | region_code: region_code,
24 | ).exists?(holiday_name: holiday[:name])
25 | end
26 |
27 | holidays
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/integration/topic_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe Topic do
6 | before do
7 | freeze_time
8 | Jobs.run_immediately!
9 | SiteSetting.calendar_enabled = true
10 | SiteSetting.discourse_post_event_enabled = true
11 | end
12 |
13 | let(:user) { Fabricate(:user, refresh_auto_groups: true) }
14 |
15 | context "when a topic is created" do
16 | context "with a date in title" do
17 | it "doesn’t create a post event" do
18 | post_with_date =
19 | PostCreator.create!(
20 | user,
21 | title: "Let’s buy a boat with me tomorrow",
22 | raw: "The boat market is quite active lately.",
23 | )
24 |
25 | expect(DiscoursePostEvent::Event).to_not exist(id: post_with_date.id)
26 | end
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/spec/requests/site_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe "calendar site additions" do
4 | let(:user) { Fabricate(:user) }
5 | let(:admin) { Fabricate(:admin) }
6 |
7 | before do
8 | SiteSetting.calendar_enabled = true
9 | DiscourseCalendar.users_on_holiday = [user.username]
10 | end
11 |
12 | it "includes users_on_holiday for staff only" do
13 | get "/site.json"
14 | expect(response.status).to eq(200)
15 | expect(response.parsed_body["users_on_holiday"]).to eq(nil)
16 |
17 | sign_in(user)
18 | get "/site.json"
19 | expect(response.status).to eq(200)
20 | expect(response.parsed_body["users_on_holiday"]).to eq(nil)
21 |
22 | sign_in(admin)
23 | get "/site.json"
24 | expect(response.status).to eq(200)
25 | expect(response.parsed_body["users_on_holiday"]).to eq([user.username])
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/spec/system/disable_sort_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe "Disabling topic list sorting", type: :system do
4 | fab!(:category)
5 | let(:category_page) { PageObjects::Pages::Category.new }
6 |
7 | before do
8 | SiteSetting.calendar_enabled = true
9 | Fabricate.times(2, :topic, category:)
10 | end
11 |
12 | it "disables the ability to sort topic list columns" do
13 | category_page.visit(category)
14 | expect(find("th.activity")).to match_selector(".sortable")
15 |
16 | category.custom_fields["disable_topic_resorting"] = true
17 | category.save!
18 | page.refresh
19 | expect(find("th.activity")).to match_selector(".sortable")
20 |
21 | SiteSetting.disable_resorting_on_categories_enabled = true
22 | page.refresh
23 | expect(find("th.activity")).to_not match_selector(".sortable")
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/spec/system/group_timezones_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe "Group timezones feature", type: :system do
4 | fab!(:group) { Fabricate(:group, name: "test-group") }
5 |
6 | fab!(:users) do
7 | Fabricate
8 | .times(5, :user)
9 | .each do |user|
10 | user.user_option.timezone = "America/New_York"
11 | user.user_option.save!
12 | group.add(user)
13 | end
14 | end
15 |
16 | before do
17 | Jobs.run_immediately!
18 | SiteSetting.calendar_enabled = true
19 | end
20 |
21 | let(:post) { create_post(raw: <<~RAW) }
22 | [timezones group="test-group"]
23 | [/timezones]
24 | RAW
25 |
26 | it "renders successfully" do
27 | visit(post.url)
28 | expect(page).to have_selector(".group-timezones")
29 | expect(page).to have_selector(".group-timezones-member", count: 5)
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/validator/custom_method.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Validator
4 | class CustomMethod
5 | VALID_ARGUMENTS = ["date", "year", "month", "day", "region"]
6 |
7 | def valid?(m)
8 | valid_name?(m[:name]) &&
9 | valid_arguments?(m[:arguments]) &&
10 | valid_source?(m[:source])
11 | end
12 |
13 | private
14 |
15 | def valid_name?(name)
16 | !name.nil? && !name.empty?
17 | end
18 |
19 | def valid_arguments?(arguments)
20 | arguments.split(",").all? { |arg|
21 | arg == arg.chomp && VALID_ARGUMENTS.include?(arg.strip)
22 | }
23 | end
24 |
25 | def valid_source?(source)
26 | !source.nil? && !source.empty?
27 | end
28 | end
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/discourse-post-event/creator.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@glimmer/component";
2 | import avatar from "discourse/helpers/avatar";
3 | import { formatUsername } from "discourse/lib/utilities";
4 | import { i18n } from "discourse-i18n";
5 |
6 | export default class DiscoursePostEventCreator extends Component {
7 | get username() {
8 | return this.args.user.name || formatUsername(this.args.user.username);
9 | }
10 |
11 |
12 |
13 | {{i18n "discourse_post_event.created_by"}}
14 |
15 |
16 |
17 | {{avatar @user imageSize="tiny"}}
18 | {{this.username}}
19 |
20 |
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/lib/colors.js:
--------------------------------------------------------------------------------
1 | // https://stackoverflow.com/a/16348977
2 | export function stringToColor(str) {
3 | let hash = 0;
4 | for (let i = 0; i < str.length; i++) {
5 | // eslint-disable-next-line no-bitwise
6 | hash = str.charCodeAt(i) + ((hash << 5) - hash);
7 | }
8 | let color = [];
9 | for (let i = 0; i < 3; i++) {
10 | // eslint-disable-next-line no-bitwise
11 | let value = (hash >> (i * 8)) & 0xff;
12 | color.push(value);
13 | }
14 | return color;
15 | }
16 |
17 | export function colorToHex(color) {
18 | let hex = "#";
19 | for (let i = 0; i < 3; i++) {
20 | hex += ("00" + Math.round(color[i]).toString(16)).slice(-2);
21 | }
22 | return hex;
23 | }
24 |
25 | export function contrastColor(color) {
26 | const luminance = 0.2126 * color[0] + 0.7152 * color[1] + 0.0722 * color[2];
27 | return luminance / 255 >= 0.5 ? "#000d" : "#fffd";
28 | }
29 |
--------------------------------------------------------------------------------
/config/locales/server.ro.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | ro:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: Nume de utilizator
12 | site_settings:
13 | map_events_title: "Suprascrie „Evenimente” în titlul barei laterale „Evenimente viitoare” pe categorie."
14 | sidebar_show_upcoming_events: "Afișează legătură evenimente viitoare în bara laterală sub „Mai multe”."
15 | include_expired_events_on_calendar: "Include evenimentele trecute sau expirate în vizualizările de calendar pe categorii și evenimente viitoare."
16 | discourse_post_event:
17 | errors:
18 | bulk_invite:
19 | error: "A apărut o eroare la încărcarea acestui fișier. Te rugăm să încerci din nou, mai târziu."
20 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/controllers/admin-plugins-calendar.js:
--------------------------------------------------------------------------------
1 | import Controller from "@ember/controller";
2 | import { action } from "@ember/object";
3 | import { ajax } from "discourse/lib/ajax";
4 | import { popupAjaxError } from "discourse/lib/ajax-error";
5 |
6 | export default class AdminPluginsCalendarController extends Controller {
7 | selectedRegion = null;
8 | loading = false;
9 |
10 | @action
11 | async getHolidays(region_code) {
12 | if (this.loading) {
13 | return;
14 | }
15 |
16 | this.set("selectedRegion", region_code);
17 | this.set("loading", true);
18 |
19 | return ajax(
20 | `/admin/discourse-calendar/holiday-regions/${region_code}/holidays`
21 | )
22 | .then((response) => {
23 | this.model.set("holidays", response.holidays);
24 | })
25 | .catch(popupAjaxError)
26 | .finally(() => this.set("loading", false));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/context/merger.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Context
4 | # Merge a new set of definitions into the Holidays module.
5 | class Merger
6 | def initialize(holidays_by_month_repo, regions_repo, custom_methods_repo)
7 | @holidays_repo = holidays_by_month_repo
8 | @regions_repo = regions_repo
9 | @custom_methods_repo = custom_methods_repo
10 | end
11 |
12 | def call(target_regions, target_holidays, target_custom_methods)
13 | #FIXME Does this need to come in this exact order? God I hope not.
14 | # If not then we should swap the order so it matches the init.
15 | @regions_repo.add(target_regions)
16 | @holidays_repo.add(target_holidays)
17 | @custom_methods_repo.add(target_custom_methods)
18 | end
19 | end
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/validator/region.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Validator
4 | class Region
5 | def initialize(regions_repo)
6 | @regions_repo = regions_repo
7 | end
8 |
9 | def valid?(r)
10 | return false unless r.is_a?(Symbol)
11 |
12 | region = find_wildcard_base(r)
13 |
14 | (region == :any ||
15 | @regions_repo.loaded?(region) ||
16 | @regions_repo.all_generated.include?(region))
17 | end
18 |
19 | private
20 |
21 | # Ex: :gb_ transformed to :gb
22 | def find_wildcard_base(region)
23 | r = region.to_s
24 |
25 | if r =~ /_$/
26 | base = r.split('_').first
27 | else
28 | base = r
29 | end
30 |
31 | base.to_sym
32 | end
33 | end
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/lib/add-recurrent-events.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 | import DiscoursePostEventEvent from "../models/discourse-post-event-event";
3 |
4 | export default function addRecurrentEvents(events) {
5 | try {
6 | return events.flatMap((event) => {
7 | if (!event.upcomingDates?.length) {
8 | return [event];
9 | }
10 |
11 | const upcomingEvents =
12 | event.upcomingDates?.map((upcomingDate) =>
13 | DiscoursePostEventEvent.create({
14 | name: event.name,
15 | post: event.post,
16 | category_id: event.categoryId,
17 | starts_at: upcomingDate.starts_at,
18 | ends_at: upcomingDate.ends_at,
19 | })
20 | ) || [];
21 |
22 | return upcomingEvents;
23 | });
24 | } catch (error) {
25 | console.error("Failed to retrieve events:", error);
26 | return [];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/vendor/holidays/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | holidays (8.4.1)
5 |
6 | GEM
7 | remote: https://rubygems.org/
8 | specs:
9 | coderay (1.1.3)
10 | docile (1.4.0)
11 | method_source (1.0.0)
12 | mocha (1.12.0)
13 | power_assert (2.0.0)
14 | pry (0.14.1)
15 | coderay (~> 1.1)
16 | method_source (~> 1.0)
17 | rake (12.3.3)
18 | simplecov (0.21.2)
19 | docile (~> 1.1)
20 | simplecov-html (~> 0.11)
21 | simplecov_json_formatter (~> 0.1)
22 | simplecov-html (0.12.3)
23 | simplecov_json_formatter (0.1.3)
24 | test-unit (3.4.2)
25 | power_assert
26 |
27 | PLATFORMS
28 | arm64-darwin-21
29 | arm64-darwin-22
30 | x86_64-linux
31 |
32 | DEPENDENCIES
33 | bundler (~> 2)
34 | holidays!
35 | mocha (~> 1)
36 | pry (~> 0.12)
37 | rake (~> 12)
38 | simplecov (~> 0.16)
39 | test-unit (~> 3)
40 |
41 | BUNDLED WITH
42 | 2.3.4
43 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_fed_ex.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/fedex.yaml
7 | class Fed_exDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_fed_ex
10 | {Date.civil(2015,1,1) => 'New Year\'s Day',
11 | Date.civil(2015,5,25) => 'Memorial Day',
12 | Date.civil(2015,7,4) => 'Independence Day',
13 | Date.civil(2015,9,7) => 'Labor Day',
14 | Date.civil(2015,11,26) => 'Thanksgiving',
15 | Date.civil(2015,11,27) => 'Day After Thanksgiving',
16 | Date.civil(2013,11,28) => 'Thanksgiving',
17 | Date.civil(2013,11,29) => 'Day After Thanksgiving',
18 | Date.civil(2015,12,25) => 'Christmas Day',
19 | Date.civil(2015,12,31) => 'New Year\'s Eve',}.each do |date, name|
20 | assert_equal name, (Holidays.on(date, :ups)[0] || {})[:name]
21 | end
22 |
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/lib/event_validator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseCalendar
4 | class EventValidator
5 | def initialize(post)
6 | @post = post
7 | @first_post = post.topic.first_post
8 | end
9 |
10 | def validate_event
11 | dates_count = count_dates(@post)
12 | calendar_type = @first_post.custom_fields[DiscourseCalendar::CALENDAR_CUSTOM_FIELD]
13 |
14 | if calendar_type == "dynamic" && dates_count > 2
15 | @post.errors.add(:base, I18n.t("discourse_calendar.more_than_two_dates"))
16 | return false
17 | end
18 |
19 | return false if calendar_type == "static" && dates_count > 0
20 |
21 | dates_count > 0
22 | end
23 |
24 | private
25 |
26 | def count_dates(post)
27 | cooked = PrettyText.cook(post.raw, topic_id: post.topic_id, user_id: post.user_id)
28 | Nokogiri.HTML(cooked).css("span.discourse-local-date").count
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/vendor/holidays/test/integration/test_nonstandard_regions.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | class NonstandardRegionsHolidaysTests < Test::Unit::TestCase
5 | def test_ecbtarget_christmas_day
6 | h = Holidays.on(Date.new(2018,12,25), :ecbtarget)
7 | assert_equal 'Christmas Day', h[0][:name]
8 | end
9 |
10 | def test_federalreserve_memorial_day
11 | h = Holidays.on(Date.new(2018,5,28), :federalreserve)
12 | assert_equal 'Memorial Day', h[0][:name]
13 |
14 | end
15 |
16 | def test_federalreservebanks_independence_day
17 | h = Holidays.on(Date.new(2019,7,4), :federalreservebanks, :observed)
18 | assert_equal 'Independence Day', h[0][:name]
19 | end
20 |
21 | def test_unitednations_international_day_of_families
22 | h = Holidays.on(Date.new(2021,5,15), :unitednations)
23 | assert_equal 'International Day of Families', h[0][:name]
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/decorator/custom_method_source.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Decorator
4 | class CustomMethodSource
5 | def call(proc)
6 | validate!(proc)
7 |
8 | method_name = proc.name
9 | args = args_string(proc.arguments)
10 | source = proc.source
11 |
12 | "\"#{method_name.to_s}(#{args})\" => Proc.new { |#{args}|\n#{source}}"
13 | end
14 |
15 | private
16 |
17 | def validate!(proc)
18 | raise ArgumentError if proc.name.nil? || proc.name == ""
19 | raise ArgumentError if proc.arguments.nil? || !proc.arguments.is_a?(Array) || proc.arguments.empty?
20 | raise ArgumentError if proc.source.nil? || proc.source == ""
21 | end
22 |
23 | def args_string(args)
24 | a = args.join(", ")
25 | a[0..-1]
26 | end
27 | end
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/spec/system/page_objects/discourse_calendar/post_event_form.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module PageObjects
4 | module Pages
5 | module DiscourseCalendar
6 | class PostEventForm < PageObjects::Pages::Base
7 | MODAL_SELECTOR = ".post-event-builder-modal"
8 |
9 | def fill_location(with)
10 | form.find(".event-field.location input").fill_in(with:)
11 | self
12 | end
13 |
14 | def fill_description(with)
15 | form.find(".event-field.description textarea").fill_in(with:)
16 | self
17 | end
18 |
19 | def form
20 | modal.find("form")
21 | end
22 |
23 | def modal
24 | find(MODAL_SELECTOR)
25 | end
26 |
27 | def submit
28 | modal.find(".d-modal__footer .btn-primary").click
29 | has_no_selector?(MODAL_SELECTOR)
30 | self
31 | end
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/finder/rules/in_region.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Finder
3 | module Rules
4 | class InRegion
5 | class << self
6 | def call(requested, available)
7 | return true if requested.include?(:any)
8 |
9 | # When an underscore is encountered, derive the parent regions
10 | # symbol and check for both.
11 | requested = requested.collect do |r|
12 | if r.to_s =~ /_/
13 | chunks = r.to_s.split('_')
14 |
15 | chunks.length.downto(1).map do |num|
16 | chunks[0..-num].join('_').to_sym
17 | end
18 | else
19 | r
20 | end
21 | end
22 |
23 | requested = requested.flatten.uniq
24 |
25 | available.any? { |avail| requested.include?(avail) }
26 | end
27 | end
28 | end
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/db/migrate/20231124021939_delete_similar_holidays.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class DeleteSimilarHolidays < ActiveRecord::Migration[7.0]
4 | def up
5 | execute <<~SQL
6 | DELETE
7 | FROM calendar_events ce
8 | WHERE
9 | ce.id IN (SELECT DISTINCT(ce3.id) FROM calendar_events ce2
10 | LEFT JOIN calendar_events ce3 ON ce3.user_id = ce2.user_id AND ce3.description = ce2.description
11 | WHERE ce2.start_date >= (ce3.start_date - INTERVAL '1 days')
12 | AND ce2.start_date <= (ce3.start_date + INTERVAL '1 days')
13 | AND ce2.timezone IS NOT NULL
14 | AND ce3.timezone IS NULL
15 | AND ce3.id != ce2.id
16 | AND ce2.post_id IS NULL
17 | AND ce3.post_id IS NULL
18 | )
19 | SQL
20 | end
21 |
22 | def down
23 | raise ActiveRecord::IrreversibleMigration
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/repository/custom_methods.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Repository
4 | class CustomMethods
5 | def initialize
6 | @custom_methods = {}
7 | end
8 |
9 | # This performs a merge that overwrites any conflicts.
10 | # While this is not ideal I'm leaving it as-is since I have no
11 | # evidence of any current definitions that will cause an issue.
12 | #
13 | # FIXME: this should probably return an error if a method with the
14 | # same ID already exists.
15 | def add(new_custom_methods)
16 | raise ArgumentError if new_custom_methods.nil?
17 | @custom_methods.merge!(new_custom_methods)
18 | end
19 |
20 | def find(method_id)
21 | raise ArgumentError if method_id.nil? || method_id.empty?
22 | @custom_methods[method_id]
23 | end
24 | end
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/db/migrate/20221121165352_add_type_field_to_events_reminders.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class AddTypeFieldToEventsReminders < ActiveRecord::Migration[7.0]
4 | def up
5 | reminders_query = <<~SQL
6 | SELECT id, reminders
7 | FROM discourse_post_event_events
8 | WHERE reminders IS NOT NULL
9 | SQL
10 |
11 | DB
12 | .query(reminders_query)
13 | .each do |event|
14 | refactored_reminders = []
15 | event
16 | .reminders
17 | .split(",") { |reminder| refactored_reminders.push(reminder.prepend("notification.")) }
18 |
19 | event_reminders = refactored_reminders.join(",")
20 |
21 | DB.exec(<<~SQL, id: event.id, reminders: event_reminders)
22 | UPDATE discourse_post_event_events
23 | SET reminders = :reminders
24 | WHERE id = :id
25 | SQL
26 | end
27 | end
28 |
29 | def down
30 | raise ActiveRecord::IrreversibleMigration
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/vendor/holidays/test/holidays/date_calculator/test_day_of_month.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../../test_helper'
2 |
3 | require 'holidays/date_calculator/day_of_month'
4 |
5 | class DayOfMonthDateCalculatorTests < Test::Unit::TestCase
6 | def setup
7 | @subject = Holidays::DateCalculator::DayOfMonth.new
8 | end
9 |
10 | def test_call_returns_expected_results
11 | assert_equal 7, @subject.call(2008, 1, :first, :monday)
12 | assert_equal 18, @subject.call(2008, 12, :third, :thursday)
13 | assert_equal 28, @subject.call(2008, 1, :last, 1)
14 | end
15 |
16 | def test_returns_argument_error_with_invalid_week_parameter
17 | assert_raises ArgumentError do
18 | @subject.call(2008, 1, :wrong_week_argument, :monday)
19 | end
20 | end
21 |
22 | def test_returns_argument_error_with_invalid_day_parameter
23 | assert_raises ArgumentError do
24 | @subject.call(2008, 1, :first, :bad_wday)
25 | end
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/.discourse-compatibility:
--------------------------------------------------------------------------------
1 | < 3.5.0.beta5-dev: bd6e30721474e16d09d1a55adb11cfaf70947837
2 | < 3.5.0.beta3-dev: 8d09cf8503b78f4c72b47a7319c0f4b9ad0247e7
3 | < 3.5.0.beta2-dev: c1031224a552ea01958d153350c2d1254b323579
4 | < 3.5.0.beta1-dev: fdf3ad927744a9dbb826cc46e489cca8ad469044
5 | < 3.4.0.beta2-dev: 5f6942c1f3616d43eec18a71d76baa0e55e1340b
6 | < 3.4.0.beta1-dev: 908ad614bc412f831f929ca726a4bda0b9ccaab6
7 | < 3.3.0.beta2-dev: 455eeed541a9b5cacf627349e543028427178a44
8 | < 3.3.0.beta1-dev: 84ef46a38cf02748ecacad16c5d9c6fec12dc8da
9 | < 3.2.0.beta3-dev: 513a92b59dd80e79cc39fe6d8eb084ce7f5db5a7
10 | < 3.2.0.beta2: 6222eec8fc0e61971f4fa4939b39cf9247201c33
11 | 3.1.0.beta3: 10077ca904956005f9fa83c3d9fb124b59e8c47b
12 | 2.9.0.beta13: b4c366b35d6f9778e54a878aa083348e8a45e86e
13 | 2.9.0.beta9: 6f16ae10dc0306d6e1369e0d1414416d7e72141d
14 | 2.9.0.beta7: ec34a96f215dce9c7321dfe04f6dd0172a197711
15 | 2.9.0.beta3: 9ab1b76a1425304f3434b49db49cb4eec8919cf6
16 | 2.7.0.beta3: 52e22b9972dc79c67f6a2f7c4c9f918307222030
17 |
--------------------------------------------------------------------------------
/spec/integration/curently_away_report_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe "currently_away report" do
4 | fab!(:user_1) { Fabricate(:user) }
5 | fab!(:user_2) { Fabricate(:user) }
6 | fab!(:group_1) { Fabricate(:group) }
7 |
8 | before { group_1.add(user_1) }
9 |
10 | context "when users_on_holiday is not set" do
11 | it "does not generate report with data" do
12 | report = Report.find("currently_away", filters: { group: group_1.id })
13 |
14 | expect(report.data).to eq([])
15 | expect(report.total).to eq(0)
16 | end
17 | end
18 |
19 | context "when users_on_holiday is set" do
20 | before { DiscourseCalendar.users_on_holiday = [user_1.username] }
21 |
22 | it "generates a correct report" do
23 | report = Report.find("currently_away", filters: { group: group_1.id })
24 |
25 | expect(report.data).to contain_exactly({ username: user_1.username })
26 | expect(report.total).to eq(1)
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/holiday_status.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseCalendar
4 | class HolidayStatus
5 | def self.set!(user, ends_at)
6 | status = user.user_status
7 | if status.blank? || status.expired? ||
8 | (is_holiday_status?(status) && status.ends_at != ends_at)
9 | user.set_status!(
10 | I18n.t("discourse_calendar.holiday_status.description"),
11 | emoji_name,
12 | ends_at,
13 | )
14 | end
15 | end
16 |
17 | def self.clear!(user)
18 | user.clear_status! if user&.user_status && is_holiday_status?(user.user_status)
19 | end
20 |
21 | private
22 |
23 | def self.is_holiday_status?(status)
24 | status.emoji == emoji_name &&
25 | status.description == I18n.t("discourse_calendar.holiday_status.description")
26 | end
27 |
28 | def self.emoji_name
29 | emoji = SiteSetting.holiday_status_emoji
30 | emoji.blank? ? "date" : emoji
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_vi.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/vi.yaml
7 | class ViDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_vi
10 | assert_equal "Tết dương lịch", (Holidays.on(Date.civil(2014, 1, 1), [:vi])[0] || {})[:name]
11 |
12 | assert_equal "Ngày Giải phóng miền Nam, thống nhất đất nước", (Holidays.on(Date.civil(2014, 4, 30), [:vi])[0] || {})[:name]
13 |
14 | assert_equal "Ngày Quốc tế Lao động", (Holidays.on(Date.civil(2014, 5, 1), [:vi])[0] || {})[:name]
15 |
16 | assert_equal "Quốc khánh", (Holidays.on(Date.civil(2014, 9, 2), [:vi])[0] || {})[:name]
17 |
18 | assert_equal "Giỗ tổ Hùng Vương", (Holidays.on(Date.civil(2017, 4, 6), [:vi])[0] || {})[:name]
19 | assert_equal "Giỗ tổ Hùng Vương", (Holidays.on(Date.civil(2018, 3, 27), [:vi])[0] || {})[:name]
20 |
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/decorator/test.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Decorator
4 | class Test
5 | def call(t)
6 | src = ""
7 |
8 | t.dates.each do |d|
9 | date = "Date.civil(#{d.year}, #{d.month}, #{d.day})"
10 |
11 | holiday_call = "Holidays.on(#{date}, #{t.regions}"
12 |
13 | if t.options
14 | holiday_call += ", #{decorate_options(t.options)}"
15 | end
16 |
17 | if t.holiday?
18 | src += "assert_equal \"#{t.name}\", (#{holiday_call})[0] || {})[:name]\n"
19 | else
20 | src += "assert_nil (#{holiday_call})[0] || {})[:name]\n"
21 | end
22 | end
23 |
24 | src
25 | end
26 |
27 | private
28 |
29 | def decorate_options(options)
30 | options.map do |o|
31 | o.to_sym
32 | end
33 | end
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/discourse_calendar/site_settings/map_events_title_json_schema.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseCalendar
4 | module SiteSettings
5 | class MapEventsTitleJsonSchema
6 | def self.schema
7 | @schema ||= {
8 | type: "array",
9 | uniqueItems: true,
10 | items: {
11 | type: "object",
12 | title: "Title Mapping",
13 | properties: {
14 | category_slug: {
15 | type: "string",
16 | description: "Slug of the category",
17 | },
18 | custom_title: {
19 | type: "string",
20 | default: "Upcoming events",
21 | description:
22 | "The words you want to replace 'Upcoming Events' with for the sidebar calendar",
23 | },
24 | },
25 | required: %w[category_slug custom_title],
26 | },
27 | }
28 | end
29 | end
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/assets/stylesheets/common/discourse-post-event-bulk-invite-modal.scss:
--------------------------------------------------------------------------------
1 | .post-event-bulk-invite {
2 | .bulk-event-help {
3 | margin: 0 0 1em 0;
4 | }
5 |
6 | .bulk-invite-rows {
7 | margin-bottom: 1em;
8 |
9 | .group-selector {
10 | margin: 0;
11 | }
12 | }
13 |
14 | .bulk-invite-row {
15 | display: flex;
16 | padding: 0.25em 0;
17 |
18 | .bulk-invite-attendance {
19 | margin: 0 0.5em;
20 |
21 | .select-kit-header {
22 | height: 100%;
23 | }
24 | }
25 |
26 | .remove-bulk-invite {
27 | margin-left: auto;
28 | }
29 | }
30 |
31 | .bulk-invites {
32 | margin-bottom: 2em;
33 |
34 | .bulk-invite-actions {
35 | display: flex;
36 |
37 | .add-bulk-invite {
38 | margin-left: auto;
39 | }
40 | }
41 | }
42 |
43 | .csv-bulk-invites {
44 | .bulk-invite-actions {
45 | display: flex;
46 |
47 | > :last-child {
48 | margin-left: 0.5em;
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/assets/stylesheets/mobile/discourse-calendar.scss:
--------------------------------------------------------------------------------
1 | .discourse-calendar-wrap {
2 | border: 0;
3 |
4 | .discourse-calendar-header {
5 | padding: 0;
6 | background: none;
7 |
8 | h2.discourse-calendar-title {
9 | font-size: var(--font-0);
10 | flex-wrap: nowrap;
11 | max-width: 75%;
12 | white-space: nowrap;
13 | text-overflow: ellipsis;
14 | overflow: hidden;
15 | }
16 |
17 | .discourse-calendar-timezone-picker {
18 | max-width: 40vw;
19 | }
20 | }
21 |
22 | .fc-view-container {
23 | .fc-day-header.fc-widget-header {
24 | text-align: center;
25 | padding: 0.25em;
26 |
27 | span {
28 | font-size: var(--font-down-1);
29 | text-align: center;
30 | padding: 0;
31 | }
32 | }
33 | }
34 |
35 | .calendar {
36 | padding: 0;
37 |
38 | .fc-list-item-add-to-calendar {
39 | display: block;
40 | }
41 |
42 | &.fc-unthemed .fc-header-toolbar {
43 | padding: 0.5em 0;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/context/load.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Context
4 | class Load
5 | def initialize(definition_merger, full_definitions_path)
6 | @definition_merger = definition_merger
7 | @full_definitions_path = full_definitions_path
8 | end
9 |
10 | def call(region)
11 | region_definition_file = "#{@full_definitions_path}/#{region}"
12 | require region_definition_file
13 |
14 | target_region_module = Module.const_get("Holidays").const_get(region.upcase)
15 |
16 | @definition_merger.call(
17 | region,
18 | target_region_module.holidays_by_month,
19 | target_region_module.custom_methods,
20 | )
21 |
22 | target_region_module.defined_regions
23 | rescue NameError, LoadError => e
24 | raise UnknownRegionError.new(e), "Could not load region prefix: #{region.to_s}"
25 | end
26 | end
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/config/locales/client.sr.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sr:
8 | js:
9 | discourse_automation:
10 | triggerables:
11 | event_started:
12 | fields:
13 | topic_id:
14 | label: ID Teme
15 | discourse_calendar:
16 | disable_holiday: "Onemogući"
17 | enable_holiday: "Omogući"
18 | region:
19 | none: "Ništa"
20 | toolbar_button:
21 | today: "Danas"
22 | month: "Mesec"
23 | week: "Nedelja"
24 | discourse_post_event:
25 | builder_modal:
26 | update: "Sačuvaj"
27 | reminders:
28 | units:
29 | days: "dana"
30 | periods:
31 | before: "pre"
32 | url:
33 | label: "URL"
34 | location:
35 | label: "Lokacija"
36 | description:
37 | label: "Opis"
38 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/initializers/add-upcoming-events-to-sidebar.js:
--------------------------------------------------------------------------------
1 | import { withPluginApi } from "discourse/lib/plugin-api";
2 | import { i18n } from "discourse-i18n";
3 |
4 | export default {
5 | name: "add-upcoming-events-to-sidebar",
6 |
7 | initialize(container) {
8 | const siteSettings = container.lookup("service:site-settings");
9 | if (
10 | siteSettings.discourse_post_event_enabled &&
11 | siteSettings.sidebar_show_upcoming_events
12 | ) {
13 | withPluginApi("0.8.7", (api) => {
14 | api.addCommunitySectionLink((baseSectionLink) => {
15 | return class UpcomingEventsSectionLink extends baseSectionLink {
16 | name = "upcoming-events";
17 | route = "discourse-post-event-upcoming-events";
18 | text = i18n("discourse_post_event.upcoming_events.title");
19 | title = i18n("discourse_post_event.upcoming_events.title");
20 | defaultPrefixValue = "calendar-day";
21 | };
22 | });
23 | });
24 | }
25 | },
26 | };
27 |
--------------------------------------------------------------------------------
/spec/integration/invitee_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe DiscoursePostEvent::Invitee do
6 | before do
7 | freeze_time
8 | Jobs.run_immediately!
9 | SiteSetting.calendar_enabled = true
10 | SiteSetting.discourse_post_event_enabled = true
11 | end
12 |
13 | let(:user) { Fabricate(:user, admin: true) }
14 | let(:user_1) { Fabricate(:user) }
15 | let(:topic) { Fabricate(:topic, user: user) }
16 | let(:post1) { Fabricate(:post, topic: topic) }
17 | let(:post_event) { Fabricate(:event, post: post1) }
18 |
19 | context "when a user is destroyed" do
20 | context "when the user is an invitee to an event" do
21 | before { post_event.create_invitees([{ user_id: user_1.id, status: nil }]) }
22 |
23 | it "destroys the invitee" do
24 | expect(post_event.invitees.first.user.id).to eq(user_1.id)
25 |
26 | UserDestroyer.new(user_1).destroy(user_1)
27 |
28 | expect(post_event.invitees).to be_empty
29 | end
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/test/javascripts/acceptance/sort-event-topics-test.js:
--------------------------------------------------------------------------------
1 | import { visit } from "@ember/test-helpers";
2 | import { test } from "qunit";
3 | import Site from "discourse/models/site";
4 | import { acceptance } from "discourse/tests/helpers/qunit-helpers";
5 |
6 | acceptance("Calendar - Disable sorting headers", function (needs) {
7 | needs.user();
8 | needs.settings({
9 | calendar_enabled: true,
10 | discourse_post_event_enabled: true,
11 | disable_resorting_on_categories_enabled: true,
12 | });
13 |
14 | test("visiting a category page", async function (assert) {
15 | const site = Site.current();
16 | site.categories[15].custom_fields = { disable_topic_resorting: true };
17 |
18 | await visit("/c/bug");
19 | assert.dom(".topic-list").exists("The list of topics was rendered");
20 | assert
21 | .dom(".topic-list .topic-list-data")
22 | .exists("The headers were rendered");
23 | assert
24 | .dom(".topic-list")
25 | .doesNotHaveClass("sortable", "The headers are not sortable");
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/lib/validation/definition_validator.rb:
--------------------------------------------------------------------------------
1 | require_relative 'error'
2 |
3 | module Definitions
4 | module Validation
5 | class Definition
6 | def initialize(custom_method_validator, months_validator, test_validator)
7 | @custom_method_validator = custom_method_validator
8 | @months_validator = months_validator
9 | @test_validator = test_validator
10 | end
11 |
12 | def call(definition)
13 | validate_months!(definition['months'])
14 | validate_methods!(definition['methods'])
15 | validate_tests!(definition['tests'])
16 |
17 | true
18 | end
19 |
20 | private
21 |
22 | def validate_months!(months)
23 | @months_validator.call(months)
24 | end
25 |
26 | def validate_methods!(methods)
27 | @custom_method_validator.call(methods) unless methods.nil?
28 | end
29 |
30 | def validate_tests!(tests)
31 | @test_validator.call(tests) unless tests.nil?
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/initializers/event-relative-date.js:
--------------------------------------------------------------------------------
1 | import { cancel } from "@ember/runloop";
2 | import { isTesting } from "discourse/lib/environment";
3 | import discourseLater from "discourse/lib/later";
4 | import eventRelativeDate from "../lib/event-relative-date";
5 |
6 | function computeRelativeEventDates() {
7 | document
8 | .querySelectorAll(".event-relative-date.topic-list")
9 | .forEach((dateContainer) => eventRelativeDate(dateContainer));
10 | }
11 |
12 | export default {
13 | name: "event-future-date",
14 |
15 | initialize() {
16 | computeRelativeEventDates();
17 |
18 | if (!isTesting()) {
19 | this._tick();
20 | }
21 | },
22 |
23 | teardown() {
24 | if (this._interval) {
25 | cancel(this._interval);
26 | this._interval = null;
27 | }
28 | },
29 |
30 | _tick() {
31 | this._interval && cancel(this._interval);
32 |
33 | this._interval = discourseLater(() => {
34 | computeRelativeEventDates();
35 | this._tick();
36 | }, 60 * 1000);
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/spec/system/category_calendar_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe "Category calendar", type: :system do
4 | fab!(:admin)
5 | fab!(:category)
6 |
7 | let(:category_page) { PageObjects::Pages::Category.new }
8 |
9 | before do
10 | SiteSetting.calendar_enabled = true
11 | SiteSetting.discourse_post_event_enabled = true
12 | SiteSetting.events_calendar_categories = category.id.to_s
13 | sign_in(admin)
14 | end
15 |
16 | it "shows the calendar on the category page" do
17 | category_page.visit(category)
18 |
19 | expect(category_page).to have_selector("#category-events-calendar.fc")
20 |
21 | find(".nav-item_hot").click
22 |
23 | expect(page).to have_current_path("#{category.relative_url}/l/hot")
24 | expect(category_page).to have_selector("#category-events-calendar.fc")
25 |
26 | find(".nav-item_latest").click
27 |
28 | expect(page).to have_current_path("#{category.relative_url}/l/latest")
29 | expect(category_page).to have_selector("#category-events-calendar.fc")
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/app/serializers/discourse_post_event/event_stats_serializer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | class EventStatsSerializer < ApplicationSerializer
5 | attributes :going
6 | attributes :interested
7 | attributes :not_going
8 | attributes :invited
9 |
10 | def invited
11 | unanswered = counts[nil] || 0
12 |
13 | # when a group is private we know the list of possible users
14 | # even if an invitee has not been created yet
15 | unanswered += object.missing_users.count if object.private?
16 |
17 | going + interested + not_going + unanswered
18 | end
19 |
20 | def going
21 | @going ||= counts[Invitee.statuses[:going]] || 0
22 | end
23 |
24 | def interested
25 | @interested ||= counts[Invitee.statuses[:interested]] || 0
26 | end
27 |
28 | def not_going
29 | @not_going ||= counts[Invitee.statuses[:not_going]] || 0
30 | end
31 |
32 | def counts
33 | @counts ||= object.invitees.group(:status).count
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/lib/validation/custom_method_validator.rb:
--------------------------------------------------------------------------------
1 | require_relative 'error'
2 |
3 | module Definitions
4 | module Validation
5 | class CustomMethod
6 | VALID_ARGUMENTS = ["date", "year", "month", "day"]
7 |
8 | def call(methods)
9 | methods.each do |name, method|
10 | raise Errors::InvalidCustomMethod unless
11 | valid_name?(name) &&
12 | valid_arguments?(method['arguments']) &&
13 | valid_source?(method['ruby'])
14 | end
15 |
16 | true
17 | end
18 |
19 | private
20 |
21 | def valid_name?(name)
22 | !name.nil? && !name.empty?
23 | end
24 |
25 | def valid_arguments?(arguments)
26 | !arguments.nil? &&
27 | !arguments.empty? &&
28 | arguments.split(",").all? { |arg|
29 | arg == arg.chomp && VALID_ARGUMENTS.include?(arg.strip)
30 | }
31 | end
32 |
33 | def valid_source?(source)
34 | !source.nil? && !source.empty?
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/vendor/holidays/test/holidays/definition/context/test_merger.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../../../test_helper'
2 |
3 | require 'holidays/definition/context/merger'
4 |
5 | class MergerTests < Test::Unit::TestCase
6 | def setup
7 | @target_regions = [:new_region]
8 | @target_holidays = {0 => [:mday => 1, :name => "Test", :regions => [:test2, :test]]}
9 | @target_custom_methods = {"test_method" => Proc.new { |year| Date.civil(year, 1, 1) } }
10 |
11 | @holidays_repo = mock()
12 | @regions_repo = mock()
13 | @custom_methods_repo = mock()
14 |
15 | @subject = Holidays::Definition::Context::Merger.new(@holidays_repo, @regions_repo, @custom_methods_repo)
16 | end
17 |
18 | def test_repos_are_called_to_add_regions_and_holidays
19 | @holidays_repo.expects(:add).with(@target_holidays)
20 | @regions_repo.expects(:add).with(@target_regions)
21 | @custom_methods_repo.expects(:add).with(@target_custom_methods)
22 |
23 | @subject.call(@target_regions, @target_holidays, @target_custom_methods)
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/lib/popover.js:
--------------------------------------------------------------------------------
1 | import { createPopper } from "@popperjs/core";
2 |
3 | let eventPopper;
4 | const EVENT_POPOVER_ID = "event-popover";
5 |
6 | export function buildPopover(jsEvent, htmlContent) {
7 | const node = document.createElement("div");
8 | node.setAttribute("id", EVENT_POPOVER_ID);
9 | node.innerHTML = htmlContent;
10 |
11 | const arrow = document.createElement("span");
12 | arrow.dataset.popperArrow = true;
13 | node.appendChild(arrow);
14 | document.body.appendChild(node);
15 |
16 | eventPopper = createPopper(
17 | jsEvent.target,
18 | document.getElementById(EVENT_POPOVER_ID),
19 | {
20 | placement: "bottom",
21 | modifiers: [
22 | {
23 | name: "arrow",
24 | },
25 | {
26 | name: "offset",
27 | options: {
28 | offset: [20, 10],
29 | },
30 | },
31 | ],
32 | }
33 | );
34 | }
35 |
36 | export function destroyPopover() {
37 | eventPopper?.destroy();
38 | document.getElementById(EVENT_POPOVER_ID)?.remove();
39 | }
40 |
--------------------------------------------------------------------------------
/vendor/holidays/test/coverage_report.rb:
--------------------------------------------------------------------------------
1 | require 'simplecov'
2 |
3 | # For reasons I don't understand jruby implementations report lower coverage
4 | # than other ruby versions. Ruby 2.5.3, for instance, is at 92%.
5 | #
6 | # We set the floor based on jruby so that all automated tests pass on Travis CI.
7 | SimpleCov.minimum_coverage 89
8 |
9 | SimpleCov.add_filter [
10 | # Apparently simplecov doesn't automatically filter 'spec' or 'test' so we
11 | # have to do it manually.
12 | 'test',
13 |
14 | # Only filtered because I tend to not see value in testing factories.
15 | 'lib/holidays/factory/',
16 |
17 | # jruby coverage flips out here and doesn't count much of the large date
18 | # arrays used by this class. This results in an extremely low reported
19 | # coverage for this specific file but only in jruby, not other ruby versions.
20 | # Since it obliterates coverage percentages I'll filter it until I can come
21 | # up with a solution.
22 | 'lib/holidays/date_calculator/lunar_date.rb',
23 | ]
24 |
25 | SimpleCov.coverage_dir 'reports/coverage'
26 | SimpleCov.start
27 |
--------------------------------------------------------------------------------
/spec/serializers/user_serializer_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe UserSerializer do
4 | fab!(:user)
5 |
6 | subject(:json) { described_class.new(user, scope: guardian).as_json }
7 |
8 | before do
9 | SiteSetting.calendar_enabled = true
10 | user.upsert_custom_fields(DiscourseCalendar::REGION_CUSTOM_FIELD => "uk")
11 | end
12 |
13 | context "as another user" do
14 | fab!(:guardian) { Fabricate(:user).guardian }
15 |
16 | it "does not return user region" do
17 | expect(json[:user][:custom_fields]).to be_blank
18 | end
19 | end
20 |
21 | context "as current user" do
22 | fab!(:guardian) { user.guardian }
23 |
24 | it "returns user region" do
25 | expect(json[:user][:custom_fields]).to eq(DiscourseCalendar::REGION_CUSTOM_FIELD => "uk")
26 | end
27 | end
28 |
29 | context "as staff" do
30 | fab!(:guardian) { Fabricate(:admin).guardian }
31 |
32 | it "returns user region" do
33 | expect(json[:user][:custom_fields]).to eq(DiscourseCalendar::REGION_CUSTOM_FIELD => "uk")
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/api-initializers/discourse-group-timezones.gjs:
--------------------------------------------------------------------------------
1 | import { apiInitializer } from "discourse/lib/api";
2 | import GroupTimezones from "../components/group-timezones";
3 |
4 | const GroupTimezonesShim =
5 |
10 | ;
11 |
12 | export default apiInitializer((api) => {
13 | api.decorateCookedElement((element, helper) => {
14 | element.querySelectorAll(".group-timezones").forEach((el) => {
15 | const post = helper.getModel();
16 |
17 | if (!post) {
18 | return;
19 | }
20 |
21 | const group = el.dataset.group;
22 | if (!group) {
23 | throw new Error(
24 | "Group timezone element is missing 'data-group' attribute"
25 | );
26 | }
27 |
28 | helper.renderGlimmer(el, GroupTimezonesShim, {
29 | group,
30 | members: (post.group_timezones || {})[group] || [],
31 | size: el.dataset.size || "medium",
32 | });
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/generated_definitions/vi.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | module Holidays
3 | # This file is generated by the Ruby Holidays gem.
4 | #
5 | # Definitions loaded: definitions/vi.yaml
6 | #
7 | # All the definitions are available at https://github.com/holidays/holidays
8 | module VI # :nodoc:
9 | def self.defined_regions
10 | [:vi]
11 | end
12 |
13 | def self.holidays_by_month
14 | {
15 | 1 => [{:mday => 1, :name => "Tết dương lịch", :regions => [:vi]}],
16 | 3 => [{:mday => 10, :function => "lunar_to_solar(year, month, day, region)", :function_arguments => [:year, :month, :day, :region], :name => "Giỗ tổ Hùng Vương", :regions => [:vi]}],
17 | 4 => [{:mday => 30, :name => "Ngày Giải phóng miền Nam, thống nhất đất nước", :regions => [:vi]}],
18 | 5 => [{:mday => 1, :name => "Ngày Quốc tế Lao động", :regions => [:vi]}],
19 | 9 => [{:mday => 2, :name => "Quốc khánh", :regions => [:vi]}]
20 | }
21 | end
22 |
23 | def self.custom_methods
24 | {
25 |
26 | }
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/bulk-invite-sample-csv-file.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@ember/component";
2 | import { action } from "@ember/object";
3 | import DButton from "discourse/components/d-button";
4 |
5 | export default class BulkInviteSampleCsvFile extends Component {
6 | @action
7 | downloadSampleCsv() {
8 | const sampleData = [
9 | ["my_awesome_group", "going"],
10 | ["lucy", "interested"],
11 | ["mark", "not_going"],
12 | ["sam", "unknown"],
13 | ];
14 |
15 | let csv = "";
16 | sampleData.forEach((row) => {
17 | csv += row.join(",");
18 | csv += "\n";
19 | });
20 |
21 | const btn = document.createElement("a");
22 | btn.href = `data:text/csv;charset=utf-8,${encodeURI(csv)}`;
23 | btn.target = "_blank";
24 | btn.rel = "noopener noreferrer";
25 | btn.download = "bulk-invite-sample.csv";
26 | btn.click();
27 | }
28 |
29 |
30 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/spec/fabricators/event_fabricator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Fabricator(:event, from: "DiscoursePostEvent::Event") do
4 | post { |attrs| attrs[:post] || Fabricate(:post) }
5 |
6 | id { |attrs| attrs[:post].id }
7 |
8 | status do |attrs|
9 | if attrs[:status]
10 | DiscoursePostEvent::Event.statuses[attrs[:status]]
11 | else
12 | DiscoursePostEvent::Event.statuses[:public]
13 | end
14 | end
15 | original_starts_at { |attrs| attrs[:original_starts_at] || 1.day.from_now.iso8601 }
16 | original_ends_at { |attrs| attrs[:original_ends_at] }
17 | end
18 |
19 | Fabricator(:event_date, from: "DiscoursePostEvent::EventDate") do
20 | event
21 |
22 | starts_at { |attrs| attrs[:starts_at] || 1.day.from_now.iso8601 }
23 | ends_at { |attrs| attrs[:ends_at] }
24 | end
25 |
26 | def create_post_with_event(user, extra_raw = "")
27 | start = (Time.now - 10.seconds).utc.iso8601(3)
28 |
29 | PostCreator.create!(
30 | user,
31 | title: "Sell a boat party ##{SecureRandom.alphanumeric}",
32 | raw: "[event start=\"#{start}\" #{extra_raw}]\n[/event]",
33 | ).reload
34 | end
35 |
--------------------------------------------------------------------------------
/spec/serializers/discourse_post_event/post_serializer_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | describe PostSerializer do
4 | before do
5 | Jobs.run_immediately!
6 | SiteSetting.calendar_enabled = true
7 | SiteSetting.discourse_post_event_enabled = true
8 | end
9 |
10 | context "when post has an event" do
11 | let(:user) { Fabricate(:user, admin: true) }
12 | let(:topic_1) { Fabricate(:topic, user: user) }
13 | let(:post_1) { Fabricate(:post, topic: topic_1) }
14 | let!(:post_event_1) { Fabricate(:event, post: post_1) }
15 |
16 | it "serializes the associated event" do
17 | json = PostSerializer.new(post_1, scope: Guardian.new).as_json
18 | expect(json[:post][:event]).to be_present
19 | end
20 |
21 | context "when the post has been destroyed" do
22 | before { PostDestroyer.new(Discourse.system_user, post_1).destroy }
23 |
24 | it "doesn’t serialize the associated event" do
25 | json = PostSerializer.new(post_1, scope: Guardian.new).as_json
26 | expect(json[:post][:event]).to_not be_present
27 | end
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/assets/stylesheets/common/discourse-post-event-core-ext.scss:
--------------------------------------------------------------------------------
1 | .header-title {
2 | @include ellipsis;
3 |
4 | .topic-link {
5 | display: inline;
6 | }
7 |
8 | .event-date {
9 | font-size: var(--font-down-4);
10 | color: var(--primary-medium);
11 | font-weight: normal;
12 | padding: 0.25em;
13 | }
14 | }
15 |
16 | .main-link {
17 | .event-date-container-wrapper {
18 | // prevents new dot from breaking separately onto next line
19 | white-space: nowrap;
20 | }
21 | }
22 |
23 | .link-top-line,
24 | .header-title {
25 | .event-date {
26 | display: inline-flex;
27 | align-items: center;
28 | font-size: var(--font-down-2);
29 | border: 1px solid var(--primary-medium);
30 | background: none;
31 | padding: 0 0.25em;
32 | border-radius: 3px;
33 | pointer-events: auto; // needed to show title attribute on hover
34 | vertical-align: text-bottom;
35 |
36 | .indicator {
37 | display: flex;
38 | width: 6px;
39 | height: 6px;
40 | border-radius: 3px;
41 | background: var(--success);
42 | margin-right: 0.25em;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/discourse_post_event/export_csv_file_extension.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | module ExportPostEventCsvReportExtension
5 | def post_event_export(&block)
6 | return enum_for(:post_event_export) unless block_given?
7 |
8 | guardian = Guardian.new(current_user)
9 |
10 | event = DiscoursePostEvent::Event.includes(invitees: :user).find(@extra[:id])
11 |
12 | guardian.ensure_can_act_on_discourse_post_event!(event)
13 |
14 | event
15 | .invitees
16 | .order(:id)
17 | .each do |invitee|
18 | yield(
19 | [
20 | invitee.user.username,
21 | DiscoursePostEvent::Invitee.statuses[invitee.status],
22 | invitee.created_at,
23 | invitee.updated_at,
24 | ]
25 | )
26 | end
27 | end
28 |
29 | def get_header(entity)
30 | if SiteSetting.discourse_post_event_enabled && entity === "post_event"
31 | %w[username status first_answered_at last_updated_at]
32 | else
33 | super
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/test/javascripts/acceptance/topic-calendar-events-test.js:
--------------------------------------------------------------------------------
1 | import { visit } from "@ember/test-helpers";
2 | import { skip } from "qunit";
3 | import { acceptance, fakeTime } from "discourse/tests/helpers/qunit-helpers";
4 | import eventTopicFixture from "../helpers/event-topic-fixture";
5 | import getEventByText from "../helpers/get-event-by-text";
6 |
7 | acceptance("Discourse Calendar - Topic Calendar Events", function (needs) {
8 | needs.hooks.beforeEach(function () {
9 | this.clock = fakeTime("2023-09-10T00:00:00", "Europe/Lisbon", true);
10 | });
11 |
12 | needs.hooks.afterEach(function () {
13 | this.clock.restore();
14 | });
15 |
16 | needs.settings({
17 | calendar_enabled: true,
18 | });
19 |
20 | needs.pretender((server, helper) => {
21 | server.get("/t/252.json", () => {
22 | return helper.response(eventTopicFixture);
23 | });
24 | });
25 |
26 | skip("renders calendar events with fullDay='false'", async (assert) => {
27 | await visit("/t/-/252");
28 |
29 | assert.dom(getEventByText("Event 1")).exists();
30 | assert.dom(getEventByText("Event 2")).exists();
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/README.md:
--------------------------------------------------------------------------------
1 | # Holidays Definitions [](https://travis-ci.org/holidays/definitions)
2 |
3 | This repository contains the 'raw' definitions for the various holidays projects. It should be added a submodule to
4 | any project that wants to use them.
5 |
6 | Currently it is only used by the [existing Holidays gem](https://github.com/holidays/holidays), which takes these
7 | definitions and generates ruby classes for use in that gem. In the future it will be used by other languages in
8 | a similar manner.
9 |
10 | **Please note** that this is _not_ a gem. The validation process is written in ruby simply for convenience. The real
11 | stars of this show are the YAML files.
12 |
13 | ### Documentation
14 |
15 | 1. [Syntax Guide](doc/SYNTAX.md)
16 | 2. [Contribution Guidelines](doc/CONTRIBUTING.md)
17 | 3. [Maintainer Guidelines](doc/MAINTAINERS.md)
18 | 4. [Architecture Decision Records](doc/architecture/README.md)
19 |
20 | ### Credits
21 |
22 | Thank you to all of these [wonderful contributors!](https://github.com/holidays/definitions/contributors)
23 |
--------------------------------------------------------------------------------
/vendor/holidays/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | require File.dirname(__FILE__) + '/coverage_report'
2 |
3 | $:.unshift(File.expand_path(File.dirname(__FILE__) + '../../lib/'))
4 |
5 | $KCODE = 'u' if RUBY_VERSION =~ /^1\.8/
6 |
7 | require 'rubygems'
8 | require 'test/unit'
9 | require 'mocha/test_unit'
10 | require 'date'
11 | require 'holidays'
12 | require 'holidays/core_extensions/date'
13 | require 'holidays/core_extensions/time'
14 |
15 | # Loads core extension for use in various definition tests as necessary
16 | class Date
17 | include Holidays::CoreExtensions::Date
18 | end
19 |
20 | class Time
21 | include Holidays::CoreExtensions::Time
22 | end
23 |
24 | module Holidays
25 | # Test region used for generating a holiday on Date.today
26 | module Test # :nodoc:
27 | DEFINED_REGIONS = [:test]
28 |
29 | HOLIDAYS_BY_MONTH = {
30 | Date.today.mon => [{:mday => Date.today.mday, :name => "Test Holiday", :regions => [:test]}]
31 | }
32 |
33 | CUSTOM_METHODS = {}
34 | end
35 | end
36 |
37 | Holidays::Factory::Definition.merger.call(Holidays::Test::DEFINED_REGIONS, Holidays::Test::HOLIDAYS_BY_MONTH, Holidays::Test::CUSTOM_METHODS)
38 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/lib/discourse-markdown/discourse-post-event-block.js:
--------------------------------------------------------------------------------
1 | const rule = {
2 | tag: "event",
3 |
4 | wrap(token, info) {
5 | if (!info.attrs.start) {
6 | return false;
7 | }
8 |
9 | token.attrs = [["class", "discourse-post-event"]];
10 |
11 | Object.keys(info.attrs).forEach((key) => {
12 | const value = info.attrs[key];
13 |
14 | if (typeof value !== "undefined") {
15 | token.attrs.push([`data-${dasherize(key)}`, value]);
16 | }
17 | });
18 |
19 | return true;
20 | },
21 | };
22 |
23 | function dasherize(input) {
24 | return input.replace(/[A-Z]/g, function (char, index) {
25 | return (index !== 0 ? "-" : "") + char.toLowerCase();
26 | });
27 | }
28 |
29 | export function setup(helper) {
30 | helper.allowList(["div.discourse-post-event"]);
31 |
32 | helper.registerOptions((opts, siteSettings) => {
33 | opts.features.discourse_post_event =
34 | siteSettings.calendar_enabled &&
35 | siteSettings.discourse_post_event_enabled;
36 | });
37 |
38 | helper.registerPlugin((md) =>
39 | md.block.bbcode.ruler.push("discourse-post-event", rule)
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/lib/discourse_calendar/site_settings/map_event_tag_colors_json_schema.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscourseCalendar
4 | module SiteSettings
5 | class MapEventTagColorsJsonSchema
6 | def self.schema
7 | @schema ||= {
8 | type: "array",
9 | uniqueItems: true,
10 | items: {
11 | type: "object",
12 | title: "Color Mapping",
13 | properties: {
14 | type: {
15 | type: "string",
16 | description: "Type of mapping (tag or category)",
17 | enum: %w[tag category],
18 | },
19 | slug: {
20 | type: "string",
21 | description: "Slug of the tag or category",
22 | },
23 | color: {
24 | type: "string",
25 | format: "color",
26 | default: "#FFFFFF",
27 | description: "Color associated with the tag or category",
28 | },
29 | },
30 | required: %w[slug type color],
31 | },
32 | }
33 | end
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Civilized Discourse Construction Kit, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/discourse-post-event/event-status.gjs:
--------------------------------------------------------------------------------
1 | import Component from "@glimmer/component";
2 | import { i18n } from "discourse-i18n";
3 |
4 | export default class EventStatus extends Component {
5 | get eventStatusLabel() {
6 | return i18n(
7 | `discourse_post_event.models.event.status.${this.args.event.status}.title`
8 | );
9 | }
10 |
11 | get eventStatusDescription() {
12 | return i18n(
13 | `discourse_post_event.models.event.status.${this.args.event.status}.description`
14 | );
15 | }
16 |
17 | get statusClass() {
18 | return `status ${this.args.event.status}`;
19 | }
20 |
21 |
22 | {{#if @event.isExpired}}
23 |
24 | {{i18n "discourse_post_event.models.event.expired"}}
25 |
26 | {{else if @event.isClosed}}
27 |
28 | {{i18n "discourse_post_event.models.event.closed"}}
29 |
30 | {{else}}
31 |
32 | {{this.eventStatusLabel}}
33 |
34 | {{/if}}
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/vendor/holidays/Makefile:
--------------------------------------------------------------------------------
1 | default: test
2 |
3 | setup: update-defs
4 | bundle install
5 |
6 | generate:
7 | bundle exec rake generate
8 |
9 | test:
10 | bundle exec rake test
11 |
12 | console:
13 | bundle exec rake console
14 |
15 | test-region:
16 | bundle exec rake test_region $(REGION)
17 |
18 | build: clean
19 | bundle exec gem build holidays.gemspec
20 |
21 | push:
22 | bundle exec gem push $(GEM)
23 |
24 | update-defs: definitions/
25 | git submodule update --init --remote --recursive
26 |
27 | definitions: point-to-defs-master
28 |
29 | point-to-defs-branch:
30 | git submodule add -b $(BRANCH) git@github.com:$(USER)/definitions.git definitions/
31 |
32 | point-to-defs-master:
33 | git submodule add https://github.com/holidays/definitions definitions/
34 |
35 | clean-defs:
36 | git rm -f definitions
37 | rm -rf .git/modules/definitions
38 | git config -f .git/config --remove-section submodule.definitions 2> /dev/null
39 |
40 | clean:
41 | rm -rf holidays-*.gem
42 | rm -rf reports
43 | rm -rf coverage
44 |
45 | .PHONY: setup test generate console build push update-defs test-region clean-defs point-to-defs-master point-to-defs-branch clean definitions
46 |
--------------------------------------------------------------------------------
/vendor/holidays/LICENSE:
--------------------------------------------------------------------------------
1 | ==== Ruby Holidays Gem License
2 |
3 | Copyright (c) 2007, 2014 Alex Dunae
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/LICENSE:
--------------------------------------------------------------------------------
1 | ==== Ruby Holidays Gem License
2 |
3 | Copyright (c) 2016 Phil Peble
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/templates/admin-plugins-calendar.gjs:
--------------------------------------------------------------------------------
1 | import RouteTemplate from "ember-route-template";
2 | import ConditionalLoadingSpinner from "discourse/components/conditional-loading-spinner";
3 | import { i18n } from "discourse-i18n";
4 | import AdminHolidaysList from "../components/admin-holidays-list";
5 | import RegionInput from "../components/region-input";
6 |
7 | export default RouteTemplate(
8 |
9 |
10 | {{i18n "discourse_calendar.holidays.header_title"}}
11 |
12 |
13 |
17 |
18 |
19 | {{i18n "discourse_calendar.holidays.pick_region_description"}}
20 |
21 | {{i18n "discourse_calendar.holidays.disabled_holidays_description"}}
22 |
23 |
24 |
25 |
26 | {{#if @controller.model.holidays}}
27 |
31 | {{/if}}
32 |
33 | );
34 |
--------------------------------------------------------------------------------
/spec/services/discourse_post_event/chat_channel_sync_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | return if !defined?(Chat)
4 |
5 | describe DiscoursePostEvent::ChatChannelSync do
6 | fab!(:user)
7 | fab!(:admin)
8 | fab!(:admin_post) { Fabricate(:post, user: admin) }
9 |
10 | it "is able to create a chat channel and sync members" do
11 | event = Fabricate(:event, chat_enabled: true, post: admin_post)
12 |
13 | expect(event.chat_channel_id).to be_present
14 | expect(event.chat_channel.name).to eq(event.name)
15 | expect(event.chat_channel.user_chat_channel_memberships.count).to eq(1)
16 | expect(event.chat_channel.user_chat_channel_memberships.first.user_id).to eq(admin.id)
17 |
18 | event.create_invitees([user_id: user.id, status: DiscoursePostEvent::Invitee.statuses[:going]])
19 | event.save!
20 |
21 | expect(event.chat_channel.user_chat_channel_memberships.count).to eq(2)
22 | end
23 |
24 | it "will simply do nothing if user has no permission to create channel" do
25 | post = Fabricate(:post, user: user)
26 | event = Fabricate(:event, chat_enabled: true, post: post)
27 |
28 | expect(event.chat_channel_id).to be_nil
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/factory/date_calculator.rb:
--------------------------------------------------------------------------------
1 | require 'holidays/date_calculator/easter'
2 | require 'holidays/date_calculator/weekend_modifier'
3 | require 'holidays/date_calculator/day_of_month'
4 | require 'holidays/date_calculator/lunar_date'
5 |
6 | module Holidays
7 | module Factory
8 | module DateCalculator
9 | module Easter
10 | module Gregorian
11 | class << self
12 | def easter_calculator
13 | Holidays::DateCalculator::Easter::Gregorian.new
14 | end
15 | end
16 | end
17 |
18 | module Julian
19 | class << self
20 | def easter_calculator
21 | Holidays::DateCalculator::Easter::Julian.new
22 | end
23 | end
24 | end
25 | end
26 |
27 | class << self
28 | def lunar_date
29 | Holidays::DateCalculator::LunarDate.new
30 | end
31 |
32 | def weekend_modifier
33 | Holidays::DateCalculator::WeekendModifier.new
34 | end
35 |
36 | def day_of_month_calculator
37 | Holidays::DateCalculator::DayOfMonth.new
38 | end
39 | end
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/config/locales/client.sq.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | sq:
8 | js:
9 | discourse_automation:
10 | triggerables:
11 | event_started:
12 | fields:
13 | topic_id:
14 | label: ID e temës
15 | discourse_calendar:
16 | disable_holiday: "Çaktivizo"
17 | enable_holiday: "Aktivizo"
18 | region:
19 | none: "Asnjë"
20 | toolbar_button:
21 | today: "Sot"
22 | month: "Këtë muaj"
23 | week: "Këtë javë"
24 | day: "Dit"
25 | discourse_post_event:
26 | bulk_invite_modal:
27 | success: "Skedari u ngarkua, do njoftoheni me mesazh kur procesi të mbarojë. "
28 | error: "Na vjen keq, skedari duhet të jete i formatit CSV."
29 | builder_modal:
30 | update: "Ruaj"
31 | reminders:
32 | units:
33 | days: "ditë"
34 | url:
35 | label: "URL"
36 | location:
37 | label: "Vendndodhja"
38 | description:
39 | label: "Përshkrimi"
40 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/generated_definitions/ecbtarget.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | module Holidays
3 | # This file is generated by the Ruby Holidays gem.
4 | #
5 | # Definitions loaded: definitions/ecbtarget.yaml
6 | #
7 | # All the definitions are available at https://github.com/holidays/holidays
8 | module ECBTARGET # :nodoc:
9 | def self.defined_regions
10 | [:ecbtarget]
11 | end
12 |
13 | def self.holidays_by_month
14 | {
15 | 0 => [{:function => "easter(year)", :function_arguments => [:year], :function_modifier => -2, :name => "Good Friday", :regions => [:ecbtarget]},
16 | {:function => "easter(year)", :function_arguments => [:year], :function_modifier => 1, :name => "Easter Monday", :regions => [:ecbtarget]}],
17 | 1 => [{:mday => 1, :name => "New Year's Day", :regions => [:ecbtarget]}],
18 | 5 => [{:mday => 1, :name => "Labour Day", :regions => [:ecbtarget]}],
19 | 12 => [{:mday => 25, :name => "Christmas Day", :regions => [:ecbtarget]},
20 | {:mday => 26, :name => "Christmas Holiday", :regions => [:ecbtarget]}]
21 | }
22 | end
23 |
24 | def self.custom_methods
25 | {
26 |
27 | }
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/config/locales/server.fa_IR.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | fa_IR:
8 | reports:
9 | currently_away:
10 | labels:
11 | username: نامکاربری
12 | discourse_automation:
13 | triggerables:
14 | event_started:
15 | title: رویداد شروع شد
16 | site_settings:
17 | events_calendar_categories: "نمایش رویدادهای تقویم در بالای دستهبندی"
18 | sidebar_show_upcoming_events: "پیوند رویدادهای آینده را در نوار کناری زیر «بیشتر» نمایش دهید."
19 | discourse_calendar:
20 | invite_user_notification: "%{username} شما را دعوت کرده به: %{description}"
21 | holiday_status:
22 | description: "در تعطیلات"
23 | discourse_post_event:
24 | errors:
25 | bulk_invite:
26 | error: "خطایی هنگام آپلود فایل مربوطه رخ داده است. لطفا بعدا امتحان کنید."
27 | models:
28 | event:
29 | invalid_timezone: "منطقهزمانی شناسایی نشد."
30 | invalid_allowed_groups: "گروههای مجاز نامعتبر."
31 | acting_user_not_allowed_to_invite_these_groups: "کاربر فعلی اجازه دعوت از این گروهها را ندارد."
32 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/generated_definitions/tn.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | module Holidays
3 | # This file is generated by the Ruby Holidays gem.
4 | #
5 | # Definitions loaded: definitions/tn.yaml
6 | #
7 | # All the definitions are available at https://github.com/holidays/holidays
8 | module TN # :nodoc:
9 | def self.defined_regions
10 | [:tn]
11 | end
12 |
13 | def self.holidays_by_month
14 | {
15 | 1 => [{:mday => 1, :name => "Jour de l'an", :regions => [:tn]},
16 | {:mday => 14, :name => "Fête de la Révolution et de la Jeunesse", :regions => [:tn]}],
17 | 3 => [{:mday => 20, :name => "Fête de l'Indépendance", :regions => [:tn]}],
18 | 4 => [{:mday => 9, :name => "Journée des Martyrs", :regions => [:tn]}],
19 | 5 => [{:mday => 1, :name => "Fête du travail", :regions => [:tn]}],
20 | 7 => [{:mday => 25, :name => "Fête de la République", :regions => [:tn]}],
21 | 8 => [{:mday => 13, :name => "Fête de la Femme et de la Famille", :regions => [:tn]}],
22 | 10 => [{:mday => 15, :name => "Fête de l'Évacuation", :regions => [:tn]}]
23 | }
24 | end
25 |
26 | def self.custom_methods
27 | {
28 |
29 | }
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_tn.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/tn.yaml
7 | class TnDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_tn
10 | assert_equal "Jour de l'an", (Holidays.on(Date.civil(2016, 1, 1), [:tn])[0] || {})[:name]
11 |
12 | assert_equal "Fête de la Révolution et de la Jeunesse", (Holidays.on(Date.civil(2016, 1, 14), [:tn])[0] || {})[:name]
13 |
14 | assert_equal "Fête de l'Indépendance", (Holidays.on(Date.civil(2016, 3, 20), [:tn])[0] || {})[:name]
15 |
16 | assert_equal "Journée des Martyrs", (Holidays.on(Date.civil(2016, 4, 9), [:tn])[0] || {})[:name]
17 |
18 | assert_equal "Fête du travail", (Holidays.on(Date.civil(2016, 5, 1), [:tn])[0] || {})[:name]
19 |
20 | assert_equal "Fête de la République", (Holidays.on(Date.civil(2016, 7, 25), [:tn])[0] || {})[:name]
21 |
22 | assert_equal "Fête de la Femme et de la Famille", (Holidays.on(Date.civil(2016, 8, 13), [:tn])[0] || {})[:name]
23 |
24 | assert_equal "Fête de l'Évacuation", (Holidays.on(Date.civil(2016, 10, 15), [:tn])[0] || {})[:name]
25 |
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_ecbtarget.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/ecbtarget.yaml
7 | class EcbtargetDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_ecbtarget
10 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2013, 1, 1), [:ecbtarget])[0] || {})[:name]
11 |
12 | assert_equal "Labour Day", (Holidays.on(Date.civil(2013, 5, 1), [:ecbtarget])[0] || {})[:name]
13 |
14 | assert_equal "Good Friday", (Holidays.on(Date.civil(2013, 3, 29), [:ecbtarget])[0] || {})[:name]
15 |
16 | assert_equal "Easter Monday", (Holidays.on(Date.civil(2013, 4, 1), [:ecbtarget])[0] || {})[:name]
17 |
18 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2013, 12, 25), [:ecbtarget])[0] || {})[:name]
19 |
20 | assert_equal "Christmas Holiday", (Holidays.on(Date.civil(2013, 12, 26), [:ecbtarget])[0] || {})[:name]
21 |
22 | assert_equal "Good Friday", (Holidays.on(Date.civil(2013, 3, 29), [:ecbtarget])[0] || {})[:name]
23 |
24 | assert_equal "Easter Monday", (Holidays.on(Date.civil(2013, 4, 1), [:ecbtarget])[0] || {})[:name]
25 |
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/test/javascripts/lib/raw-event-helper-test.js:
--------------------------------------------------------------------------------
1 | import { module, test } from "qunit";
2 | import { replaceRaw } from "discourse/plugins/discourse-calendar/discourse/lib/raw-event-helper";
3 |
4 | module("Unit | Lib | raw-event-helper", function () {
5 | test("replaceRaw", function (assert) {
6 | const raw = 'Some text \n[event param1="va]lue1"]\n[/event]\n more text';
7 | const params = {
8 | param1: "newValue1",
9 | param2: "value2",
10 | };
11 |
12 | assert.strictEqual(
13 | replaceRaw(params, raw),
14 | 'Some text \n[event param1="newValue1" param2="value2"]\n[/event]\n more text',
15 | "updates existing parameters and adds new ones"
16 | );
17 |
18 | assert.false(
19 | replaceRaw(params, "No event tag here"),
20 | "returns false when no event tag is found"
21 | );
22 |
23 | assert.strictEqual(
24 | replaceRaw({ foo: 'bar"quoted' }, '[event original="value"]\n[/event]'),
25 | '[event foo="barquoted"]\n[/event]',
26 | "escapes double quotes in parameter values"
27 | );
28 |
29 | assert.strictEqual(
30 | replaceRaw({}, '[event param1="value1"]\n[/event]'),
31 | "[event ]\n[/event]",
32 | "handles empty params object"
33 | );
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/toggle-invitees.gjs:
--------------------------------------------------------------------------------
1 | import { fn } from "@ember/helper";
2 | import { eq } from "truth-helpers";
3 | import DButton from "discourse/components/d-button";
4 | import concatClass from "discourse/helpers/concat-class";
5 |
6 | const ToggleInvitees =
7 |
8 |
16 |
17 |
25 |
26 |
34 |
35 | ;
36 |
37 | export default ToggleInvitees;
38 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/generated_definitions/ma.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | module Holidays
3 | # This file is generated by the Ruby Holidays gem.
4 | #
5 | # Definitions loaded: definitions/ma.yaml
6 | #
7 | # All the definitions are available at https://github.com/holidays/holidays
8 | module MA # :nodoc:
9 | def self.defined_regions
10 | [:ma]
11 | end
12 |
13 | def self.holidays_by_month
14 | {
15 | 1 => [{:mday => 1, :name => "Ras l' âm", :regions => [:ma]},
16 | {:mday => 11, :name => "Takdim watikat al-istiqlal", :regions => [:ma]}],
17 | 5 => [{:mday => 1, :name => "Eid Ash-Shughl", :regions => [:ma]}],
18 | 7 => [{:mday => 30, :name => "Eid Al-Ârch", :regions => [:ma]}],
19 | 8 => [{:mday => 14, :name => "Zikra Oued Ed-Dahab", :regions => [:ma]},
20 | {:mday => 20, :name => "Thawrat al malik wa shâab", :regions => [:ma]},
21 | {:mday => 21, :name => "Eid Al Milad", :regions => [:ma]}],
22 | 11 => [{:mday => 6, :name => "Eid Al Massira Al Khadra", :regions => [:ma]},
23 | {:mday => 18, :name => "Eid Al Istiqulal", :regions => [:ma]}]
24 | }
25 | end
26 |
27 | def self.custom_methods
28 | {
29 |
30 | }
31 | end
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_ph.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/ph.yaml
7 | class PhDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_ph
10 | assert_equal "Good Friday", (Holidays.on(Date.civil(2015, 4, 3), [:ph])[0] || {})[:name]
11 |
12 | assert_equal "The Day of Valor", (Holidays.on(Date.civil(2015, 4, 9), [:ph])[0] || {})[:name]
13 |
14 | assert_equal "Labor Day", (Holidays.on(Date.civil(2015, 5, 1), [:ph])[0] || {})[:name]
15 |
16 | assert_equal "Independence Day", (Holidays.on(Date.civil(2015, 6, 12), [:ph])[0] || {})[:name]
17 |
18 | assert_equal "Ninoy Aquino Day", (Holidays.on(Date.civil(2015, 8, 21), [:ph])[0] || {})[:name]
19 |
20 | assert_equal "National Heroes Day", (Holidays.on(Date.civil(2015, 8, 31), [:ph])[0] || {})[:name]
21 |
22 | assert_equal "Bonifacio Day", (Holidays.on(Date.civil(2015, 11, 30), [:ph])[0] || {})[:name]
23 |
24 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2015, 12, 25), [:ph])[0] || {})[:name]
25 |
26 | assert_equal "Rizal Day", (Holidays.on(Date.civil(2015, 12, 30), [:ph])[0] || {})[:name]
27 |
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/vendor/holidays/test/holidays/definition/repository/test_custom_methods.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../../../test_helper'
2 |
3 | require 'holidays/definition/repository/custom_methods'
4 |
5 | class CustomMethodsRepoTests < Test::Unit::TestCase
6 | def setup
7 | @subject = Holidays::Definition::Repository::CustomMethods.new
8 | end
9 |
10 | def test_add_raises_error_if_input_is_nil
11 | assert_raise ArgumentError do
12 | @subject.add(nil)
13 | end
14 | end
15 |
16 | def test_find_returns_nil_if_method_id_does_not_exist
17 | assert_nil @subject.find("some-method-id")
18 | end
19 |
20 | def test_add_successfully_adds_new_custom_methods
21 | new_custom_methods = {
22 | "some-method-id" => Proc.new { |year|
23 | Date.civil(year, 1, 1)
24 | }
25 | }
26 |
27 | @subject.add(new_custom_methods)
28 |
29 | target_method = @subject.find("some-method-id")
30 |
31 | assert_equal new_custom_methods["some-method-id"], target_method
32 | end
33 |
34 | def test_find_raises_error_if_target_method_id_is_nil_or_empty
35 | assert_raise ArgumentError do
36 | @subject.find(nil)
37 | end
38 |
39 | assert_raise ArgumentError do
40 | @subject.find("")
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/generated_definitions/nerc.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | module Holidays
3 | # This file is generated by the Ruby Holidays gem.
4 | #
5 | # Definitions loaded: definitions/nerc.yaml
6 | #
7 | # All the definitions are available at https://github.com/holidays/holidays
8 | module NERC # :nodoc:
9 | def self.defined_regions
10 | [:nerc]
11 | end
12 |
13 | def self.holidays_by_month
14 | {
15 | 1 => [{:mday => 1, :observed => "to_monday_if_sunday(date)", :observed_arguments => [:date], :name => "New Year's Day", :regions => [:nerc]}],
16 | 5 => [{:wday => 1, :week => -1, :name => "Memorial Day", :regions => [:nerc]}],
17 | 7 => [{:mday => 4, :observed => "to_monday_if_sunday(date)", :observed_arguments => [:date], :name => "Independence Day", :regions => [:nerc]}],
18 | 9 => [{:wday => 1, :week => 1, :name => "Labor Day", :regions => [:nerc]}],
19 | 11 => [{:wday => 4, :week => 4, :name => "Thanksgiving", :regions => [:nerc]}],
20 | 12 => [{:mday => 25, :observed => "to_monday_if_sunday(date)", :observed_arguments => [:date], :name => "Christmas Day", :regions => [:nerc]}]
21 | }
22 | end
23 |
24 | def self.custom_methods
25 | {
26 |
27 | }
28 | end
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_ng.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/ng.yaml
7 | class NgDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_ng
10 | assert_equal "Good Friday", (Holidays.on(Date.civil(2008, 3, 21), [:ng])[0] || {})[:name]
11 |
12 | assert_equal "Easter Monday", (Holidays.on(Date.civil(2008, 3, 24), [:ng])[0] || {})[:name]
13 |
14 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2008, 1, 1), [:ng])[0] || {})[:name]
15 |
16 | assert_equal "Workers' Day", (Holidays.on(Date.civil(2008, 5, 1), [:ng])[0] || {})[:name]
17 |
18 | assert_equal "Children's Day", (Holidays.on(Date.civil(2008, 5, 27), [:ng], [:informal])[0] || {})[:name]
19 |
20 | assert_equal "Democracy Day", (Holidays.on(Date.civil(2019, 6, 12), [:ng])[0] || {})[:name]
21 |
22 | assert_equal "Independence Day", (Holidays.on(Date.civil(2008, 10, 1), [:ng])[0] || {})[:name]
23 |
24 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2008, 12, 25), [:ng])[0] || {})[:name]
25 |
26 | assert_equal "Boxing Day", (Holidays.on(Date.civil(2008, 12, 26), [:ng])[0] || {})[:name]
27 |
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/vendor/holidays/holidays.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 |
5 | require 'holidays/version'
6 |
7 | Gem::Specification.new do |gem|
8 | gem.name = 'holidays'
9 | gem.version = Holidays::VERSION
10 | gem.authors = ['Alex Dunae', 'Phil Peble']
11 | gem.email = ['holidaysgem@gmail.com']
12 | gem.homepage = 'https://github.com/holidays/holidays'
13 | gem.description = %q(A collection of Ruby methods to deal with statutory and other holidays. You deserve a holiday!)
14 | gem.summary = %q(A collection of Ruby methods to deal with statutory and other holidays.)
15 | gem.files = `git ls-files`.split("\n") - ['.gitignore', '.travis.yml']
16 | gem.test_files = gem.files.grep(/^test/)
17 | gem.require_paths = ['lib']
18 | gem.licenses = ['MIT']
19 | gem.required_ruby_version = '>= 2.4'
20 | gem.add_development_dependency 'bundler', '~> 2'
21 | gem.add_development_dependency 'rake', '~> 12'
22 | gem.add_development_dependency 'simplecov', '~> 0.16'
23 | gem.add_development_dependency 'test-unit', '~> 3'
24 | gem.add_development_dependency 'mocha', '~> 1'
25 | gem.add_development_dependency 'pry', '~> 0.12'
26 | end
27 |
--------------------------------------------------------------------------------
/vendor/holidays/test/holidays/definition/context/test_load.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../../../test_helper'
2 |
3 | require 'holidays/definition/context/load'
4 |
5 | class LoadTests < Test::Unit::TestCase
6 | def setup
7 | @definition_merger = mock()
8 | full_definitions_path = File.expand_path(File.dirname(__FILE__)) + '/../../../data'
9 |
10 | @subject = Holidays::Definition::Context::Load.new(
11 | @definition_merger,
12 | full_definitions_path,
13 | )
14 | end
15 |
16 | def test_region_is_found_and_loaded_and_merged
17 | @definition_merger.expects(:call).with(:test_region, {}, {})
18 | @subject.call(:test_region)
19 | end
20 |
21 | def test_region_file_not_found
22 | assert_raises Holidays::UnknownRegionError do
23 | @subject.call(:unknown)
24 | end
25 | end
26 |
27 | def test_region_can_be_loaded_but_file_is_invalid
28 | assert_raises Holidays::UnknownRegionError do
29 | @subject.call(:test_invalid_region)
30 | end
31 | end
32 |
33 | def test_returns_list_of_loaded_regions
34 | @definition_merger.expects(:call).with(:test_region, {}, {})
35 | assert_equal([:test_region, :test_region2], @subject.call(:test_region), "Should cache subregions under the parent region's name")
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/discourse_post_event/rrule_generator.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rrule"
4 |
5 | class RRuleGenerator
6 | def self.generate(
7 | starts_at:,
8 | timezone: "UTC",
9 | max_years: nil,
10 | recurrence: "every_week",
11 | recurrence_until: nil
12 | )
13 | rrule = generate_hash(RRuleConfigurator.rule(recurrence_until:, recurrence:, starts_at:))
14 | rrule = set_mandatory_options(rrule, starts_at)
15 |
16 | ::RRule::Rule
17 | .new(stringify(rrule), dtstart: starts_at, tzid: timezone)
18 | .between(Time.current, Time.current + 14.months)
19 | .first(RRuleConfigurator.how_many_recurring_events(recurrence:, max_years:))
20 | end
21 |
22 | private
23 |
24 | def self.stringify(rrule)
25 | rrule.map { |k, v| "#{k}=#{v}" }.join(";")
26 | end
27 |
28 | def self.generate_hash(rrule)
29 | rrule
30 | .split(";")
31 | .each_with_object({}) do |rr, h|
32 | key, value = rr.split("=")
33 | h[key] = value
34 | end
35 | end
36 |
37 | def self.set_mandatory_options(rrule, time)
38 | rrule["BYHOUR"] = time.strftime("%H")
39 | rrule["BYMINUTE"] = time.strftime("%M")
40 | rrule["INTERVAL"] ||= 1
41 | rrule["WKST"] = "MO" # considers Monday as the first day of the week
42 | rrule
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_cr.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/cr.yaml
7 | class CrDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_cr
10 | assert_equal "Año Nuevo", (Holidays.on(Date.civil(2015, 1, 1), [:cr])[0] || {})[:name]
11 |
12 | assert_equal "Día de Juan Santamaría", (Holidays.on(Date.civil(2015, 4, 11), [:cr])[0] || {})[:name]
13 |
14 | assert_equal "Día del Trabajador", (Holidays.on(Date.civil(2015, 5, 1), [:cr])[0] || {})[:name]
15 |
16 | assert_equal "Día de la Anexión de Guanacaste", (Holidays.on(Date.civil(2015, 7, 25), [:cr])[0] || {})[:name]
17 |
18 | assert_equal "Día de la Virgen de los Angeles", (Holidays.on(Date.civil(2015, 8, 2), [:cr])[0] || {})[:name]
19 |
20 | assert_equal "Día de la Madre", (Holidays.on(Date.civil(2015, 8, 15), [:cr])[0] || {})[:name]
21 |
22 | assert_equal "Día de la Independencia", (Holidays.on(Date.civil(2015, 9, 15), [:cr])[0] || {})[:name]
23 |
24 | assert_equal "Día de las Culturas", (Holidays.on(Date.civil(2015, 10, 12), [:cr])[0] || {})[:name]
25 |
26 | assert_equal "Navidad", (Holidays.on(Date.civil(2016, 12, 25), [:cr])[0] || {})[:name]
27 |
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/discourse_post_event/export_csv_controller_extension.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module DiscoursePostEvent
4 | module ExportCsvControllerExtension
5 | def export_entity
6 | if post_event_export? && ensure_can_export_post_event
7 | Jobs.enqueue(
8 | :export_csv_file,
9 | entity: export_params[:entity],
10 | user_id: current_user.id,
11 | args: export_params[:args],
12 | )
13 | StaffActionLogger.new(current_user).log_entity_export(export_params[:entity])
14 | render json: success_json
15 | else
16 | super
17 | end
18 | end
19 |
20 | private
21 |
22 | def export_params
23 | if post_event_export?
24 | @_export_params ||=
25 | begin
26 | params.require(:entity)
27 | params.permit(:entity, args: %i[id]).to_h
28 | end
29 | else
30 | super
31 | end
32 | end
33 |
34 | def post_event_export?
35 | params[:entity] === "post_event"
36 | end
37 |
38 | def ensure_can_export_post_event
39 | return if !SiteSetting.discourse_post_event_enabled
40 |
41 | post_event = DiscoursePostEvent::Event.find(export_params[:args][:id])
42 | post_event && guardian.can_act_on_discourse_post_event?(post_event)
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/vendor/holidays/definitions/vi.yaml:
--------------------------------------------------------------------------------
1 | # Vietnam holiday definitions for the Ruby Holiday gem.
2 | #
3 | # Updated: 2014-07-17.
4 | # Source: http://en.wikipedia.org/wiki/Public_holidays_in_Vietnam
5 | ---
6 | months:
7 | 1:
8 | - name: Tết dương lịch
9 | regions: [vi]
10 | mday: 1
11 | 3:
12 | - name: Giỗ tổ Hùng Vương
13 | regions: [vi]
14 | function: lunar_to_solar(year, month, day, region)
15 | mday: 10
16 | 4:
17 | - name: Ngày Giải phóng miền Nam, thống nhất đất nước
18 | regions: [vi]
19 | mday: 30
20 | 5:
21 | - name: Ngày Quốc tế Lao động
22 | regions: [vi]
23 | mday: 1
24 | 9:
25 | - name: Quốc khánh
26 | regions: [vi]
27 | mday: 2
28 |
29 | tests:
30 | - given:
31 | date: '2014-01-01'
32 | regions: ["vi"]
33 | expect:
34 | name: "Tết dương lịch"
35 | - given:
36 | date: '2014-04-30'
37 | regions: ["vi"]
38 | expect:
39 | name: "Ngày Giải phóng miền Nam, thống nhất đất nước"
40 | - given:
41 | date: '2014-05-01'
42 | regions: ["vi"]
43 | expect:
44 | name: "Ngày Quốc tế Lao động"
45 | - given:
46 | date: '2014-09-02'
47 | regions: ["vi"]
48 | expect:
49 | name: "Quốc khánh"
50 | - given:
51 | date: ['2017-04-06', '2018-03-27']
52 | regions: ["vi"]
53 | expect:
54 | name: "Giỗ tổ Hùng Vương"
55 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_ke.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/ke.yaml
7 | class KeDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_ke
10 | assert_equal "Good Friday", (Holidays.on(Date.civil(2008, 3, 21), [:ke])[0] || {})[:name]
11 |
12 | assert_equal "Easter Monday", (Holidays.on(Date.civil(2008, 3, 24), [:ke])[0] || {})[:name]
13 |
14 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2008, 1, 1), [:ke])[0] || {})[:name]
15 |
16 | assert_equal "Labour Day", (Holidays.on(Date.civil(2008, 5, 1), [:ke])[0] || {})[:name]
17 |
18 | assert_equal "Madaraka Day", (Holidays.on(Date.civil(2019, 6, 1), [:ke])[0] || {})[:name]
19 |
20 | assert_equal "Huduma Day", (Holidays.on(Date.civil(2018, 10, 10), [:ke])[0] || {})[:name]
21 |
22 | assert_equal "Mashujaa Day", (Holidays.on(Date.civil(2018, 10, 20), [:ke])[0] || {})[:name]
23 |
24 | assert_equal "Jamhuri Day", (Holidays.on(Date.civil(2019, 12, 12), [:ke])[0] || {})[:name]
25 |
26 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2008, 12, 25), [:ke])[0] || {})[:name]
27 |
28 | assert_equal "Utamaduni Day", (Holidays.on(Date.civil(2018, 12, 26), [:ke])[0] || {})[:name]
29 |
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/repository/regions.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Repository
4 | class Regions
5 | def initialize(all_generated_regions, parent_region_lookup)
6 | @loaded_regions = []
7 | @all_generated_regions = all_generated_regions
8 | @parent_region_lookup = parent_region_lookup
9 | end
10 |
11 | def all_generated
12 | @all_generated_regions
13 | end
14 |
15 | def parent_region_lookup(r)
16 | @parent_region_lookup[r]
17 | end
18 |
19 | def all_loaded
20 | @loaded_regions
21 | end
22 |
23 | def loaded?(region)
24 | raise ArgumentError unless region.is_a?(Symbol)
25 | @loaded_regions.include?(region)
26 | end
27 |
28 | def add(regions)
29 | regions = [regions] unless regions.is_a?(Array)
30 |
31 | regions.each do |region|
32 | raise ArgumentError unless region.is_a?(Symbol)
33 | end
34 |
35 | @loaded_regions = @loaded_regions | regions
36 | @loaded_regions.uniq!
37 | end
38 |
39 | def search(prefix)
40 | raise ArgumentError unless prefix.is_a?(Symbol)
41 | @loaded_regions.select { |region| region.to_s =~ Regexp.new("^#{prefix}") }
42 | end
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_nerc.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/nerc.yaml
7 | class NercDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_nerc
10 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2013, 1, 1), [:nerc], [:observed])[0] || {})[:name]
11 |
12 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2017, 1, 2), [:nerc], [:observed])[0] || {})[:name]
13 |
14 | assert_equal "Memorial Day", (Holidays.on(Date.civil(2013, 5, 27), [:nerc], [:observed])[0] || {})[:name]
15 |
16 | assert_equal "Independence Day", (Holidays.on(Date.civil(2013, 7, 4), [:nerc], [:observed])[0] || {})[:name]
17 |
18 | assert_equal "Independence Day", (Holidays.on(Date.civil(2010, 7, 5), [:nerc], [:observed])[0] || {})[:name]
19 |
20 | assert_equal "Labor Day", (Holidays.on(Date.civil(2013, 9, 2), [:nerc], [:observed])[0] || {})[:name]
21 |
22 | assert_equal "Thanksgiving", (Holidays.on(Date.civil(2013, 11, 28), [:nerc], [:observed])[0] || {})[:name]
23 |
24 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2013, 12, 25), [:nerc], [:observed])[0] || {})[:name]
25 |
26 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2011, 12, 26), [:nerc], [:observed])[0] || {})[:name]
27 |
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_ups.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/ups.yaml
7 | class UpsDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_ups
10 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2008, 1, 1), [:ups])[0] || {})[:name]
11 |
12 | assert_equal "Memorial Day", (Holidays.on(Date.civil(2008, 5, 26), [:ups])[0] || {})[:name]
13 |
14 | assert_equal "Independence Day", (Holidays.on(Date.civil(2008, 7, 4), [:ups])[0] || {})[:name]
15 |
16 | assert_equal "Labor Day", (Holidays.on(Date.civil(2008, 9, 1), [:ups])[0] || {})[:name]
17 |
18 | assert_equal "Thanksgiving", (Holidays.on(Date.civil(2008, 11, 27), [:ups])[0] || {})[:name]
19 |
20 | assert_equal "Day After Thanksgiving", (Holidays.on(Date.civil(2008, 11, 28), [:ups])[0] || {})[:name]
21 |
22 | assert_equal "Thanksgiving", (Holidays.on(Date.civil(2013, 11, 28), [:ups])[0] || {})[:name]
23 |
24 | assert_equal "Day After Thanksgiving", (Holidays.on(Date.civil(2013, 11, 29), [:ups])[0] || {})[:name]
25 |
26 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2008, 12, 25), [:ups])[0] || {})[:name]
27 |
28 | assert_equal "New Year's Eve", (Holidays.on(Date.civil(2008, 12, 31), [:ups])[0] || {})[:name]
29 |
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/components/region-input.js:
--------------------------------------------------------------------------------
1 | import { computed } from "@ember/object";
2 | import { classNames } from "@ember-decorators/component";
3 | import { i18n } from "discourse-i18n";
4 | import ComboBoxComponent from "select-kit/components/combo-box";
5 | import {
6 | pluginApiIdentifiers,
7 | selectKitOptions,
8 | } from "select-kit/components/select-kit";
9 | import { HOLIDAY_REGIONS } from "../lib/regions";
10 |
11 | @selectKitOptions({
12 | filterable: true,
13 | allowAny: false,
14 | })
15 | @pluginApiIdentifiers("timezone-input")
16 | @classNames("timezone-input", "region-input")
17 | export default class RegionInput extends ComboBoxComponent {
18 | allowNoneRegion = false;
19 |
20 | @computed
21 | get content() {
22 | const localeNames = {};
23 | let regions = [];
24 |
25 | JSON.parse(this.siteSettings.available_locales).forEach((locale) => {
26 | localeNames[locale.value] = locale.name;
27 | });
28 |
29 | if (this.allowNoneRegion === true) {
30 | regions.push({
31 | name: i18n("discourse_calendar.region.none"),
32 | id: null,
33 | });
34 | }
35 |
36 | regions = regions.concat(
37 | HOLIDAY_REGIONS.map((region) => ({
38 | name: i18n(`discourse_calendar.region.names.${region}`),
39 | id: region,
40 | })).sort((a, b) => a.name.localeCompare(b.name))
41 | );
42 | return regions;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_fedex.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/fedex.yaml
7 | class FedexDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_fedex
10 | assert_equal "New Year's Day", (Holidays.on(Date.civil(2015, 1, 1), [:ups])[0] || {})[:name]
11 |
12 | assert_equal "Memorial Day", (Holidays.on(Date.civil(2015, 5, 25), [:ups])[0] || {})[:name]
13 |
14 | assert_equal "Independence Day", (Holidays.on(Date.civil(2015, 7, 4), [:ups])[0] || {})[:name]
15 |
16 | assert_equal "Labor Day", (Holidays.on(Date.civil(2015, 9, 7), [:ups])[0] || {})[:name]
17 |
18 | assert_equal "Thanksgiving", (Holidays.on(Date.civil(2015, 11, 26), [:ups])[0] || {})[:name]
19 |
20 | assert_equal "Day After Thanksgiving", (Holidays.on(Date.civil(2015, 11, 27), [:ups])[0] || {})[:name]
21 |
22 | assert_equal "Thanksgiving", (Holidays.on(Date.civil(2013, 11, 28), [:ups])[0] || {})[:name]
23 |
24 | assert_equal "Day After Thanksgiving", (Holidays.on(Date.civil(2013, 11, 29), [:ups])[0] || {})[:name]
25 |
26 | assert_equal "Christmas Day", (Holidays.on(Date.civil(2015, 12, 25), [:ups])[0] || {})[:name]
27 |
28 | assert_equal "New Year's Eve", (Holidays.on(Date.civil(2015, 12, 31), [:ups])[0] || {})[:name]
29 |
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/vendor/holidays/test/integration/test_multiple_regions_with_conflict.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
2 |
3 | # See https://github.com/holidays/holidays/issues/344 for more info on why
4 | # these tests exist.
5 | class MultipleRegionsWithConflictsTests < Test::Unit::TestCase
6 |
7 | def test_corpus_christi_returns_correctly_for_co_even_if_br_is_loaded_first
8 | result = Holidays.on(Date.new(2014, 6, 19), :br)
9 | assert_equal 1, result.count
10 | assert_equal 'Corpus Christi', result.first[:name]
11 |
12 | result = Holidays.on(Date.new(2014, 6, 23), :co)
13 | assert_equal 1, result.count
14 | assert_equal 'Corpus Christi', result.first[:name]
15 | end
16 |
17 | def test_custom_loaded_region_returns_correct_value_with_function_modifier_conflict_even_if_conflict_definition_is_loaded_first
18 | Holidays.load_custom('test/data/test_multiple_regions_with_conflicts_region_1.yaml')
19 | result = Holidays.on(Date.new(2019, 6, 20), :multiple_with_conflict_1)
20 | assert_equal 1, result.count
21 | assert_equal 'With Function Modifier', result.first[:name]
22 |
23 | Holidays.load_custom('test/data/test_multiple_regions_with_conflicts_region_2.yaml')
24 | result = Holidays.on(Date.new(2019, 6, 24), :multiple_with_conflict_2)
25 | assert_equal 1, result.count
26 | assert_equal 'With Function Modifier', result.first[:name]
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_ma.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/ma.yaml
7 | class MaDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_ma
10 | assert_equal "Ras l' âm", (Holidays.on(Date.civil(2007, 1, 1), [:ma], [:informal])[0] || {})[:name]
11 |
12 | assert_equal "Takdim watikat al-istiqlal", (Holidays.on(Date.civil(2007, 1, 11), [:ma], [:informal])[0] || {})[:name]
13 |
14 | assert_equal "Eid Ash-Shughl", (Holidays.on(Date.civil(2007, 5, 1), [:ma], [:informal])[0] || {})[:name]
15 |
16 | assert_equal "Eid Al-Ârch", (Holidays.on(Date.civil(2007, 7, 30), [:ma], [:informal])[0] || {})[:name]
17 |
18 | assert_equal "Zikra Oued Ed-Dahab", (Holidays.on(Date.civil(2007, 8, 14), [:ma], [:informal])[0] || {})[:name]
19 |
20 | assert_equal "Thawrat al malik wa shâab", (Holidays.on(Date.civil(2007, 8, 20), [:ma], [:informal])[0] || {})[:name]
21 |
22 | assert_equal "Eid Al Milad", (Holidays.on(Date.civil(2007, 8, 21), [:ma], [:informal])[0] || {})[:name]
23 |
24 | assert_equal "Eid Al Massira Al Khadra", (Holidays.on(Date.civil(2007, 11, 6), [:ma], [:informal])[0] || {})[:name]
25 |
26 | assert_equal "Eid Al Istiqulal", (Holidays.on(Date.civil(2007, 11, 18), [:ma], [:informal])[0] || {})[:name]
27 |
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_multiple_regions_with_conflicts_region_1.yaml:
--------------------------------------------------------------------------------
1 | months:
2 | 0:
3 | - name: With Function Modifier
4 | regions: [multiple_with_conflict_1]
5 | function: easter(year)
6 | function_modifier: 60
7 | - name: With Function Only Different Function Name
8 | regions: [multiple_with_conflict_1]
9 | function: conflict_custom_method_1(year)
10 | - name: With Function Only Same Function Name
11 | regions: [multiple_with_conflict_1]
12 | function: conflict_custom_method_identical_name_between_regions(year)
13 | - name: With Function Only Same Function Name - Region 1
14 | regions: [multiple_with_conflict_1]
15 | function: conflict_custom_method_identical_name_between_regions_but_different_holiday_names(year)
16 | 1:
17 | - name: New Year's Day
18 | regions: [multiple_with_conflict_1]
19 | mday: 1
20 | observed: to_monday_if_weekend(date)
21 | 10:
22 | - name: Testing Conflict Month 10
23 | regions: [multiple_with_conflict_1]
24 | mday: 5
25 |
26 | methods:
27 | conflict_custom_method_1:
28 | arguments: year
29 | ruby: |
30 | Date.civil(year, 8, 1)
31 | conflict_custom_method_identical_name_between_regions:
32 | arguments: year
33 | ruby: |
34 | Date.civil(year, 9, 1)
35 | conflict_custom_method_identical_name_between_regions_but_different_holiday_names:
36 | arguments: year
37 | ruby: |
38 | Date.civil(year, 9, 15)
39 |
--------------------------------------------------------------------------------
/vendor/holidays/test/defs/test_defs_at.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
3 |
4 | # This file is generated by the Ruby Holiday gem.
5 | #
6 | # Definitions loaded: definitions/at.yaml
7 | class AtDefinitionTests < Test::Unit::TestCase # :nodoc:
8 |
9 | def test_at
10 | assert_equal "Neujahrstag", (Holidays.on(Date.civil(2009, 1, 1), [:at], [:informal])[0] || {})[:name]
11 |
12 | assert_equal "Ostermontag", (Holidays.on(Date.civil(2009, 4, 13), [:at])[0] || {})[:name]
13 |
14 | assert_equal "Christi Himmelfahrt", (Holidays.on(Date.civil(2009, 5, 21), [:at])[0] || {})[:name]
15 |
16 | assert_equal "Pfingstmontag", (Holidays.on(Date.civil(2009, 6, 1), [:at])[0] || {})[:name]
17 |
18 | assert_equal "Nationalfeiertag", (Holidays.on(Date.civil(2009, 10, 26), [:at], [:informal])[0] || {})[:name]
19 |
20 | assert_equal "Mariä Empfängnis", (Holidays.on(Date.civil(2009, 12, 8), [:at], [:informal])[0] || {})[:name]
21 |
22 | assert_equal "1. Weihnachtstag", (Holidays.on(Date.civil(2009, 12, 25), [:at], [:informal])[0] || {})[:name]
23 |
24 | assert_equal "2. Weihnachtstag", (Holidays.on(Date.civil(2009, 12, 26), [:at], [:informal])[0] || {})[:name]
25 |
26 | assert_nil (Holidays.on(Date.civil(2010, 5, 8), [:at])[0] || {})[:name]
27 |
28 | assert_equal "Fronleichnam", (Holidays.on(Date.civil(2017, 6, 15), [:at])[0] || {})[:name]
29 |
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/vendor/holidays/test/data/test_multiple_regions_with_conflicts_region_2.yaml:
--------------------------------------------------------------------------------
1 | months:
2 | 0:
3 | - name: With Function Modifier
4 | regions: [multiple_with_conflict_2]
5 | function: easter(year)
6 | function_modifier: 64
7 | - name: With Function Only Different Function Name
8 | regions: [multiple_with_conflict_2]
9 | function: conflict_custom_method_2(year)
10 | - name: With Function Only Same Function Name
11 | regions: [multiple_with_conflict_2]
12 | function: conflict_custom_method_identical_name_between_regions(year)
13 | - name: With Function Only Same Function Name - Region 2
14 | regions: [multiple_with_conflict_2]
15 | function: conflict_custom_method_identical_name_between_regions_but_different_holiday_names(year)
16 | 1:
17 | - name: New Year's Day
18 | regions: [multiple_with_conflict_2]
19 | mday: 1
20 | observed: to_tuesday_if_sunday_or_monday_if_saturday(date)
21 | 10:
22 | - name: Testing Conflict Month 10
23 | regions: [multiple_with_conflict_2]
24 | mday: 7
25 |
26 | methods:
27 | conflict_custom_method_2:
28 | arguments: year
29 | ruby: |
30 | Date.civil(year, 12, 1)
31 | conflict_custom_method_identical_name_between_regions:
32 | arguments: year
33 | ruby: |
34 | Date.civil(year, 11, 1)
35 | conflict_custom_method_identical_name_between_regions_but_different_holiday_names:
36 | arguments: year
37 | ruby: |
38 | Date.civil(year, 11, 15)
39 |
--------------------------------------------------------------------------------
/spec/system/page_objects/discourse_calendar/bulk_invite_modal.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module PageObjects
4 | module Pages
5 | module DiscourseCalendar
6 | class BulkInviteModal < PageObjects::Pages::Base
7 | def set_invitee_at_row(name, status, row_number)
8 | dropdown =
9 | PageObjects::Components::SelectKit.new(
10 | ".bulk-invite-row:nth-of-type(#{row_number}) .email-group-user-chooser",
11 | )
12 | dropdown.expand
13 | dropdown.search(name)
14 | dropdown.select_row_by_value(name)
15 |
16 | dropdown =
17 | PageObjects::Components::SelectKit.new(
18 | ".bulk-invite-row:nth-of-type(#{row_number}) .bulk-invite-attendance",
19 | )
20 | dropdown.expand
21 | dropdown.select_row_by_value(status)
22 |
23 | self
24 | end
25 |
26 | def add_invitee
27 | find(".add-bulk-invite").click
28 | self
29 | end
30 |
31 | def remove_invitee_row(row_number)
32 | find(".bulk-invite-row:nth-of-type(#{row_number}) .remove-bulk-invite").click
33 | self
34 | end
35 |
36 | def send_invites
37 | find(".send-bulk-invites").click
38 | self
39 | end
40 |
41 | def closed?
42 | has_no_css?(".post-event-bulk-invite")
43 | end
44 | end
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/lib/tasks/javascript.rake:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "open-uri"
4 |
5 | task "javascript:update_constants" => :environment do
6 | timezone_definitions =
7 | "https://raw.githubusercontent.com/moment/moment-timezone/develop/data/meta/latest.json"
8 |
9 | unused_regions = %w[
10 | ecbtarget
11 | federalreserve
12 | federalreservebanks
13 | fedex
14 | nerc
15 | unitednations
16 | ups
17 | nyse
18 | ]
19 |
20 | holidays_country_overrides = { "gr" => "el" }
21 |
22 | require "holidays" if !defined?(Holidays)
23 |
24 | holiday_regions = Holidays.available_regions.map(&:to_s) - unused_regions
25 |
26 | time_zone_to_region = {}
27 | data = JSON.parse(URI.parse(timezone_definitions).open.read)
28 | data["zones"].sort.each do |timezone, timezone_data|
29 | country_code = timezone_data["countries"].first.downcase
30 |
31 | if holidays_country_overrides.include?(country_code)
32 | country_code = holidays_country_overrides[country_code]
33 | end
34 |
35 | next if !holiday_regions.include?(country_code)
36 | time_zone_to_region[timezone] = country_code
37 | end
38 |
39 | write_template(
40 | "../../../plugins/discourse-calendar/assets/javascripts/discourse/lib/regions.js",
41 | "update_constants",
42 | <<~JS,
43 | export const HOLIDAY_REGIONS = #{holiday_regions.to_json};
44 |
45 | export const TIME_ZONE_TO_REGION = #{time_zone_to_region.to_json};
46 | JS
47 | )
48 | end
49 |
--------------------------------------------------------------------------------
/vendor/holidays/lib/holidays/definition/repository/cache.rb:
--------------------------------------------------------------------------------
1 | module Holidays
2 | module Definition
3 | module Repository
4 | class Cache
5 | def initialize
6 | reset!
7 | end
8 |
9 | def cache_between(start_date, end_date, cache_data, options)
10 | raise ArgumentError unless cache_data
11 | raise ArgumentError unless start_date && end_date
12 |
13 | @cache_range[options] = start_date..end_date
14 | @cache[options] = cache_data.group_by { |holiday| holiday[:date] }
15 | end
16 |
17 | def find(start_date, end_date, options)
18 | return nil unless in_cache_range?(start_date, end_date, options)
19 |
20 | if start_date == end_date
21 | @cache[options].fetch(start_date, [])
22 | else
23 | @cache[options].select do |date, holidays|
24 | date >= start_date && date <= end_date
25 | end.flat_map { |date, holidays| holidays }
26 | end
27 | end
28 |
29 | def reset!
30 | @cache = {}
31 | @cache_range = {}
32 | end
33 |
34 | private
35 |
36 | def in_cache_range?(start_date, end_date, options)
37 | range = @cache_range[options]
38 | if range
39 | range.begin <= start_date && range.end >= end_date
40 | else
41 | false
42 | end
43 | end
44 | end
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/assets/javascripts/discourse/models/discourse-post-event-invitees.js:
--------------------------------------------------------------------------------
1 | import { tracked } from "@glimmer/tracking";
2 | import { TrackedArray } from "@ember-compat/tracked-built-ins";
3 | import User from "discourse/models/user";
4 | import DiscoursePostEventInvitee from "./discourse-post-event-invitee";
5 |
6 | export default class DiscoursePostEventInvitees {
7 | static create(args = {}) {
8 | return new DiscoursePostEventInvitees(args);
9 | }
10 |
11 | @tracked _invitees;
12 | @tracked _suggestedUsers;
13 |
14 | constructor(args = {}) {
15 | this.invitees = args.invitees || [];
16 | this.suggestedUsers = args.meta?.suggested_users || [];
17 | }
18 |
19 | get invitees() {
20 | return this._invitees;
21 | }
22 |
23 | set invitees(invitees = []) {
24 | this._invitees = new TrackedArray(
25 | invitees.map((i) => DiscoursePostEventInvitee.create(i))
26 | );
27 | }
28 |
29 | get suggestedUsers() {
30 | return this._suggestedUsers;
31 | }
32 |
33 | set suggestedUsers(suggestedUsers = []) {
34 | this._suggestedUsers = new TrackedArray(
35 | suggestedUsers.map((su) => User.create(su))
36 | );
37 | }
38 |
39 | add(invitee) {
40 | this.invitees.push(invitee);
41 |
42 | this.suggestedUsers = this.suggestedUsers.filter(
43 | (su) => su.id !== invitee.user.id
44 | );
45 | }
46 |
47 | remove(invitee) {
48 | this.invitees = this.invitees.filter((i) => i.user.id !== invitee.user.id);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/vendor/holidays/test/holidays/finder/rules/test_in_region.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path(File.dirname(__FILE__)) + '/../../../test_helper'
2 |
3 | require 'holidays/finder/rules/in_region'
4 |
5 | class FinderRulesInRegionTests < Test::Unit::TestCase
6 | def setup
7 | @available = [:test]
8 | @subject = Holidays::Finder::Rules::InRegion
9 | end
10 |
11 | def test_returns_true_if_any_specified
12 | assert_equal(true, @subject.call([:any], @available))
13 | end
14 |
15 | def test_returns_true_if_exact_match_found
16 | assert_equal(true, @subject.call([:test], @available))
17 | end
18 |
19 | def test_returns_true_if_subregion_matches_parent
20 | assert_equal(true, @subject.call([:test_sub], @available))
21 | end
22 |
23 | def test_returns_true_if_subregion_matches_grandparent
24 | assert_equal(true, @subject.call([:test_sub_sub], @available))
25 | end
26 |
27 | def test_returns_true_if_subregion_is_in_available
28 | assert_equal(true, @subject.call([:test_sub], [:test, :test_sub]))
29 | end
30 |
31 | def test_returns_false_if_match_not_found
32 | assert_equal(false, @subject.call([:other], @available))
33 | end
34 |
35 | def test_returns_false_if_match_not_found_for_subregion
36 | assert_equal(false, @subject.call([:other_sub], @available))
37 | end
38 |
39 | def test_returns_true_if_request_includes_nonmatching_but_also_any
40 | assert_equal(true, @subject.call([:other_sub, :other, :any], @available))
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/config/locales/client.be.yml:
--------------------------------------------------------------------------------
1 | # WARNING: Never edit this file.
2 | # It will be overwritten when translations are pulled from Crowdin.
3 | #
4 | # To work with us on translations, join this project:
5 | # https://translate.discourse.org/
6 |
7 | be:
8 | js:
9 | discourse_automation:
10 | triggerables:
11 | event_started:
12 | fields:
13 | topic_id:
14 | label: Номер тэмы
15 | discourse_calendar:
16 | disable_holiday: "Адключыць"
17 | enable_holiday: "Уключыць"
18 | toolbar_button:
19 | today: "сёння"
20 | month: "месяц"
21 | week: "тыдзень"
22 | day: "дзень"
23 | discourse_post_event:
24 | upcoming_events:
25 | status: "Статус"
26 | models:
27 | event:
28 | closed: "Закрыта"
29 | status:
30 | public:
31 | title: "грамадскага"
32 | private:
33 | title: "прыватны"
34 | builder_modal:
35 | create: "стварыць"
36 | update: "захаваць"
37 | reminders:
38 | units:
39 | days: "дзён"
40 | periods:
41 | before: "перад"
42 | after: "пасля"
43 | url:
44 | label: "URL спасылка"
45 | location:
46 | label: "размяшчэнне"
47 | description:
48 | label: "Апісанне"
49 | status:
50 | label: "Статус"
51 | invite_user_or_group:
52 | invite: "адправіць"
53 |
--------------------------------------------------------------------------------
/spec/jobs/regular/discourse_post_event/bump_topic_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "rails_helper"
4 |
5 | describe Jobs::DiscoursePostEventBumpTopic do
6 | let(:admin_1) { Fabricate(:user, admin: true) }
7 | let(:topic_1) { Fabricate(:topic, user: admin_1) }
8 |
9 | before do
10 | freeze_time DateTime.parse("2019-11-10 12:00")
11 |
12 | Jobs.run_immediately!
13 |
14 | SiteSetting.calendar_enabled = true
15 | SiteSetting.discourse_post_event_enabled = true
16 | end
17 |
18 | describe "#execute" do
19 | context "when params are present" do
20 | it "creates an auto-bump topic timer" do
21 | freeze_time
22 | Jobs::DiscoursePostEventBumpTopic.new.execute(topic_id: topic_1.id, date: "2019-12-10 5:00")
23 |
24 | timer = TopicTimer.find_by(topic: topic_1)
25 | expect(timer.status_type).to eq(TopicTimer.types[:bump])
26 | expect(timer.execute_at).to eq_time(Time.zone.local(2019, 12, 10, 5, 0))
27 | end
28 | end
29 |
30 | context "when the topic_id param is missing" do
31 | it "does not throw an error if the date param is present" do
32 | expect {
33 | Jobs::DiscoursePostEventBumpTopic.new.execute(date: "2019-12-10 5:00")
34 | }.not_to raise_error
35 | end
36 | it "does not throw an error if the date param is missing" do
37 | expect { Jobs::DiscoursePostEventBumpTopic.new.execute({}) }.not_to raise_error
38 | end
39 | end
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/db/migrate/20220724130519_fix_post_event_timezones.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | class FixPostEventTimezones < ActiveRecord::Migration[7.0]
4 | def up
5 | execute <<~SQL
6 | UPDATE discourse_post_event_events
7 | SET
8 | original_starts_at = (original_starts_at::timestamp AT TIME ZONE timezone),
9 | original_ends_at = (original_ends_at::timestamp AT TIME ZONE timezone)
10 | WHERE timezone IS NOT NULL;
11 | SQL
12 |
13 | execute <<~SQL
14 | UPDATE discourse_calendar_post_event_dates
15 | SET
16 | starts_at = (starts_at::timestamp AT TIME ZONE timezone),
17 | ends_at = (ends_at::timestamp AT TIME ZONE timezone)
18 | FROM discourse_post_event_events
19 | WHERE discourse_post_event_events.id = discourse_calendar_post_event_dates.event_id
20 | AND discourse_post_event_events.timezone IS NOT NULL
21 | SQL
22 |
23 | execute <<~SQL
24 | UPDATE topic_custom_fields
25 | SET value = (value::timestamp AT TIME ZONE discourse_post_event_events.timezone) AT TIME ZONE 'UTC'
26 | FROM discourse_post_event_events
27 | JOIN posts ON discourse_post_event_events.id = posts.id
28 | WHERE discourse_post_event_events.timezone IS NOT NULL
29 | AND topic_custom_fields.topic_id = posts.topic_id
30 | AND topic_custom_fields.name IN ('TopicEventStartsAt', 'TopicEventEndsAt')
31 | SQL
32 | end
33 |
34 | def down
35 | raise ActiveRecord::IrreversibleMigration
36 | end
37 | end
38 |
--------------------------------------------------------------------------------