1de02284cSSzymon Olewniczak<?php 2de02284cSSzymon Olewniczak 3de02284cSSzymon Olewniczaknamespace dokuwiki\plugin\bez\mdl; 4de02284cSSzymon Olewniczak 57fbf4c39SSzymon Olewniczakuse Assetic\Exception\Exception; 67fbf4c39SSzymon Olewniczak 7de02284cSSzymon Olewniczakclass ThreadFactory extends Factory { 8de02284cSSzymon Olewniczak 953df74e7SSzymon Olewniczak public function get_table_view() { 1053df74e7SSzymon Olewniczak return 'thread_view'; 11de02284cSSzymon Olewniczak } 12de02284cSSzymon Olewniczak 13de02284cSSzymon Olewniczak public function get_years_scope() { 14de02284cSSzymon Olewniczak $r = $this->model->sqlite->query('SELECT create_date FROM thread ORDER BY id LIMIT 1'); 15de02284cSSzymon Olewniczak $date = $this->model->sqlite->res2single($r); 16de02284cSSzymon Olewniczak 17de02284cSSzymon Olewniczak //get only year 18de02284cSSzymon Olewniczak $first = (int) substr($date, 0, strpos($date, '-')); 19de02284cSSzymon Olewniczak $last = (int) date('Y'); 20de02284cSSzymon Olewniczak 21de02284cSSzymon Olewniczak $years = array(); 22de02284cSSzymon Olewniczak for ($year = $first; $year <= $last; $year++) { 23de02284cSSzymon Olewniczak $years[] = (string) $year; 24de02284cSSzymon Olewniczak } 25de02284cSSzymon Olewniczak return $years; 26de02284cSSzymon Olewniczak } 277fbf4c39SSzymon Olewniczak 28*bc2653b0SSzymon Olewniczak public function users_involvement(\DatePeriod $period=NULL) { 29*bc2653b0SSzymon Olewniczak if ($period) { 30*bc2653b0SSzymon Olewniczak $from = $period->getStartDate()->format(\DateTime::ISO8601); 31*bc2653b0SSzymon Olewniczak $to = $period->getEndDate()->format(\DateTime::ISO8601); 32*bc2653b0SSzymon Olewniczak 33eb2e6be9SSzymon Olewniczak $sql = "SELECT thread_participant.user_id, 34eb2e6be9SSzymon Olewniczak SUM(thread_participant.original_poster) AS original_poster_sum, 35eb2e6be9SSzymon Olewniczak SUM(thread_participant.coordinator) AS coordinator_sum, 36eb2e6be9SSzymon Olewniczak SUM(thread_participant.commentator) AS commentator_sum, 37eb2e6be9SSzymon Olewniczak SUM(thread_participant.task_assignee) AS task_assignee_sum 38eb2e6be9SSzymon Olewniczak FROM thread_participant JOIN thread ON thread_participant.thread_id = thread.id 39eb2e6be9SSzymon Olewniczak WHERE thread.create_date BETWEEN ? AND ? 40eb2e6be9SSzymon Olewniczak GROUP BY user_id 41eb2e6be9SSzymon Olewniczak ORDER BY user_id"; 42eb2e6be9SSzymon Olewniczak $r = $this->model->sqlite->query($sql, $from, $to); 43eb2e6be9SSzymon Olewniczak } else { 44eb2e6be9SSzymon Olewniczak $sql = "SELECT user_id, 45eb2e6be9SSzymon Olewniczak SUM(original_poster) AS original_poster_sum, 46eb2e6be9SSzymon Olewniczak SUM(coordinator) AS coordinator_sum, 47eb2e6be9SSzymon Olewniczak SUM(commentator) AS commentator_sum, 48eb2e6be9SSzymon Olewniczak SUM(task_assignee) AS task_assignee_sum 49ff14b107SSzymon Olewniczak FROM thread_participant 50ff14b107SSzymon Olewniczak GROUP BY user_id 51eb2e6be9SSzymon Olewniczak ORDER BY user_id"; 52ff14b107SSzymon Olewniczak 53ff14b107SSzymon Olewniczak $r = $this->model->sqlite->query($sql); 54eb2e6be9SSzymon Olewniczak } 55ff14b107SSzymon Olewniczak return $r; 56ff14b107SSzymon Olewniczak } 57ff14b107SSzymon Olewniczak 58*bc2653b0SSzymon Olewniczak public function kpi(\DatePeriod $period=NULL) { 59*bc2653b0SSzymon Olewniczak if ($period) { 60*bc2653b0SSzymon Olewniczak $from = $period->getStartDate()->format(\DateTime::ISO8601); 61*bc2653b0SSzymon Olewniczak $to = $period->getEndDate()->format(\DateTime::ISO8601); 62*bc2653b0SSzymon Olewniczak 636fa92f54SSzymon Olewniczak $sql = "SELECT COUNT(*)*1.0/COUNT(DISTINCT thread_id) AS kpi 646fa92f54SSzymon Olewniczak FROM thread_participant JOIN thread ON thread_participant.thread_id = thread.id 65a5de966aSSzymon Olewniczak WHERE thread.create_date BETWEEN ? AND ?"; 666fa92f54SSzymon Olewniczak $r = $this->model->sqlite->query($sql, $from, $to); 676fa92f54SSzymon Olewniczak } else { 686fa92f54SSzymon Olewniczak $sql = "SELECT COUNT(*)*1.0/COUNT(DISTINCT thread_id) AS kpi 696fa92f54SSzymon Olewniczak FROM thread_participant"; 706fa92f54SSzymon Olewniczak 716fa92f54SSzymon Olewniczak $r = $this->model->sqlite->query($sql); 726fa92f54SSzymon Olewniczak } 736fa92f54SSzymon Olewniczak 746fa92f54SSzymon Olewniczak return $r->fetchColumn(); 756fa92f54SSzymon Olewniczak } 766fa92f54SSzymon Olewniczak 77*bc2653b0SSzymon Olewniczak public function bez_activity(\DatePeriod $period=NULL) { 78*bc2653b0SSzymon Olewniczak if ($period) { 79*bc2653b0SSzymon Olewniczak $from = $period->getStartDate()->format(\DateTime::ISO8601); 80*bc2653b0SSzymon Olewniczak $to = $period->getEndDate()->format(\DateTime::ISO8601); 81*bc2653b0SSzymon Olewniczak 82a5de966aSSzymon Olewniczak $sql = "SELECT COUNT(DISTINCT user_id) 83a5de966aSSzymon Olewniczak FROM (SELECT user_id 84a5de966aSSzymon Olewniczak FROM thread_participant JOIN thread ON thread_participant.thread_id = thread.id 85a5de966aSSzymon Olewniczak WHERE create_date BETWEEN ? AND ? 86a5de966aSSzymon Olewniczak UNION 87a5de966aSSzymon Olewniczak SELECT user_id 88a5de966aSSzymon Olewniczak FROM task_participant JOIN task ON task_participant.task_id = task.id 89a5de966aSSzymon Olewniczak WHERE create_date BETWEEN ? AND ?)"; 90a5de966aSSzymon Olewniczak $r = $this->model->sqlite->query($sql, $from, $to, $from, $to); 91a5de966aSSzymon Olewniczak } else { 92a5de966aSSzymon Olewniczak $sql = "SELECT COUNT(DISTINCT user_id) 93a5de966aSSzymon Olewniczak FROM (SELECT user_id FROM thread_participant 94a5de966aSSzymon Olewniczak UNION 95a5de966aSSzymon Olewniczak SELECT user_id FROM task_participant)"; 96a5de966aSSzymon Olewniczak 97a5de966aSSzymon Olewniczak $r = $this->model->sqlite->query($sql); 98a5de966aSSzymon Olewniczak } 99a5de966aSSzymon Olewniczak $active_users = $r->fetchColumn(); 100a5de966aSSzymon Olewniczak $wiki_users = count($this->model->userFactory->get_all()); 101a5de966aSSzymon Olewniczak 102a5de966aSSzymon Olewniczak return $active_users/$wiki_users * 100; 103a5de966aSSzymon Olewniczak } 104a5de966aSSzymon Olewniczak 105*bc2653b0SSzymon Olewniczak 106*bc2653b0SSzymon Olewniczak public function report_issue(\DatePeriod $period=NULL) { 107*bc2653b0SSzymon Olewniczak if ($period) { 108*bc2653b0SSzymon Olewniczak $from = $period->getStartDate()->format(\DateTime::ISO8601); 109*bc2653b0SSzymon Olewniczak $to = $period->getEndDate()->format(\DateTime::ISO8601); 110*bc2653b0SSzymon Olewniczak 111*bc2653b0SSzymon Olewniczak $sql = "SELECT label_name, 112*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'proposal' THEN 1 END) AS proposal, 113*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'opened' THEN 1 END) AS opened, 114*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'done' THEN 1 END) AS done, 115*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'closed' THEN 1 END) AS closed, 116*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'rejected' THEN 1 END) AS rejected, 117*bc2653b0SSzymon Olewniczak COUNT(*) AS count_all, 118*bc2653b0SSzymon Olewniczak SUM(task_sum_cost) AS sum_all, 119*bc2653b0SSzymon Olewniczak SUM(CASE WHEN state = 'closed' THEN task_sum_cost END) AS sum_closed, 120*bc2653b0SSzymon Olewniczak (CASE WHEN state = 'closed' THEN 121*bc2653b0SSzymon Olewniczak AVG(julianday(close_date) - julianday(create_date)) 122*bc2653b0SSzymon Olewniczak END) AS avg_closed 123*bc2653b0SSzymon Olewniczak FROM thread_view 124*bc2653b0SSzymon Olewniczak WHERE type = 'issue' AND create_date BETWEEN ? AND ? 125*bc2653b0SSzymon Olewniczak GROUP BY label_name 126*bc2653b0SSzymon Olewniczak ORDER BY label_name"; 127*bc2653b0SSzymon Olewniczak 128*bc2653b0SSzymon Olewniczak $r = $this->model->sqlite->query($sql, $from, $to); 129*bc2653b0SSzymon Olewniczak } else { 130*bc2653b0SSzymon Olewniczak $sql = "SELECT label_name, 131*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'proposal' THEN 1 END) AS proposal, 132*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'opened' THEN 1 END) AS opened, 133*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'done' THEN 1 END) AS done, 134*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'closed' THEN 1 END) AS closed, 135*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'rejected' THEN 1 END) AS rejected, 136*bc2653b0SSzymon Olewniczak COUNT(*) AS count_all, 137*bc2653b0SSzymon Olewniczak SUM(task_sum_cost) AS sum_all, 138*bc2653b0SSzymon Olewniczak SUM(CASE WHEN state = 'closed' THEN task_sum_cost END) AS sum_closed, 139*bc2653b0SSzymon Olewniczak (CASE WHEN state = 'closed' THEN 140*bc2653b0SSzymon Olewniczak AVG(julianday(close_date) - julianday(create_date)) 141*bc2653b0SSzymon Olewniczak END) AS avg_closed 142*bc2653b0SSzymon Olewniczak FROM thread_view 143*bc2653b0SSzymon Olewniczak WHERE type = 'issue' 144*bc2653b0SSzymon Olewniczak GROUP BY label_name 145*bc2653b0SSzymon Olewniczak ORDER BY label_name"; 146*bc2653b0SSzymon Olewniczak 147*bc2653b0SSzymon Olewniczak $r = $this->model->sqlite->query($sql); 148*bc2653b0SSzymon Olewniczak } 149*bc2653b0SSzymon Olewniczak return $r; 150*bc2653b0SSzymon Olewniczak } 151*bc2653b0SSzymon Olewniczak 152*bc2653b0SSzymon Olewniczak public function report_project(\DatePeriod $period=NULL) { 153*bc2653b0SSzymon Olewniczak if ($period) { 154*bc2653b0SSzymon Olewniczak $from = $period->getStartDate()->format(\DateTime::ISO8601); 155*bc2653b0SSzymon Olewniczak $to = $period->getEndDate()->format(\DateTime::ISO8601); 156*bc2653b0SSzymon Olewniczak 157*bc2653b0SSzymon Olewniczak $sql = "SELECT label_name, 158*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'proposal' THEN 1 END) AS proposal, 159*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'opened' THEN 1 END) AS opened, 160*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'done' THEN 1 END) AS done, 161*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'closed' THEN 1 END) AS closed, 162*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'rejected' THEN 1 END) AS rejected, 163*bc2653b0SSzymon Olewniczak COUNT(*) AS count_all, 164*bc2653b0SSzymon Olewniczak SUM(task_sum_cost) AS sum_all, 165*bc2653b0SSzymon Olewniczak SUM(CASE WHEN state = 'closed' THEN task_sum_cost END) AS sum_closed, 166*bc2653b0SSzymon Olewniczak (CASE WHEN state = 'closed' THEN 167*bc2653b0SSzymon Olewniczak AVG(julianday(close_date) - julianday(create_date)) 168*bc2653b0SSzymon Olewniczak END) AS avg_closed 169*bc2653b0SSzymon Olewniczak FROM thread_view 170*bc2653b0SSzymon Olewniczak WHERE type = 'project' AND create_date BETWEEN ? AND ?"; 171*bc2653b0SSzymon Olewniczak 172*bc2653b0SSzymon Olewniczak $r = $this->model->sqlite->query($sql, $from, $to); 173*bc2653b0SSzymon Olewniczak } else { 174*bc2653b0SSzymon Olewniczak $sql = "SELECT label_name, 175*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'proposal' THEN 1 END) AS proposal, 176*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'opened' THEN 1 END) AS opened, 177*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'done' THEN 1 END) AS done, 178*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'closed' THEN 1 END) AS closed, 179*bc2653b0SSzymon Olewniczak COUNT(CASE WHEN state = 'rejected' THEN 1 END) AS rejected, 180*bc2653b0SSzymon Olewniczak COUNT(*) AS count_all, 181*bc2653b0SSzymon Olewniczak SUM(task_sum_cost) AS sum_all, 182*bc2653b0SSzymon Olewniczak SUM(CASE WHEN state = 'closed' THEN task_sum_cost END) AS sum_closed, 183*bc2653b0SSzymon Olewniczak (CASE WHEN state = 'closed' THEN 184*bc2653b0SSzymon Olewniczak AVG(julianday(close_date) - julianday(create_date)) 185*bc2653b0SSzymon Olewniczak END) AS avg_closed 186*bc2653b0SSzymon Olewniczak FROM thread_view 187*bc2653b0SSzymon Olewniczak WHERE type = 'project'"; 188*bc2653b0SSzymon Olewniczak 189*bc2653b0SSzymon Olewniczak $r = $this->model->sqlite->query($sql); 190*bc2653b0SSzymon Olewniczak } 191*bc2653b0SSzymon Olewniczak return $r; 192*bc2653b0SSzymon Olewniczak } 193*bc2653b0SSzymon Olewniczak 1948a638198SSzymon Olewniczak public function initial_save(Entity $thread, $data) { 1957fbf4c39SSzymon Olewniczak $label_ids = array(); 1967fbf4c39SSzymon Olewniczak if (isset($data['label_id']) && $data['label_id'] != '') { 1977fbf4c39SSzymon Olewniczak $label_ids[] = $data['label_id']; 1987fbf4c39SSzymon Olewniczak } 1997fbf4c39SSzymon Olewniczak try { 2007fbf4c39SSzymon Olewniczak $this->beginTransaction(); 201a0cd8c78SSzymon Olewniczak 20253df74e7SSzymon Olewniczak parent::initial_save($thread, $data); 2037fbf4c39SSzymon Olewniczak 2047fbf4c39SSzymon Olewniczak foreach($label_ids as $label_id) { 2057fbf4c39SSzymon Olewniczak $thread->add_label($label_id); 2067fbf4c39SSzymon Olewniczak } 2077fbf4c39SSzymon Olewniczak 2087fbf4c39SSzymon Olewniczak $thread->set_participant_flags($thread->original_poster, array('original_poster', 'subscribent')); 2097fbf4c39SSzymon Olewniczak if($thread->coordinator != null) { 2107fbf4c39SSzymon Olewniczak $thread->set_participant_flags($thread->coordinator, array('coordinator', 'subscribent')); 2117fbf4c39SSzymon Olewniczak } 2127fbf4c39SSzymon Olewniczak 213a0cd8c78SSzymon Olewniczak if ($this->model->get_level() >= BEZ_AUTH_LEADER) { 21453df74e7SSzymon Olewniczak $private = false; 21553df74e7SSzymon Olewniczak if (isset($data['private'])) { 21653df74e7SSzymon Olewniczak $private = true; 21753df74e7SSzymon Olewniczak } 21853df74e7SSzymon Olewniczak $thread->set_private_flag($private); 21953df74e7SSzymon Olewniczak } 22053df74e7SSzymon Olewniczak 2218a638198SSzymon Olewniczak $this->commitTransaction(); 2228a638198SSzymon Olewniczak 2238a638198SSzymon Olewniczak if ($thread->state != 'proposal' && $this->model->user_nick != $thread->coordinator) { 2248a638198SSzymon Olewniczak $thread->mail_inform_coordinator(); 225e09b232fSSzymon Olewniczak } elseif ($thread->state == 'proposal') { 226e09b232fSSzymon Olewniczak $thread->mail_inform_admins(); 2277fbf4c39SSzymon Olewniczak } 22814a1f0a4SSzymon Olewniczak 22914a1f0a4SSzymon Olewniczak } catch(Exception $exception) { 23014a1f0a4SSzymon Olewniczak $this->rollbackTransaction(); 23114a1f0a4SSzymon Olewniczak } 2327fbf4c39SSzymon Olewniczak } 2337fbf4c39SSzymon Olewniczak 234b90263acSSzymon Olewniczak protected function update(Entity $obj) { 235b90263acSSzymon Olewniczak if ($obj->state == 'done') { 2365b88664dSSzymon Olewniczak $prev_state = $obj->state; 237b90263acSSzymon Olewniczak $reflectionClass = new \ReflectionClass('dokuwiki\plugin\bez\mdl\Thread'); 238b90263acSSzymon Olewniczak $reflectionProperty = $reflectionClass->getProperty('state'); 239b90263acSSzymon Olewniczak $reflectionProperty->setAccessible(true); 240b90263acSSzymon Olewniczak $reflectionProperty->setValue($obj, 'opened'); 241b90263acSSzymon Olewniczak } 242b90263acSSzymon Olewniczak try { 243b90263acSSzymon Olewniczak parent::update($obj); 244b90263acSSzymon Olewniczak } finally { 2455b88664dSSzymon Olewniczak if (isset($prev_state)) { 246b90263acSSzymon Olewniczak $reflectionProperty->setValue($obj, $prev_state); 247b90263acSSzymon Olewniczak } 248b90263acSSzymon Olewniczak } 2495b88664dSSzymon Olewniczak } 250b90263acSSzymon Olewniczak 2518a638198SSzymon Olewniczak public function update_save(Entity $thread, $data) { 2527fbf4c39SSzymon Olewniczak $prev_coordinator = $thread->coordinator; 25353df74e7SSzymon Olewniczak 2547fbf4c39SSzymon Olewniczak $label_ids = array(); 2557fbf4c39SSzymon Olewniczak if (isset($data['label_id']) && $data['label_id'] != '') { 2567fbf4c39SSzymon Olewniczak $label_ids[] = $data['label_id']; 2577fbf4c39SSzymon Olewniczak } 2587fbf4c39SSzymon Olewniczak try { 2597fbf4c39SSzymon Olewniczak $this->beginTransaction(); 26053df74e7SSzymon Olewniczak parent::update_save($thread, $data); 2617fbf4c39SSzymon Olewniczak 2627fbf4c39SSzymon Olewniczak $cur_label_ids = array_keys($thread->get_labels()); 2637fbf4c39SSzymon Olewniczak $labels_to_add = array_diff($label_ids, $cur_label_ids); 2647fbf4c39SSzymon Olewniczak $labels_to_rem = array_diff($cur_label_ids, $label_ids); 2657fbf4c39SSzymon Olewniczak 2667fbf4c39SSzymon Olewniczak foreach($labels_to_add as $label_id) { 2677fbf4c39SSzymon Olewniczak $thread->add_label($label_id); 2687fbf4c39SSzymon Olewniczak } 2697fbf4c39SSzymon Olewniczak 2707fbf4c39SSzymon Olewniczak foreach($labels_to_rem as $label_id) { 2717fbf4c39SSzymon Olewniczak $thread->remove_label($label_id); 2727fbf4c39SSzymon Olewniczak } 2737fbf4c39SSzymon Olewniczak 2747fbf4c39SSzymon Olewniczak if ($thread->coordinator != null && $thread->coordinator != $prev_coordinator) { 275eb2e6be9SSzymon Olewniczak if ($prev_coordinator != null) { 2767fbf4c39SSzymon Olewniczak $thread->remove_participant_flags($prev_coordinator, array('coordinator')); 277eb2e6be9SSzymon Olewniczak } 2787fbf4c39SSzymon Olewniczak $thread->set_participant_flags($thread->coordinator, array('subscribent', 'coordinator')); 2797fbf4c39SSzymon Olewniczak } 2807fbf4c39SSzymon Olewniczak 28153df74e7SSzymon Olewniczak if ($thread->acl_of('private') >= BEZ_PERMISSION_CHANGE) { 28253df74e7SSzymon Olewniczak $private = false; 28353df74e7SSzymon Olewniczak if (isset($data['private'])) { 28453df74e7SSzymon Olewniczak $private = true; 28553df74e7SSzymon Olewniczak } 28653df74e7SSzymon Olewniczak $thread->set_private_flag($private); 28753df74e7SSzymon Olewniczak } 28853df74e7SSzymon Olewniczak 2898a638198SSzymon Olewniczak $this->commitTransaction(); 2907fbf4c39SSzymon Olewniczak } catch(Exception $exception) { 2918a638198SSzymon Olewniczak $this->rollbackTransaction(); 2928a638198SSzymon Olewniczak } 2938a638198SSzymon Olewniczak 2948a638198SSzymon Olewniczak if ($thread->state != 'proposal' && $this->model->user_nick != $thread->coordinator) { 2958a638198SSzymon Olewniczak $thread->mail_inform_coordinator(); 2967fbf4c39SSzymon Olewniczak } 2977fbf4c39SSzymon Olewniczak } 298de02284cSSzymon Olewniczak} 299