diff --git a/app/controllers/course_management/curriculums_controller.rb b/app/controllers/course_management/curriculums_controller.rb
index ef79810c2..4553a6c94 100644
--- a/app/controllers/course_management/curriculums_controller.rb
+++ b/app/controllers/course_management/curriculums_controller.rb
@@ -3,7 +3,7 @@
module CourseManagement
class CurriculumsController < ApplicationController
include PagyBackendWithHelpers
- before_action :set_curriculum, only: %i[show edit update destroy courses]
+ before_action :set_curriculum, only: %i[show edit update destroy openable_courses]
def index
curriculums = Curriculum.includes(:unit)
@@ -44,9 +44,9 @@ def destroy
redirect_with(message)
end
- def courses
- @courses = @curriculum.courses
- render json: @courses
+ def openable_courses
+ @curriculum = CurriculumDecorator.new(@curriculum)
+ render json: @curriculum.openable_courses_for_active_term
end
private
diff --git a/app/decorators/curriculum_decorator.rb b/app/decorators/curriculum_decorator.rb
new file mode 100644
index 000000000..840da3112
--- /dev/null
+++ b/app/decorators/curriculum_decorator.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CurriculumDecorator < SimpleDelegator
+ def openable_courses_for_active_term(appends: nil)
+ term = AcademicTerm.active.last.try(:term)
+
+ return [] unless term
+
+ courses = semesters.where(term: term)
+ .includes(:courses)
+ .where.not(courses: { id: available_courses.pluck(:course_id) })
+ .order('courses.name')
+ .map(&:courses)
+ [*appends, courses].flatten
+ end
+end
diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb
index 85af1c2b8..6d63f8ce9 100644
--- a/app/helpers/link_helper.rb
+++ b/app/helpers/link_helper.rb
@@ -1,62 +1,79 @@
# frozen_string_literal: true
module LinkHelper
- def link_to_back(path = nil, text = t('action_group.back'))
- link_to(
- fa_icon('arrow-left', text: text),
- path,
- class: 'btn btn-secondary btn-sm'
- )
- end
-
- def link_to_destroy(path = nil, text = t('action_group.destroy'))
- link_to(
- fa_icon('trash', text: text),
- path,
- method: :delete,
- data: { confirm: t('are_you_sure') },
- class: 'btn btn-outline-danger btn-sm'
- )
- end
-
- def link_to_edit(path = nil, text = t('action_group.edit'))
- link_to(
- fa_icon('pencil', text: text),
- path,
- class: 'btn btn-outline-success btn-sm'
- )
- end
+ LINKS = {
+ back: {
+ icon: 'arrow-left',
+ text: I18n.t('action_group.back'),
+ options: {
+ class: 'btn btn-secondary btn-sm'
+ }
+ },
+ destroy: {
+ icon: 'trash',
+ text: I18n.t('action_group.destroy'),
+ options: {
+ class: 'btn btn-outline-danger btn-sm',
+ method: :delete,
+ data: { confirm: I18n.t('are_you_sure') }
+ }
+ },
+ edit: {
+ icon: 'pencil',
+ text: I18n.t('action_group.edit'),
+ options: {
+ class: 'btn btn-outline-success btn-sm'
+ }
+ },
+ new: {
+ icon: 'plus',
+ text: I18n.t('action_group.add'),
+ options: {
+ class: 'btn btn-outline-primary btn-sm',
+ id: 'add-button'
+ }
+ },
+ show: {
+ icon: 'eye',
+ text: I18n.t('action_group.show'),
+ options: {
+ class: 'btn btn-outline-info btn-sm'
+ }
+ },
+ update: {
+ icon: 'pencil-square-o',
+ text: I18n.t('action_group.update'),
+ options: {
+ class: 'btn btn-outline-info btn-sm'
+ }
+ },
+ file: {
+ icon: 'file-word-o',
+ text: I18n.t('action_group.file'),
+ options: {
+ class: 'btn btn-secondary btn-sm'
+ }
+ }
+ }.freeze
- def link_to_new(path = nil, text = t('action_group.add'))
- link_to(
- fa_icon('plus', text: text),
- path,
- class: 'btn btn-outline-primary btn-sm',
- id: 'add-button'
- )
+ LINKS.each do |action, configuration|
+ define_method("link_to_#{action}") do |*args|
+ link_builder(args, configuration)
+ end
end
- def link_to_show(path = nil, text = t('action_group.show'))
- link_to(
- fa_icon('eye', text: text),
- path,
- class: 'btn btn-outline-info btn-sm'
- )
- end
+ private
- def link_to_update(path = nil, text = t('action_group.update'))
+ def link_builder(args, configuration)
+ text, path = split_args_for_link_to(args)
link_to(
- fa_icon('pencil-square-o', text: text),
+ fa_icon(configuration[:icon], text: text || configuration[:text]),
path,
- class: 'btn btn-outline-info btn-sm'
+ configuration.fetch(:options, {})
)
end
- def link_to_file(path = nil, text = t('action_group.file'))
- link_to(
- fa_icon('file-word-o', text: text),
- path,
- class: 'btn btn-secondary btn-sm'
- )
+ def split_args_for_link_to(args)
+ args.length == 1 ? [nil, *args] : args
end
end
diff --git a/app/models/academic_term.rb b/app/models/academic_term.rb
index ea90125f4..dc071378a 100644
--- a/app/models/academic_term.rb
+++ b/app/models/academic_term.rb
@@ -3,6 +3,9 @@
class AcademicTerm < ApplicationRecord
include EnumForTerm
+ # callbacks
+ after_save -> { AcademicTerm.where.not(id: id).update(active: false) }, if: :active?
+
# relations
has_many :calendars, dependent: :nullify
has_many :registration_documents, dependent: :nullify
@@ -12,6 +15,7 @@ class AcademicTerm < ApplicationRecord
validates :start_of_term, presence: true
validates :end_of_term, presence: true
validates :active, inclusion: { in: [true, false] }
+ validates_with AcademicTermValidator
# scopes
scope :active, -> { where(active: true) }
diff --git a/app/validators/academic_term_validator.rb b/app/validators/academic_term_validator.rb
new file mode 100644
index 000000000..09aab524d
--- /dev/null
+++ b/app/validators/academic_term_validator.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AcademicTermValidator < ActiveModel::Validator
+ def validate(record)
+ return if record.active?
+ return if AcademicTerm.where.not(id: record.id).exists?(active: true)
+
+ record.errors[:active] << I18n.t('active_check', scope: %i[validators academic_term])
+ end
+end
diff --git a/app/views/account/addresses/index.html.erb b/app/views/account/addresses/index.html.erb
index 1bd97a7e1..c36a21af6 100644
--- a/app/views/account/addresses/index.html.erb
+++ b/app/views/account/addresses/index.html.erb
@@ -1,6 +1,6 @@
<%= link_to_back user_path(@user) %>
- <%= link_to_new(new_user_address_path(@user), t('.new_address')) unless @user.addresses.informal.present? %>
+ <%= link_to_new(t('.new_address'), new_user_address_path(@user)) unless @user.addresses.informal.present? %>
<%= link_to (@addresses.formal.present? ? t('.update_from_mernis') : t('.create_from_mernis') ), save_from_mernis_user_addresses_path, class: "btn btn-outline-primary btn-sm" %>
diff --git a/app/views/account/identities/index.html.erb b/app/views/account/identities/index.html.erb
index 5ce0b2d62..5b3edefbc 100644
--- a/app/views/account/identities/index.html.erb
+++ b/app/views/account/identities/index.html.erb
@@ -1,6 +1,6 @@
<%= link_to_back user_path(@user) %>
- <%= link_to_new(new_user_identity_path(@user), t('.new_identity')) unless @user.identities.informal.present? %>
+ <%= link_to_new(t('.new_identity'), new_user_identity_path(@user)) unless @user.identities.informal.present? %>
<%= link_to (@identities.formal.present? ? t('.update_from_mernis') : t('.create_from_mernis') ), save_from_mernis_user_identities_path, class: "btn btn-outline-primary btn-sm" %>
diff --git a/app/views/admin/cities/show.html.erb b/app/views/admin/cities/show.html.erb
index 42113db6e..13f83c1d7 100644
--- a/app/views/admin/cities/show.html.erb
+++ b/app/views/admin/cities/show.html.erb
@@ -29,7 +29,7 @@
diff --git a/app/views/admin/countries/show.html.erb b/app/views/admin/countries/show.html.erb
index 9d8a5326c..3c3d7b5ab 100644
--- a/app/views/admin/countries/show.html.erb
+++ b/app/views/admin/countries/show.html.erb
@@ -45,7 +45,7 @@
diff --git a/app/views/calendar_management/calendars/index.html.erb b/app/views/calendar_management/calendars/index.html.erb
index c46242193..14252cfd7 100644
--- a/app/views/calendar_management/calendars/index.html.erb
+++ b/app/views/calendar_management/calendars/index.html.erb
@@ -4,7 +4,7 @@
diff --git a/app/views/committee/agenda_types/index.html.erb b/app/views/committee/agenda_types/index.html.erb
index 645f70abc..45b0f16c5 100644
--- a/app/views/committee/agenda_types/index.html.erb
+++ b/app/views/committee/agenda_types/index.html.erb
@@ -1,5 +1,5 @@
- <%= link_to_new new_agenda_type_path, t('.new_agenda_type_link') %>
+ <%= link_to_new t('.new_agenda_type_link'), new_agenda_type_path %>
diff --git a/app/views/committee/agendas/index.html.erb b/app/views/committee/agendas/index.html.erb
index e14ab6f94..ec1fbe45b 100644
--- a/app/views/committee/agendas/index.html.erb
+++ b/app/views/committee/agendas/index.html.erb
@@ -1,5 +1,5 @@
- <%= link_to_new new_committee_agenda_path(@committee), t('.new_agenda_link') %>
+ <%= link_to_new t('.new_agenda_link'), new_committee_agenda_path(@committee) %>
<%= link_to(fa_icon('archive', text: t('.meetings')),
committee_meetings_path(@committee),
diff --git a/app/views/committee/decisions/show.html.erb b/app/views/committee/decisions/show.html.erb
index 25fb5c3cd..bd50ce0e2 100644
--- a/app/views/committee/decisions/show.html.erb
+++ b/app/views/committee/decisions/show.html.erb
@@ -39,7 +39,7 @@
diff --git a/app/views/committee/meetings/index.html.erb b/app/views/committee/meetings/index.html.erb
index ce8ac4ac6..86f5298cc 100644
--- a/app/views/committee/meetings/index.html.erb
+++ b/app/views/committee/meetings/index.html.erb
@@ -1,5 +1,5 @@
- <%= link_to_new new_committee_meeting_path(@committee), t('.new_committee_meeting_link') %>
+ <%= link_to_new t('.new_committee_meeting_link'), new_committee_meeting_path(@committee) %>
<%= link_to(fa_icon('tasks', text: t('.agendas')), committee_agendas_path(@committee),
class: 'btn btn-dark btn-sm') %>
diff --git a/app/views/committee/meetings/show.html.erb b/app/views/committee/meetings/show.html.erb
index 8fdea1c26..7ccb215d1 100644
--- a/app/views/committee/meetings/show.html.erb
+++ b/app/views/committee/meetings/show.html.erb
@@ -56,10 +56,10 @@
<%= agenda.decision.try(:decision_no) %> |
<% if agenda.decision.present? %>
- <%= link_to_show(committee_meeting_agenda_decision_path(@committee, agenda, agenda.decision), t('.show_decision')) %>
- <%= link_to_edit(edit_committee_meeting_agenda_decision_path(@committee, agenda), t('.update_decision')) %>
+ <%= link_to_show(t('.show_decision'), committee_meeting_agenda_decision_path(@committee, agenda, agenda.decision)) %>
+ <%= link_to_edit(t('.update_decision'), edit_committee_meeting_agenda_decision_path(@committee, agenda)) %>
<% else %>
- <%= link_to_new(new_committee_meeting_agenda_decision_path(@committee, agenda), t('.create_decision')) %>
+ <%= link_to_new(t('.create_decision'), new_committee_meeting_agenda_decision_path(@committee, agenda)) %>
<% end %>
|
diff --git a/app/views/course_management/available_courses/_evaluation_types.html.erb b/app/views/course_management/available_courses/_evaluation_types.html.erb
index 4ecbf5dff..53281ebc1 100644
--- a/app/views/course_management/available_courses/_evaluation_types.html.erb
+++ b/app/views/course_management/available_courses/_evaluation_types.html.erb
@@ -3,7 +3,7 @@
diff --git a/app/views/course_management/available_courses/_form.html.erb b/app/views/course_management/available_courses/_form.html.erb
index 73982b4f5..f5292f1b9 100644
--- a/app/views/course_management/available_courses/_form.html.erb
+++ b/app/views/course_management/available_courses/_form.html.erb
@@ -20,16 +20,26 @@
<% end %>
- <%= f.association :unit, collection: Unit.active.coursable.order(:name), label_method: :names_depth_cache %>
+ <%= f.association :unit,
+ collection: Unit.active.coursable.order(:name),
+ label_method: :names_depth_cache %>
- <%= f.association :curriculum, collection: f.object.unit.present? ? f.object.unit.managed_curriculums : [] %>
+ <%= f.association :curriculum,
+ collection: [*f.object.unit.try(:managed_curriculums)] %>
- <%= f.association :coordinator, collection: f.object.unit.present? ? f.object.unit.subtree_employees : [], label_method: lambda { |c| full_name(c) } %>
+ <%= f.association :coordinator,
+ collection: [*f.object.unit.try(:subtree_employees)],
+ label_method: lambda { |c| full_name(c) } %>
- <%= f.association :course, collection: f.object.curriculum.present? ? f.object.curriculum.courses : [] %>
+ <% if f.object.curriculum %>
+ <% courses = CurriculumDecorator.new(f.object.curriculum)
+ .openable_courses_for_active_term(appends: f.object.course) %>
+ <% end %>
+ <%= f.association :course,
+ collection: [*courses] %>