From 26831902cc5a87f2f9177450b7c4f1e47530c7a5 Mon Sep 17 00:00:00 2001 From: BoHung Chiu Date: Wed, 11 Jan 2023 17:46:06 +0800 Subject: [PATCH] Add signup limit feature. --- app/controllers/seminars_controller.rb | 41 +++++++++++++++++++++++++ app/models/seminar_main.rb | 40 ++++++++++++++++++++++++ app/models/seminar_signup.rb | 13 +++++++- app/views/admin/seminars/_form.html.erb | 7 +++++ app/views/seminars/index.html.erb | 3 ++ app/views/seminars/show.html.erb | 6 ++++ config/locales/en.yml | 2 ++ config/locales/zh_tw.yml | 2 ++ config/routes.rb | 4 +++ seminar.gemspec | 3 ++ 10 files changed, 120 insertions(+), 1 deletion(-) diff --git a/app/controllers/seminars_controller.rb b/app/controllers/seminars_controller.rb index 5765b2f..cc8f4fd 100644 --- a/app/controllers/seminars_controller.rb +++ b/app/controllers/seminars_controller.rb @@ -28,6 +28,7 @@ class SeminarsController < ApplicationController registration_is_open = seminar.registration_status.present? sign_up_not_yet = seminar.signup_start_date && @time_now && @seminar.signup_start_date > @time_now sign_up_overdue = seminar.signup_end_date && @time_now && (@seminar.signup_end_date + 1.day <= @time_now) + signup_is_full = seminar.signup_is_full? seminar_url = (@custom_slug ? OrbitHelper.url_to_show(@custom_slug) : OrbitHelper.url_to_show(seminar.to_param)) if !registration_is_open sign_up = t('seminar.sign_up_not_open') @@ -35,6 +36,8 @@ class SeminarsController < ApplicationController sign_up = t('seminar.sign_up_not_yet') elsif sign_up_overdue sign_up = t('seminar.sign_up_overdue') + elsif signup_is_full + sign_up = t('seminar.sign_up_is_full') else sign_up_text = t('seminar.signup') sign_up = link_to(sign_up_text, seminar.get_frontend_url(link_url), :target=>'_blank', :title=>sign_up_text) @@ -329,6 +332,7 @@ class SeminarsController < ApplicationController registration_is_open = seminar.registration_status.present? sign_up_not_yet = seminar.signup_start_date && @time_now && @seminar.signup_start_date > @time_now sign_up_overdue = seminar.signup_end_date && @time_now && (@seminar.signup_end_date + 1.day <= @time_now) + signup_is_full = seminar.signup_is_full? seminar_url = (@custom_slug ? OrbitHelper.url_to_show(@custom_slug) : OrbitHelper.url_to_show(seminar.to_param)) if !registration_is_open sign_up = t('seminar.sign_up_not_open') @@ -336,6 +340,8 @@ class SeminarsController < ApplicationController sign_up = t('seminar.sign_up_not_yet') elsif sign_up_overdue sign_up = t('seminar.sign_up_overdue') + elsif signup_is_full + sign_up = t('seminar.sign_up_is_full') else sign_up_text = t('seminar.signup') sign_up = link_to(sign_up_text, seminar.get_frontend_url(seminar_url), :target=>'_blank', :title=>sign_up_text) @@ -424,6 +430,36 @@ class SeminarsController < ApplicationController redirect_to referer_url, :notice => notice_words return end + signup_limit = @seminar.signup_limit + has_counter = false + if signup_limit + if defined?(OrbitHelper::SharedMutex) + OrbitHelper::SharedMutex.synchronize do + signup_count = OrbitHelper::SharedHash['seminar'][:counter][seminar_id] + if signup_count.nil? + signup_count = SeminarSignup.where(:seminar_main_id=>@seminar.id).count + OrbitHelper::SharedHash['seminar'][:counter][seminar_id] = signup_count + end + if signup_limit > signup_count + OrbitHelper::SharedHash['seminar'][:counter][seminar_id] = signup_count + 1 + has_counter = true + else + notice_words = t('seminar.sign_up_is_full') + referer_url = get_referer_url_for_notice(notice_words) + redirect_to referer_url, :notice => notice_words + return + end + end + else + signup_count = SeminarSignup.where(:seminar_main_id=>@seminar.id).count + if signup_limit <= signup_count + notice_words = t('seminar.sign_up_is_full') + referer_url = get_referer_url_for_notice(notice_words) + redirect_to referer_url, :notice => notice_words + return + end + end + end @signup = SeminarSignup.where(email: params[:seminar_signup][:email], seminar_main_id: seminar_id ).first @seminar_signup = SeminarSignup.new(seminar_signup_params) @@ -463,6 +499,11 @@ class SeminarsController < ApplicationController end redirect_to "#{params[:referer_url].to_s.chomp('/').gsub(/\/([^\/?#]+)(|[^\/]+)$/){|f| '/'+$1}}?method=signup_ok#{status_param}&serial_number=#{@seminar_signup.display_serial_number}" else + if has_counter + OrbitHelper::SharedMutex.synchronize do + OrbitHelper::SharedHash['seminar'][:counter][seminar_id] = OrbitHelper::SharedHash['seminar'][:counter][seminar_id] - 1 + end + end if !not_signup_yet notice_words = t('seminar.email_exist') referer_url = get_referer_url_for_notice(notice_words) diff --git a/app/models/seminar_main.rb b/app/models/seminar_main.rb index f95d74b..d1eb37c 100644 --- a/app/models/seminar_main.rb +++ b/app/models/seminar_main.rb @@ -51,6 +51,9 @@ class SeminarMain field :last_serial_number, :type => Integer, :default => 0 field :assign_mode, :type => Integer, :default => 0 # 0 => 用default signup ids來分配 ,1 => 用final_session來分配, 2 => 用final_session來分配(當有preffered session欄位時) field :update_old_flag, :type => Boolean, :default => false + + field :signup_limit, :type => Integer, :default => nil + belongs_to :seminar_item belongs_to :organizer , :class_name=>"MemberProfile", :foreign_key => :organizer_id has_many :seminar_sessions, :autosave => true, :dependent => :destroy @@ -80,6 +83,12 @@ class SeminarMain accepts_nested_attributes_for :seminar_signup_field_customs, :allow_destroy => true accepts_nested_attributes_for :seminar_template_setting, :allow_destroy => true before_save do + if self.signup_limit == 0 + self.signup_limit = nil + end + if self.signup_limit_changed? + self.sync_signup_count + end module_app_key = "seminar" add_module_app_member_ids = [] remove_module_app_member_ids = [] @@ -257,6 +266,37 @@ class SeminarMain self.enable_recaptcha = (self.seminar_signup_field_sets.where(:field_name=>'recaptcha', :disabled.ne=>true).count != 0) self.save end + def sync_signup_count + if defined?(OrbitHelper::SharedMutex) + seminar_id =self.id.to_s + OrbitHelper::SharedMutex.synchronize do + if self.signup_limit.nil? + OrbitHelper::SharedHash['seminar'][:counter][seminar_id] = nil + else + signup_count = SeminarSignup.where(:seminar_main_id=>self.id).count + OrbitHelper::SharedHash['seminar'][:counter][seminar_id] = signup_count + end + end + end + end + def signup_is_full? + tmp_signup_limit = self.signup_limit + return false if tmp_signup_limit.nil? + if defined?(OrbitHelper::SharedMutex) + seminar_id =self.id.to_s + signup_count = 0 + OrbitHelper::SharedMutex.synchronize do + signup_count = OrbitHelper::SharedHash['seminar'][:counter][seminar_id] + if signup_count.nil? + signup_count = SeminarSignup.where(:seminar_main_id=>self.id).count + OrbitHelper::SharedHash['seminar'][:counter][seminar_id] = signup_count + end + end + else + signup_count = SeminarSignup.where(:seminar_main_id=>self.id).count + end + return (tmp_signup_limit <= signup_count) + end def self.time_range(date1 = null, date2 = null) if !date1.blank? diff --git a/app/models/seminar_signup.rb b/app/models/seminar_signup.rb index 4fde0df..c73aef2 100644 --- a/app/models/seminar_signup.rb +++ b/app/models/seminar_signup.rb @@ -30,7 +30,18 @@ class SeminarSignup accepts_nested_attributes_for :seminar_signup_values, allow_destroy: true accepts_nested_attributes_for :seminar_signup_contributes, allow_destroy: true scope :sort_ordered, ->{ order_by(:sort_number=>1,:created_at=>1) } - + after_destroy do + if defined?(OrbitHelper::SharedMutex) + OrbitHelper::SharedMutex.synchronize do + seminar_id = self.seminar_main_id.to_s + signup_count = OrbitHelper::SharedHash['seminar'][:counter][seminar_id] + if signup_count + signup_count -= 1 + OrbitHelper::SharedHash['seminar'][:counter][seminar_id] = signup_count + end + end + end + end before_create do unit = self.unit_translations.values.select{|v| v.present?}.first tmp_unit_translations = self.unit_translations diff --git a/app/views/admin/seminars/_form.html.erb b/app/views/admin/seminars/_form.html.erb index b026be9..e0c6ecb 100644 --- a/app/views/admin/seminars/_form.html.erb +++ b/app/views/admin/seminars/_form.html.erb @@ -112,6 +112,13 @@ +
+ +
+ <%= f.number_field :signup_limit, placeholder: t('seminar.blank_no_limit') %> +
+
+
diff --git a/app/views/seminars/index.html.erb b/app/views/seminars/index.html.erb index e0108df..a64cdf1 100644 --- a/app/views/seminars/index.html.erb +++ b/app/views/seminars/index.html.erb @@ -26,6 +26,7 @@ registration_is_open = seminar.registration_status.present? sign_up_not_yet = seminar.signup_start_date && @time_now && seminar.signup_start_date > @time_now sign_up_overdue = seminar.signup_end_date && @time_now && (seminar.signup_end_date + 1.day <= @time_now) + signup_is_full = seminar.signup_is_full? seminar_url = OrbitHelper.url_to_show(seminar.to_param) if !registration_is_open sign_up = t('seminar.sign_up_not_open') @@ -33,6 +34,8 @@ sign_up = t('seminar.sign_up_not_yet') elsif sign_up_overdue sign_up = t('seminar.sign_up_overdue') + elsif signup_is_full + sign_up = t('seminar.sign_up_is_full') else sign_up_text = t('seminar.signup') sign_up = link_to(sign_up_text, seminar.get_frontend_url(seminar_url), :target=>'_blank', :title=>sign_up_text) diff --git a/app/views/seminars/show.html.erb b/app/views/seminars/show.html.erb index 2608529..b77212b 100644 --- a/app/views/seminars/show.html.erb +++ b/app/views/seminars/show.html.erb @@ -12,6 +12,7 @@ registration_is_open = @seminar.registration_status.present? sign_up_not_yet = @seminar.signup_start_date && @time_now && @seminar.signup_start_date > @time_now sign_up_overdue = @seminar.signup_end_date && @time_now && (@seminar.signup_end_date + 1.day <= @time_now) + signup_is_full = @seminar.signup_is_full? %> <% if !registration_is_open %> @@ -24,6 +25,11 @@ <% elsif sign_up_overdue %> <%= t('seminar.sign_up_overdue') %> + +<% elsif signup_is_full %> + +<%= t('seminar.sign_up_is_full') %> + <% else %> <%#= stylesheet_link_tag "lib/main-forms" %> <%= stylesheet_link_tag "basic/bootstrap-datetimepicker" %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 1a7e1f3..c316bfa 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -27,6 +27,7 @@ en: abstract_number: Abstract number presentation_type: Presentation seminar: + signup_limit: Signup Limit participant_list: Participant list back: Back please_login_first: "Please login first!" @@ -154,6 +155,7 @@ en: sign_up_not_yet: Does Not Yet Allow Sign Up #報名時間未開始 sign_up_not_open: Does Not Open Sign Up #未開放報名 sign_up_overdue: Sign Up Overdue #報名時間已過 + sign_up_is_full: "Sign up is FULL!" sign_up_failed: "Sign up failed!" contribute_file_count: Count of Contribute Files #投稿檔案數 diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index 58e1a9e..a31cc88 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -28,6 +28,7 @@ zh_tw: abstract_number: 摘要編號 presentation_type: 發表方式 seminar: + signup_limit: 報名限制人數 participant_list: 參加者名單 back: 回上一頁 please_login_first: "請先登入!" @@ -155,6 +156,7 @@ zh_tw: sign_up_not_yet: 報名時間未開始 sign_up_not_open: 未開放報名 sign_up_overdue: 報名時間已過 + sign_up_is_full: "報名已額滿!" sign_up_failed: "報名失敗" contribute_file_count: 投稿檔案數 diff --git a/config/routes.rb b/config/routes.rb index 78e33d2..3a242de 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,8 @@ Rails.application.routes.draw do + OrbitHelper::SharedMutex.synchronize do + OrbitHelper::SharedHash['seminar'][:counter] = SeminarMain.where(:signup_limit.ne => nil).map{|v| [v.id, v.seminar_signups.count]}.to_h + OrbitHelper::SharedHash['seminar'][:limit] = SeminarMain.where(:signup_limit.ne => nil).map{|v| [v.id, v.signup_limit]}.to_h + end Thread.new do if Page.fields.include?('all_pageids') s = Site.first diff --git a/seminar.gemspec b/seminar.gemspec index ad6ef40..bd040b5 100644 --- a/seminar.gemspec +++ b/seminar.gemspec @@ -93,4 +93,7 @@ Gem::Specification.new do |s| s.test_files = Dir["test/**/*"] s.add_dependency "custom_announcement" s.add_dependency "custom_gallery" + s.metadata = { + "global_hash" => "{counter: {}, limit: {}}" + } end