approval email notifications implemented

This commit is contained in:
Karel Picman 2013-06-26 14:30:34 +02:00
parent a4a200510a
commit 91221f26d5
11 changed files with 221 additions and 61 deletions

View File

@ -40,13 +40,72 @@ class DmsfWorkflowsController < ApplicationController
if params[:commit] == l(:button_submit)
action = DmsfWorkflowStepAction.new(
:dmsf_workflow_step_assignment_id => params[:dmsf_workflow_step_assignment_id],
:action => params[:step_action],
:action => (params[:step_action].to_i >= 10) ? DmsfWorkflowStepAction::ACTION_DELEGATE : params[:step_action],
:note => params[:note])
if request.post?
if action.save
if @workflow.try_finish params[:dmsf_file_revision_id], action, params[:user_id]
file = DmsfFile.joins(:revisions).where(:dmsf_file_revisions => {:id => params[:dmsf_file_revision_id]}).first
file.unlock! if file
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id]
if revision
if @workflow.try_finish revision, action, (params[:step_action].to_i / 10)
file = DmsfFile.joins(:revisions).where(:dmsf_file_revisions => {:id => revision.id}).first
file.unlock! if file
if revision.workflow == DmsfWorkflow::STATE_APPROVED
# Just approved
DmsfMailer.workflow_notification(
revision.project.members.collect{ |member| member.user.mail},
@workflow,
revision,
"Approval workflow #{@workflow.name} approved",
'been finished and the document has been approved',
'To see the approval history click on the workflow status of the document in').deliver
else
# Just rejected
owner = User.find_by_id revision.dmsf_workflow_assigned_by
DmsfMailer.workflow_notification(
@workflow.participiants.collect{ |user| user.mail} << owner.mail,
@workflow,
revision,
"Approval workflow #{@workflow.name} rejected",
"been finished and the document has been rejected because of '#{action.note}'",
'To see the approval history click on the workflow status of the document in').deliver
end
else
if action.action == DmsfWorkflowStepAction::ACTION_DELEGATE
# Delegation
# TODO: Find the real delegate
delegate = User.current
DmsfMailer.workflow_notification(
delegate.mail,
@workflow,
revision,
"Approval workflow #{@workflow.name} step delegated",
"been delegated because of '#{action.note}' and you are expected to do an approval in the current approval step",
'To proceed click on the check box icon next to the document in').deliver
else
# Next step
assignments = @workflow.next_assignments revision.id
unless assignments.empty?
if assignments.first.dmsf_workflow_step.step != action.dmsf_workflow_step_assignment.dmsf_workflow_step.step
# Next step
DmsfMailer.workflow_notification(
assignments.collect{ |assignment| assignment.user.mail},
@workflow,
revision,
"Approval workflow #{@workflow.name} requires your approval",
'finished one of the approval steps and you are expected to do an approval in the next approval step',
'To proceed click on the check box icon next to the document in the').deliver
owner = User.find_by_id revision.dmsf_workflow_assigned_by
DmsfMailer.workflow_notification(
owner.mail,
@workflow,
revision,
"Approval workflow #{@workflow.name} updated",
'finished one of the approval steps',
'To see the current status of the approval workflow click on the workflow status the document in').deliver
end
end
end
end
end
flash[:notice] = l(:notice_successful_update)
else
@ -190,11 +249,19 @@ class DmsfWorkflowsController < ApplicationController
def start
revision = DmsfFileRevision.find_by_id(params[:dmsf_file_revision_id])
if revision
revision.set_workflow(@workflow.id, params[:action])
if request.post?
if revision.save
flash[:notice] = l(:notice_successful_update)
if revision
if request.post?
revision.set_workflow(@workflow.id, params[:action])
if revision.save
assignments = @workflow.next_assignments revision.id
DmsfMailer.workflow_notification(
assignments.collect{ |assignment| assignment.user.mail},
@workflow,
revision,
"Approval workflow #{@workflow.name} started",
'been started and you are expected to do an approval in the current approval step',
'To proceed click on the check box icon next to the document in').deliver
flash[:notice] = l(:notice_workflow_started)
else
flash[:error] = l(:notice_cannot_start_workflow)
end
@ -202,9 +269,8 @@ class DmsfWorkflowsController < ApplicationController
end
redirect_to :back
end
private
private
def find_workflow
@workflow = DmsfWorkflow.find_by_id(params[:id])
end

View File

@ -49,7 +49,7 @@ module DmsfWorkflowsHelper
def dmsf_workflows_for_select(project, dmsf_workflow_id)
options = Array.new
options << [l(:option_workflow_none), nil]
#options << [l(:option_workflow_none), nil]
DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', project.id]).each do |wf|
options << [wf.name, wf.id]
end
@ -59,7 +59,7 @@ module DmsfWorkflowsHelper
def principals_radio_button_tags(name, principals)
s = ''
principals.each do |principal|
s << "<label>#{ radio_button_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
s << "<label>#{ radio_button_tag name, principal.id * 10, false, :id => nil } #{h principal}</label>\n"
end
s.html_safe
end

View File

@ -57,6 +57,20 @@ class DmsfMailer < Mailer
mail(:to => email_to, :cc => email_cc, :subject => email_subject, :from => user.mail)
end
def workflow_notification(to, workflow, revision, subject, text1, text2)
set_language_if_valid User.current.language
@workflow = workflow
@revision = revision
@text1 = "The approval workflow '#{@workflow.name}' assigned to '#{@revision.file.name}' document has just #{text1}."
unless @revision.folder
url = url_for(:controller => 'dmsf', :action => 'edit_root', :id => @revision.project, :only_path => false)
else
url = url_for(:controller => 'dmsf', :action => 'edit', :id => @project, :folder_id => @revision.folder, :only_path => false)
end
@text2 = "#{text2} #{url}."
mail :to => to, :subject => subject
end
private
def get_notify_user_emails(user, files)
@ -93,5 +107,5 @@ class DmsfMailer < Mailer
notify_members.collect {|m| m.user.mail }
end
end

View File

@ -28,6 +28,14 @@ class DmsfWorkflow < ActiveRecord::Base
STATE_WAITING_FOR_APPROVAL = 1
STATE_APPROVED = 2
STATE_REJECTED = 4
def participiants
users = Array.new
self.dmsf_workflow_steps.each do |step|
users << step.user
end
users
end
def self.workflows(project)
project ? where(:project_id => project) : where('project_id IS NULL')
@ -110,7 +118,7 @@ class DmsfWorkflow < ActiveRecord::Base
def next_assignments(dmsf_file_revision_id)
results = Array.new
self.dmsf_workflow_steps.each do |step|
break unless results.empty? || results[0].step.step == step.step
break unless results.empty? || results[0].dmsf_workflow_step.step == step.step
step.dmsf_workflow_step_assignments.each do |assignment|
if assignment.dmsf_file_revision_id == dmsf_file_revision_id
if assignment.dmsf_workflow_step_actions.empty?
@ -134,14 +142,11 @@ class DmsfWorkflow < ActiveRecord::Base
def self.assignments_to_users_str(assignments)
str = ''
if assignments
assignments.each_with_index do |assignment, index|
user = User.find_by_id assignment.user_id
if user
if index > 0
str << ', '
end
str << user.name
assignments.each_with_index do |assignment, index|
if index > 0
str << ', '
end
str << assignment.user.name
end
end
str
@ -153,33 +158,38 @@ class DmsfWorkflow < ActiveRecord::Base
end
end
def try_finish(dmsf_file_revision_id, action, user_id)
revision = DmsfFileRevision.find_by_id dmsf_file_revision_id
if revision
case action.action
when DmsfWorkflowStepAction::ACTION_APPROVE
self.dmsf_workflow_steps.each do |step|
step.dmsf_workflow_step_assignments.each do |assignment|
if assignment.dmsf_file_revision_id == dmsf_file_revision_id.to_i
if assignment.dmsf_workflow_step_actions.empty?
return false
end
assignment.dmsf_workflow_step_actions.each do |act|
return false unless act.is_finished?
end
end
end
end
revision.update_attribute(:workflow, DmsfWorkflow::STATE_APPROVED)
return true
when DmsfWorkflowStepAction::ACTION_REJECT
revision.update_attribute(:workflow, DmsfWorkflow::STATE_REJECTED)
return true
when DmsfWorkflowStepAction::ACTION_DELEGATE
assignment = DmsfWorkflowStepAssignment.find_by_id(action.dmsf_workflow_step_assignment_id)
assignment.update_attribute(:user_id, user_id) if assignment
end
def try_finish(revision, action, user_id)
case action.action
when DmsfWorkflowStepAction::ACTION_APPROVE
self.dmsf_workflow_steps.each do |step|
step.dmsf_workflow_step_assignments.each do |assignment|
if assignment.dmsf_file_revision_id == revision.id
if assignment.dmsf_workflow_step_actions.empty?
return false
end
assignment.dmsf_workflow_step_actions.each do |act|
return false unless act.is_finished?
end
end
end
end
revision.update_attribute(:workflow, DmsfWorkflow::STATE_APPROVED)
return true
when DmsfWorkflowStepAction::ACTION_REJECT
revision.update_attribute(:workflow, DmsfWorkflow::STATE_REJECTED)
return true
when DmsfWorkflowStepAction::ACTION_DELEGATE
#assignment = DmsfWorkflowStepAssignment.find_by_id(action.dmsf_workflow_step_assignment_id)
#assignment.update_attribute(:user_id, user_id) if assignment
self.dmsf_workflow_steps.each do |step|
step.dmsf_workflow_step_assignments.each do |assignment|
if assignment.id == action.dmsf_workflow_step_assignment_id
assignment.update_attribute(:user_id, user_id)
return false
end
end
end
end
return false
end
end
end

View File

@ -18,14 +18,9 @@
class DmsfWorkflowStepAssignment < ActiveRecord::Base
belongs_to :dmsf_workflow_step
belongs_to :user
has_many :dmsf_workflow_step_actions, :dependent => :destroy
validates :dmsf_workflow_step_id, :presence => true
validates :dmsf_file_revision_id, :presence => true
validates_uniqueness_of :dmsf_workflow_step_id, :scope => [:dmsf_file_revision_id]
def step
DmsfWorkflowStep.find_by_id self.dmsf_workflow_step_id
end
end

View File

@ -0,0 +1,15 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
</head>
<body>
<p>Dear user,</p>
<p>
<%= @text1 %>
</p>
<p>
<%= @text2 %>
</p>
</body>
</html>

View File

@ -0,0 +1,4 @@
Dear user,
<%= @text1 %>
<%= @text2 %>

View File

@ -241,4 +241,5 @@ en:
dmsf_new_step: New step
message_dmsf_wokflow_note: Your note...
info_revision: "r%{rev}"
link_workflow: Workflow
link_workflow: Workflow
notice_workflow_started: 'Approval workflow successfully started'

View File

@ -0,0 +1,54 @@
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2013 Karel Picman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
desc <<-END_DESC
Alert all users who are expected to do an approval in the current approval steps
Available options:
Example:
rake redmine:dmsf_alert_approvals RAILS_ENV="production"
END_DESC
require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
class DmsfAlertApprovals
def self.alert
revisions = DmsfFileRevision.where(:workflow => 1)
revisions.each do |revision|
next unless revision.file.last_revision == revision
workflow = DmsfWorkflow.find_by_id revision.dmsf_workflow_id
next unless workflow
assignments = workflow.next_assignments revision.id
DmsfMailer.workflow_notification(
assignments.collect{|a| a.user.mail},
workflow,
revision,
"Approval workflow #{workflow.name} requires your approval",
'finished one of the approval steps and you are expected to do an approval in the next approval step',
'To proceed click on the check box icon next to the document in the').deliver
Rails.logger.info "#{assignments.collect{|a| a.user.login}.join(',')} were alerted in order to do an approval of [workflow = #{workflow.id}, revision = #{revision.id}]"
end
end
end
namespace :redmine do
task :dmsf_alert_approvals => :environment do
DmsfAlertApprovals.alert
end
end

View File

@ -58,8 +58,4 @@ class WorkflowStepAssignmentTest < RedmineDmsf::Test::UnitTest
assert_nil DmsfWorkflowStepAssignment.find_by_id(1)
assert_nil DmsfWorkflowStepAction.find_by_id(1)
end
def test_step
assert_equal @wfsa1.step, DmsfWorkflowStep.find_by_id(@wfsa1.dmsf_workflow_step_id)
end
end

View File

@ -175,4 +175,9 @@ class DmsfWorkflowTest < RedmineDmsf::Test::UnitTest
# assert_equal @revision2.workflow, DmsfWorkflow::STATE_WAITING_FOR_APPROVAL
assert true
end
def test_participiants
# TODO:
assert true
end
end