Skip to content

Redmine Social Extends

Oliver Skawronek edited this page Jun 17, 2015 · 1 revision

Im Modul RedmineSocialExtends werden bestehende Modell-Klassen und Controller-Klassen von Redmine zur Laufzeit um weitere Funktionalitäten ergänzt. Alle Erweiterungen befinden sich im Projektverzeichnis escience/plugins/redmine_social/lib/redmine_social. Ausnahme hiervon bildet patch_pagination.rb, welches nicht zum RedmineSocialExtends gehört.

Inhaltsverzeichnis

Ablaufbeschreibung init.rb

Zur Laufzeit werden die Klassen um weitere Klassen- und Instanzmethoden ergänzt, die vom Plugin redmine_social benötigt werden. Koordiniert wird das über init.rb. Sie ist für das Plugin redmine_social also essentiell. Für das Testen des Plugins wird sie bspw. über redmine_social/test/test_helper.rb eingebunden.

Anhand von User soll der Ablauf beschrieben werden. In der init.rb wird die Klasse User zur Laufzeit via

User.send(:include, ::RedmineSocialExtends::UserExtension)

erweitert. User.send(:include, <Module>) ist synonym zu User.include(<Module>). User wird damit zu einem sog. Mixin, d. h. eine Klasse kombiniert mit einem Modul. Das Modul UserExtension ist in lib/patch_user.rb definiert und hat folgenden Aufbau:

module UserExtension
  module ClassMethods
    # ...
  end

  module InstanceMethods
    # ...
  end

  def self.included(receiver)
    receiver.extend  ClassMethods
    receiver.send :include, InstanceMethods
    receiver.class_eval do
      # ...
    end
  end
end
  1. Nach dem Aufruf von User.send :include, RedmineSocialExtends::UserExtension wird die Methode UserExtension#self.included(receiver) aufgerufen. Der Methode wird hier das Klassenobjekt User an receiver übergeben.
  2. Über receiver.extend ClassMethods werden receiver alle Methoden des Moduls UserExtension::ClassMethods als Klassenmethoden hinzugefügt.
  3. Analog dazu werden über receiver.send :include, InstanceMethods receiver alle Methoden des Moduls UserExtension::InstanceMethods als Instanzmethoden hinzugefügt.

Danach stehen also receiver (hier der Klasse User) alle Methoden von ClassMethods als Klassenmethoden und alle Methoden von InstanceMethods als Instanzmethoden zur Verfügung. Sie können über User.a_class_method bzw. my_user.a_instance_method aufgerufen werden.

receiver.class_eval führt den übergebenen Code-Block zur Laufzeit zwischen

class User
  # und
end

aus. Das Redmine-Social-Plugin nutzt das, um bspw. zusätzliche Action-Filter, Assoziationen und Validatoren zu ergänzen:

# Modul UserExtension
def self.included(receiver)
  receiver.class_eval do
    validates :skill_list, length: { maximum: 20 }
    has_many :photos, :order => "created_at desc", :dependent => :destroy
  end
end

# Modul UsersController
def self.included(receiver)
  receiver.class_eval do
    before_filter :require_admin, :except => [:show, :user_search, :contact_member_search, :online_live_count, :crop_profile_photo, :upload_profile_photo]
  end
end

Leider werden auch über receiver.class_eval Methoden ergänzt, sodass nicht alle Methoden in den Modulen ClassMethods und InstanceMethods zu finden sind:

# Modul UsersController
def self.included(receiver)
  receiver.class_eval do
    def update
      #...
    end

    def contact_member_search
      #...
    end

    def require_user_security(user_id)
      #...
    end
  end
end

Die instanzmethoden update, contact_member_search, require_user_security(user_id) sind also nicht im Modul InstanceMethods sondern im Codeblock für receiver.class_eval definiert. Auch sie können dann über bspw. my_user.update aufgerufen werden.

Im Folgenden werden alle Erweiterungen nach Klassen geordnet aufgelistet


User

Klassenmethoden

  • security_hash
  • calc_security_number(sec_hash)
  • method_missing(method_name, *args, &block)

Instanzmethoden

  • avatar_photo_url(size = :original)
  • selected_security_options
  • sort
  • can_request_friendship_with(user)
  • friendship_exists_with?(friend)
  • has_reached_daily_friend_request_limit?
  • create_private_project(user=self)

Validatoren

  • validates :interest_list, length: { maximum: 20 }
  • validates :skill_list, length: { maximum: 20 }

Assoziationen

  • has_many :photos
  • has_many :albums
  • belongs_to :avatar
  • has_many :friendships
  • has_many :accepted_friendships
  • has_many :pending_friendships
  • has_many :friendships_initiated_by_me
  • has_many :friendships_not_initiated_by_me
  • has_many :occurances_as_friend
  • belongs_to :private_project

UsersController

Instanzmethoden

  • upload_profile_photo
  • tag_search
  • crop_profile_photo
  • update
  • contact_member_search
  • require_user_security(user_id)

Action-Filter

  • before_filter :require_admin, ...
  • before_filter(:only => [:show]){ ... }

AppointmentsController

Instanzmethoden

  • edit

CommentsController

Instanzmethoden

  • create_general_comment

Action-Filter

  • before_filter :find_model_object
  • before_filter :find_project_from_association
  • before_filter :authorize

UserMessage

Instanzmethoden

  • send_mails
  • get_history
  • generate_sent_receiver_copy(receiver_id = self.receiver_id, receiver_list = nil)
  • recipients_mail
  • receiver_list

Assoziationen

  • has_and_belongs_to_many :group_invitations
  • belongs_to :parent

Action-Filter

  • after_save :send_mails

UserMessagesController

Instanzmethoden

  • private get_reply_message
  • create
  • history_messages

Action-Filter

  • before_filter :get_reply_message, :only => [:new, :create, :show]

Project

Assoziationen

  • has_many :albums
  • has_one :exclusive_user

ProjectsHelper

Instanzmethoden

  • private_project_settings_tabs(project=nil)

ProjectsController

Instanzmethoden

  • private no_private_project

Action-Filter

  • before_filter :no_private_project, :only => [:show]

Mailer

Klassenemthoden

  • message_id_for(object)

Instanzmethoden

  • comment_added(comment)
  • user_message_sent(user_message)

MyController

Instanzmethoden

  • interest_search
  • skill_search
  • prepare_tag_params
  • render_block
  • account

Attachment

Instanzmethoden

  • sort
  • render_to_image(options=nil)
  • image_convertable?
  • thumbnailable?
  • thumbnail(options={})

AttachmentsController

Instanzmethoden

  • show
  • thumbnail
  • sent_render_to_image(options=nil)

AccountController

Instanzmethoden

  • set_initial_session_scope

Action-Filter

  • after_filter :set_initial_session_scope, :only => [:login]

SettingsHelper

Instanzmethoden

  • generate_select_from_key(key,value,name_pre,display_attribute="name")
  • settings_hash_to_html(settings,name_pre="settings")

ApplicationController

Instanzmethoden

  • set_user_session_scope
  • generate_qr_code(url = params[:p_url], size_x=30, size_y=30)

AccountController

Instanzmethoden

  • set_initial_session_scope

Action-Filter

  • after_filter :set_initial_session_scope, :only => [:login]