1<?php
2
3namespace Kanboard\Console;
4
5use Kanboard\Model\ProjectModel;
6use Kanboard\Model\TaskModel;
7use Kanboard\Core\Security\Role;
8use Symfony\Component\Console\Helper\Table;
9use Symfony\Component\Console\Input\InputInterface;
10use Symfony\Component\Console\Input\InputOption;
11use Symfony\Component\Console\Output\OutputInterface;
12
13class TaskOverdueNotificationCommand extends BaseCommand
14{
15    protected function configure()
16    {
17        $this
18            ->setName('notification:overdue-tasks')
19            ->setDescription('Send notifications for overdue tasks')
20            ->addOption('show', null, InputOption::VALUE_NONE, 'Show sent overdue tasks')
21            ->addOption('group', null, InputOption::VALUE_NONE, 'Group all overdue tasks for one user (from all projects) in one email')
22            ->addOption('manager', null, InputOption::VALUE_NONE, 'Send all overdue tasks to project manager(s) in one email')
23            ->addOption('project', 'p', InputOption::VALUE_REQUIRED, 'Send notifications only the given project')
24        ;
25    }
26
27    protected function execute(InputInterface $input, OutputInterface $output)
28    {
29        if ($input->getOption('project')) {
30            $tasks = $this->taskFinderModel->getOverdueTasksQuery()
31                ->beginOr()
32                ->eq(TaskModel::TABLE.'.project_id', $input->getOption('project'))
33                ->eq(ProjectModel::TABLE.'.identifier', $input->getOption('project'))
34                ->closeOr()
35                ->findAll();
36        } else {
37            $tasks = $this->taskFinderModel->getOverdueTasks();
38        }
39
40        if ($input->getOption('group')) {
41            $tasks = $this->sendGroupOverdueTaskNotifications($tasks);
42        } elseif ($input->getOption('manager')) {
43            $tasks = $this->sendOverdueTaskNotificationsToManagers($tasks);
44        } else {
45            $tasks = $this->sendOverdueTaskNotifications($tasks);
46        }
47
48        if ($input->getOption('show')) {
49            $this->showTable($output, $tasks);
50        }
51    }
52
53    public function showTable(OutputInterface $output, array $tasks)
54    {
55        $rows = array();
56
57        foreach ($tasks as $task) {
58            $rows[] = array(
59                $task['id'],
60                $task['title'],
61                date('Y-m-d H:i', $task['date_due']),
62                $task['project_id'],
63                $task['project_name'],
64                $task['assignee_name'] ?: $task['assignee_username'],
65            );
66        }
67
68        $table = new Table($output);
69        $table
70            ->setHeaders(array('Id', 'Title', 'Due date', 'Project Id', 'Project name', 'Assignee'))
71            ->setRows($rows)
72            ->render();
73    }
74
75    /**
76     * Send all overdue tasks for one user in one email
77     *
78     * @access public
79     * @param  array $tasks
80     * @return array
81     */
82    public function sendGroupOverdueTaskNotifications(array $tasks)
83    {
84        foreach ($this->groupByColumn($tasks, 'owner_id') as $user_tasks) {
85            $users = $this->userNotificationModel->getUsersWithNotificationEnabled($user_tasks[0]['project_id']);
86
87            foreach ($users as $user) {
88                $this->sendUserOverdueTaskNotifications($user, $user_tasks);
89            }
90        }
91
92        return $tasks;
93    }
94
95    /**
96     * Send all overdue tasks in one email to project manager(s)
97     *
98     * @access public
99     * @param  array $tasks
100     * @return array
101     */
102    public function sendOverdueTaskNotificationsToManagers(array $tasks)
103    {
104        foreach ($this->groupByColumn($tasks, 'project_id') as $project_id => $project_tasks) {
105            $users = $this->userNotificationModel->getUsersWithNotificationEnabled($project_id);
106            $managers = array();
107
108            foreach ($users as $user) {
109                $role = $this->projectUserRoleModel->getUserRole($project_id, $user['id']);
110                if ($role == Role::PROJECT_MANAGER) {
111                    $managers[] = $user;
112                }
113            }
114
115            foreach ($managers as $manager) {
116                $this->sendUserOverdueTaskNotificationsToManagers($manager, $project_tasks);
117            }
118        }
119
120        return $tasks;
121    }
122
123    /**
124     * Send overdue tasks
125     *
126     * @access public
127     * @param  array $tasks
128     * @return array
129     */
130    public function sendOverdueTaskNotifications(array $tasks)
131    {
132        foreach ($this->groupByColumn($tasks, 'project_id') as $project_id => $project_tasks) {
133            $users = $this->userNotificationModel->getUsersWithNotificationEnabled($project_id);
134
135            foreach ($users as $user) {
136                $this->sendUserOverdueTaskNotifications($user, $project_tasks);
137            }
138        }
139
140        return $tasks;
141    }
142
143    /**
144     * Send overdue tasks for a given user
145     *
146     * @access public
147     * @param  array   $user
148     * @param  array   $tasks
149     */
150    public function sendUserOverdueTaskNotifications(array $user, array $tasks)
151    {
152        $user_tasks = array();
153        $project_names = array();
154
155        foreach ($tasks as $task) {
156            if ($this->userNotificationFilterModel->shouldReceiveNotification($user, array('task' => $task))) {
157                $user_tasks[] = $task;
158                $project_names[$task['project_id']] = $task['project_name'];
159            }
160        }
161
162        if (! empty($user_tasks)) {
163            $this->userNotificationModel->sendUserNotification(
164                $user,
165                TaskModel::EVENT_OVERDUE,
166                array('tasks' => $user_tasks, 'project_name' => implode(', ', $project_names))
167            );
168        }
169    }
170
171    /**
172     * Send overdue tasks for a project manager(s)
173     *
174     * @access public
175     * @param  array   $manager
176     * @param  array   $tasks
177     */
178    public function sendUserOverdueTaskNotificationsToManagers(array $manager, array $tasks)
179    {
180        $this->userNotificationModel->sendUserNotification(
181            $manager,
182            TaskModel::EVENT_OVERDUE,
183            array('tasks' => $tasks, 'project_name' => $tasks[0]['project_name'])
184        );
185    }
186
187    /**
188     * Group a collection of records by a column
189     *
190     * @access public
191     * @param  array   $collection
192     * @param  string  $column
193     * @return array
194     */
195    public function groupByColumn(array $collection, $column)
196    {
197        $result = array();
198
199        foreach ($collection as $item) {
200            $result[$item[$column]][] = $item;
201        }
202
203        return $result;
204    }
205}
206