Newer
Older
dmpopidor / app / models / project.rb
class Project < ActiveRecord::Base
  include GlobalHelpers

	extend FriendlyId

	attr_accessible :dmptemplate_id, :title, :organisation_id, :unit_id, :guidance_group_ids, 
                  :project_group_ids, :funder_id, :institution_id, :grant_number, :identifier, 
                  :description, :principal_investigator, :principal_investigator_identifier, 
                  :data_contact, :funder_name, :as => [:default, :admin]

	#associations between tables
	belongs_to :dmptemplate
	belongs_to :organisation
	has_many :plans
	has_many :project_groups, :dependent => :destroy
	has_and_belongs_to_many :guidance_groups, join_table: "project_guidance"

	friendly_id :title, use: [:slugged, :history, :finders]

  ##
  # returns the title of the project
  #
  # @return [String] the project's title
	def to_s
		"#{title}"
	end

	after_create :create_plans

  ##
  # sets a new funder for the project
  # defaults to the first dmptemplate if the current template is nill and the funder has more than one dmptemplate
  #
  # @param new_funder_id [Integer] the id for a new funder
  # @return [Organisation] the new funder
	def funder_id=(new_funder_id)
		if new_funder_id != "" then
			new_funder = Organisation.find(new_funder_id);
			if new_funder.dmptemplates.count >= 1 && self.dmptemplate.nil? then
				self.dmptemplate = new_funder.dmptemplates.first
      end
		end
	end

  ##
  # returns the funder id for the project
  #
  # @return [Integer, nil] the id for the funder
	def funder_id
		if self.dmptemplate.nil? then
			return nil
		end
		template_org = self.dmptemplate.organisation
		if template_org.organisation_type.name == constant("organisation_types.funder").downcase
			return template_org.id
		else
			return nil
		end
	end

  ##
  # returns the funder organisation for the project or nil if none is specified
  #
  # @return [Organisation, nil] the funder for project, or nil if none exists
	def funder
		if self.dmptemplate.nil? then
			return nil
		end
		template_org = self.dmptemplate.organisation
		if template_org.organisation_type.name == constant("organisation_types.funder").downcase
			return template_org
		else
			return nil
		end
	end

  ##
  # returns the name of the funder for the project
  #
  # @return [String] the name fo the funder for the project
	def funder_name
		if self.funder.nil?
			return read_attribute(:funder_name)
		else
			return self.funder.name
		end
	end

  ##
  # defines a new funder_name for the project.
  #
  # @param new_funder_name [String] the string name of the new funder
  # @return [Integer, nil] the org_id of the new funder
	def funder_name=(new_funder_name)
		write_attribute(:funder_name, new_funder_name)
		org_table = Organisation.arel_table
		existing_org = Organisation.where(org_table[:name].matches(new_funder_name))
		if existing_org.nil?
			existing_org = Organisation.where(org_table[:abbreviation].matches(new_funder_name))
		end
		unless existing_org.empty?
			self.funder_id=existing_org.id
		end
	end

  ##
  # sets a new institution_id if there is no current organisation
  #
  # @params new_institution_id [Integer] the id for the new institution
  # @return [Integer, Bool] false if an organisation exists, or the id of the set org if a new organisation is set
	def institution_id=(new_institution_id)
		if organisation.nil? then
			self.organisation_id = new_institution_id
		end
	end

  ##
  # returns the organisation which is root over the owning organisation
  #
  # @return [Integer, nil] the organisation_id or nil
	def institution_id
		if organisation.nil?
			return nil
		else
			return organisation.root.id
		end
	end

  ##
  # defines a new organisation_id for the project
  # but is confusingly labled unit_id
  #
  # @params new_unit_id [Integer]
  # @return [Integer, Boolean] the new organisation ID or false if no unit_id was passed
	def unit_id=(new_unit_id)
		unless new_unit_id.nil? ||new_unit_id == ""
			self.organisation_id = new_unit_id
		end
	end

  ##
  # returns the organisation_id or nil
  # again seems redundant
  #
  # @return [nil, Integer] nil if no organisation, or the id if there is an organisation specified
	def unit_id
		if organisation.nil? || organisation.parent_id.nil?
			return nil
		else
			return organisation_id
		end
	end

  ##
  # assigns the passed user_id to the creater_role for the project
  # gives the user rights to read, edit, administrate, and defines them as creator
  #
  # @param user_id [Integer] the user to be given priveleges' id
	def assign_creator(user_id)
		add_user(user_id, true, true, true)
	end

  ##
  # assigns the passed user_id as an editor for the project
  # gives the user rights to read and edit
  #
  # @param user_id [Integer] the user to be given priveleges' id
	def assign_editor(user_id)
		add_user(user_id, true)
	end

  ##
  # assigns the passed user_id as a reader for the project
  # gives the user rights to read
  #
  # @param user_id [Integer] the user to be given priveleges' id
	def assign_reader(user_id)
		add_user(user_id)
	end

  ##
  # assigns the passed user_id as an administrator for the project
  # gives the user rights to read, adit, and administrate the project
  #
  # @param user_id [Integer] the user to be given priveleges' id
	def assign_administrator(user_id)
		add_user(user_id, true, true)
	end

  ##
  # whether or not the current plan is administrable by the user
  #
  # @param user_id [Integer] the user to check if has privleges
  # @return [Boolean] true if user can administer project, false otherwise
	def administerable_by(user_id)
		user = project_groups.find_by_user_id(user_id)
		if (! user.nil?) && user.project_administrator then
			return true
		else
			return false
		end
	end

  ##
  # whether or not the current plan is editable by the user
  #
  # @param user_id [Integer] the user to check if has privleges
  # @return [Boolean] true if user can edit project, false otherwise
	def editable_by(user_id)
		user = project_groups.find_by_user_id(user_id)
		if (! user.nil?) && user.project_editor then
			return true
		else
			return false
		end
	end

  ##
  # whether or not the current plan is readable by the user
  # should be renamed to readable_by?
  #
  # @param user_id [Integer] the user to check if has privleges
  # @return [Boolean] true if user can read project, false otherwise
	def readable_by(user_id)
		user = project_groups.find_by_user_id(user_id)
		if (! user.nil?) then
			return true
		else
			return false
		end
	end

  ##
  # returns the projects which the user can atleast read
  #
  # @param user_id [Integer] the user to lookup projects for
  # @return [Array<Project>] list of all projects the user can atleast read
	def self.projects_for_user(user_id)
		projects = Array.new
		groups = ProjectGroup.where("user_id = ?", user_id)
		unless groups.nil? then
			groups.each do |group|
				unless group.project.nil? then
					projects << group.project
				end
			end
		end
		return projects
	end

  ##
  # whether or not the specified user_id created this project
  # should be renamed to created_by?
  #
  # @params user_id [Integer] the user to check the priveleges of
  # @return [Boolean] true if the user created the project
	def created_by(user_id)
		user = project_groups.find_by_user_id(user_id)
		if (! user.nil?) && user.project_creator then
			return true
		else
			return false
		end
	end

  ##
  # the datetime for the latest update of this project, or any plan it owns
  #
  # @return [DateTime] the time of latest update
	def latest_update
		latest_update = updated_at
		plans.each do |plan|
			if plan.latest_update > latest_update then
				latest_update = plan.latest_update
			end
		end
		return latest_update
	end

	# Getters to match 'My plans' columns

  ##
  # the title of the project
  #
  # @return [String] the title of the project
	def name
		self.title
	end

  ##
  # the owner of the project
  #
  # @return [User] the creater of the project
	def owner
		self.project_groups.find_by_project_creator(true).try(:user)
	end

  ##
  # the time the project was last updated, formatted as a date
  #
  # @return [Date] last update as a date
	def last_edited
		self.latest_update.to_date
	end

  ##
  # whether or not the plan is shared with anybody
  #
  # @return [Boolean] true if the project has been shared
	def shared?
		self.project_groups.count > 1
	end

	alias_method :shared, :shared?

  ##
  # the organisation who owns the project
  #
  # @return [Dmptemplate,Organisation,String] the template, it's owner, or it's owner's abreviation
	def template_owner
		self.dmptemplate.try(:organisation).try(:abbreviation)
	end

	private

  ##
  # adds a user to the project
  # if no flags are specified, the user is given read privleges
  #
  # @param user_id [Integer] the user to be given privleges
  # @param is_editor [Boolean] whether or not the user can edit the project
  # @param is_administrator [Boolean] whether or not the user can administrate the project
  # @param is_creator [Boolean] wheter or not the user created the project
  # @return [Array<ProjectGroup>]
	def add_user(user_id, is_editor = false, is_administrator = false, is_creator = false)
		group = ProjectGroup.new
		group.user_id = user_id
		group.project_creator = is_creator
		group.project_editor = is_editor
		group.project_administrator = is_administrator
		project_groups << group
	end

  ##
  # creates a plan for each phase in the dmptemplate associated with this project
  # unless the phase is unpublished, it creates a new plan, and a new version of the plan and adds them to the project's plans
  #
  # @return [Array<Plan>]
	def create_plans
		dmptemplate.phases.each do |phase|
			latest_published_version = phase.latest_published_version
			unless latest_published_version.nil?
				new_plan = Plan.new
				new_plan.version = latest_published_version
				plans << new_plan
			end
		end
	end
end