app/models/group.rb
class Group < ApplicationRecord
has_dag_links ancestor_class_names: %w(Group Page Event), descendant_class_names: %w(Group User Page Workflow Project Post), link_class_name: 'DagLink'
default_scope { includes(:flags) }
scope :regular, -> {
where(type: nil).or(where.not(type: "Groups::PhvsParent")).not_flagged([:contact_people, :attendees, :officers_parent, :admins_parent, :group_of_groups, :everyone, :corporations_parent, :bvs_parent, :wbl_abo])
}
scope :has_descendant_users, -> { includes(:descendant_users).where(users: { id: nil }) }
include Structureable
include GroupGraph
include Navable
include GroupMemberships
include GroupMemberList
include GroupEveryone
include GroupMixins::Corporations
include GroupMixins::Roles
include GroupMixins::Guests
include GroupMixins::HiddenUsers
include GroupMixins::Developers
include GroupMixins::Officers
include GroupMixins::Import
include GroupPosts
include GroupAttachments
include GroupProfile
include GroupMailingLists
include GroupDummyUsers
include GroupWelcomeMessage
include GroupSemesterCalendars
include GroupEvents
include GroupListExports
include GroupMapItem
include HasProfile
include GroupSearch
include GroupAvatar
include GroupCharts
include GroupPublicWebsite
include GroupHeraldics
# Easy group settings: https://github.com/huacnlee/rails-settings-cached
# For example:
#
# group = Group.find(123)
# group.settings.color = :red
# group.settings.color # => :red
#
include RailsSettings::Extend
after_create :import_default_group_structure # from GroupMixins::Import
# General Properties
# ==========================================================================================
# The title of the group, i.e. a kind of caption, e.g. used in the <title> tag of the
# webpage. By default, this returns just the name of the group. But this may be changed
# in the main application.
#
def title
self.name
end
# The name of the group.
# If there is a translation for that group name, e.g. for a generic group name like
# 'admins', use the translation.
#
def name
I18n.t( super.to_sym, default: super ) if defined?(super) && super.present?
end
def name_with_surrounding
name
end
def extensive_name
if has_flag? :attendees
name + (parent_events.first ? ": " + parent_events.first.name : '')
elsif has_flag? :contact_people
name + (parent_events.first ? ": " + parent_events.first.name : '')
elsif has_flag?(:admins_parent) && parent_groups.first.try(:parent_groups).try(:first)
name + ": " + parent_groups.first.parent_groups.first.name
elsif super.present?
super
else
name
end
end
def name_with_corporation
if self.corporation_id && (self.corporation_id != self.id)
"#{self.name} #{self.corporation.name}"
else
self.name
end
end
# This sets the format of the Group urls to be
#
# example.com/groups/24-planeswalkers
#
# rather than just
#
# example.com/groups/24
#
def to_param
"#{id} #{title}".parameterize
end
# Mark this group of groups, i.e. the primary members of the group are groups,
# not users. This does not effect the DAG structure, but may affect the way
# the group is displayed.
#
def group_of_groups?
has_flag? :group_of_groups
end
def group_of_groups=(add_the_flag)
add_the_flag ? add_flag(:group_of_groups) : remove_flag(:group_of_groups)
end
# Associated Objects
# ==========================================================================================
# Workflows
# ------------------------------------------------------------------------------------------
# These methods override the standard methods, which are usual ActiveRecord associations
# methods created by the acts-as-dag gem
# (https://github.com/resgraph/acts-as-dag/blob/master/lib/dag/dag.rb).
# But since the Workflow in the main application
# inherits from WorkflowKit::Workflow and single table inheritance and polymorphic
# associations do not always work together as expected in rails, as can be seen here
# http://stackoverflow.com/questions/9628610/why-polymorphic-association-doesnt-work-for-sti-if-type-column-of-the-polymorph,
# we have to override these methods.
#
# ActiveRecord associations require 'WorkflowKit::Workflow' to be stored in the database's
# type column, but by asking for the `child_workflows` we want to get òbjects of the
# `Workflow` type, not `WorkflowKit::Workflow`, since Workflow objects may have
# additional methods, added by the main application.
#
def descendant_workflows
Workflow
.joins( :links_as_descendant )
.where( :dag_links => { :ancestor_type => "Group", :ancestor_id => self.id } )
.distinct
end
def child_workflows
self.descendant_workflows.where( :dag_links => { direct: true } )
end
# Adress Labels (PDF)
# options:
# - sender: Sender line including sender address.
# - book_rate: Whether the "Büchersendung"/"Envois à taxe réduite" badge
# is to be printed.
# - filter: ["without_email", "with_local_postal_mail_subscription"]
#
def members_to_pdf(options = {sender: '', book_rate: false, type: "AddressLabelsPdf"})
@filter = options[:filter]
#timestamp = cached_members_postal_addresses_created_at || Time.zone.now
timestamp = Time.zone.now
options[:type].constantize.new(members_postal_addresses, title: self.title, updated_at: timestamp, **options).render
end
def members_postal_addresses
# Sort alphabetically:
members
.apply_filter(@filter)
.order(:last_name, :first_name)
.collect { |user| user.address_label }
# # Sort by address:
# members
# .apply_filter(@filter)
# .collect { |user| user.address_label }
# .sort_by { |address_label| (not address_label.country_code == 'DE').to_s + address_label.country_code.to_s + address_label.postal_code.to_s }
end
# def cached_members_postal_addresses_created_at
# Rails.cache.fetch [self.cache_key, "cached_members_postal_addresses_created_at", @filter] do
# members.apply_filter(@filter).collect { |user| user.cache_created_at(:address_label) || Time.zone.now }.min
# end
# end
# Groups
# ------------------------------------------------------------------------------------------
def descendant_groups_by_name( descendant_group_name )
self.descendant_groups.where( :name => descendant_group_name )
end
def corporation
Corporation.find corporation_id if corporation_id
end
def corporation_id
(([self.id] + ancestor_group_ids) & Corporation.pluck(:id)).first
end
def corporation?
kind_of? Corporation
end
# This returns all sub-groups of the corporation that have no
# sub-groups of their ownes except for officer groups.
# This is needed for the selection of status groups.
#
def leaf_groups
Group.find(leaf_group_ids)
end
def leaf_group_ids
self.descendant_groups.order('id').includes(:flags).select { |group|
group.has_no_subgroups_other_than_the_officers_parent? and not group.is_officers_group?
}.map(&:id).uniq
end
def status_groups
descendant_groups.where(type: "StatusGroup")
end
def status_group_ids
status_groups.pluck(:id)
end
def status_group_tree
child_groups_with_status_groups.collect do |child_group|
{
id: child_group.id,
name: child_group.name,
type: child_group.type,
children: child_group.status_group_tree
}
end
end
def status_group_tree_ids
child_groups_with_status_groups.collect { |child_group| [child_group, child_group.descendant_groups] }.flatten.map(&:id)
end
def child_groups_with_status_groups
child_groups & (status_groups + status_groups.map(&:ancestor_groups)).flatten
end
def status_groups_with_level(group_hash_array = status_group_tree, level = 0)
group_hash_array.collect do |entry|
entry[:level] = level
children = status_groups_with_level(entry[:children], level + 1)
entry[:children] = nil
[entry, children]
end.flatten
end
def find_deceased_members_parent_group
self.descendant_groups.where(name: ["Verstorbene", "Deceased"]).limit(1).first
end
def deceased
find_deceased_members_parent_group
end
# This is an alias for the group that represents the main organization.
# This is, for example, used to determine when the membership in the
# main org ended.
#
# Feel free to override this method in the main app to match your
# organizational structure.
#
def self.main_org
self.corporations_parent
end
def self.support
find_or_create_special_group :support
end
include GroupCaching if use_caching?
end