tra('Convene'), 'documentation' => 'PluginConvene', 'description' => tra('Suggest meeting dates and times and vote to select one'), 'introduced' => 9, 'prefs' => ['wikiplugin_convene','feature_calendar'], 'body' => tra('Convene data generated from user input'), 'iconname' => 'group', 'filter' => 'rawhtml_unsafe', 'tags' => [ 'basic' ], 'format' => 'html', 'params' => [ 'title' => [ 'required' => false, 'name' => tra('Title'), 'description' => tra('Title for the event'), 'since' => '9.0', 'default' => tra('Convene'), ], 'calendarid' => [ 'required' => false, 'name' => tra('Calendar ID'), 'description' => tra('ID number of the site calendar in which to store the date for the events with the most votes'), 'since' => '9.0', 'filter' => 'digits', 'default' => 1, 'profile_reference' => 'calendar', ], 'minvotes' => [ 'required' => false, 'name' => tra('Minimum Votes'), 'description' => tra('Minimum number of votes needed to show Add-to-Calendar icon, so that new users do not see a potentially confusing icon before the convene has enough information on it'), 'since' => '10.3', 'filter' => 'digits', 'default' => 3, ], 'dateformat' => [ 'required' => false, 'name' => tra('Date-Time Format'), 'description' => tra('Display date and time in short or long format, according to the site wide setting (or use "other" to specify a custom format below)'), 'since' => '9.0', 'filter' => 'alpha', 'default' => 'short', 'options' => [ ['text' => '', 'value' => ''], ['text' => tra('Short'), 'value' => 'short'], ['text' => tra('Long'), 'value' => 'long'], ['text' => tra('Other'), 'value' => 'other'], ] ], 'dateformatother' => [ 'required' => false, 'name' => tra('Other Date-Time Format'), 'description' => tra('Use a custom format string for the dates using PHP "strftime" or "date_format" parameters'), 'since' => '23.0', 'filter' => 'text', 'default' => '', ], 'adminperms' => [ 'required' => false, 'name' => tra('Observe Admin Permissions'), 'description' => tra("Only admins can edit or delete other users' votes and dates. N.B. This is a guide only as if a user can edit the page they can change this setting, it is intended to make the plugin easier to use for most users."), 'since' => '9.0', 'filter' => 'alpha', 'default' => 'y', 'options' => [ ['text' => '', 'value' => ''], ['text' => tra('Yes'), 'value' => 'y'], ['text' => tra('No'), 'value' => 'n'] ] ], 'avatars' => [ 'required' => false, 'name' => tra('Show user profile pictures'), 'description' => tra("Show user's profile pictures next to their names."), 'since' => '9.0', 'filter' => 'alpha', 'default' => 'y', 'options' => [ ['text' => '', 'value' => ''], ['text' => tra('Yes'), 'value' => 'y'], ['text' => tra('No'), 'value' => 'n'] ] ], 'autolock' => [ 'required' => false, 'name' => tra('Automatic Lock'), 'description' => tra('Lock this plugin at a certain time and date (format YYYY-MM-DD hh:mm'), 'since' => '20.2', 'filter' => 'datetime', 'default' => '', ], 'locked' => [ 'required' => false, 'name' => tra('Locked'), 'description' => tra('Prevent further votes or changes from the interface.'), 'since' => '20.2', 'filter' => 'alpha', 'default' => 'n', 'options' => [ ['text' => '', 'value' => ''], ['text' => tra('Yes'), 'value' => 'y'], ['text' => tra('No'), 'value' => 'n'] ], ], 'id' => [ 'required' => false, 'name' => tra('Id of the form'), 'description' => tra('Leave blank automatically generate.'), 'since' => '23.0', 'filter' => 'text', 'default' => '', ], 'voteoptions' => [ 'required' => false, 'name' => tra('Vote options'), 'description' => tra('Comma-separated for personalized set of vote options'), 'since' => '24.0', 'filter' => 'text', 'default' => default_voteoptions(), 'separator' => ',', 'accepted' => tr('-1=Not OK,-0.5=No but...,0=Unconfirmed,0.5=OK but...,1=OK'), ], ] ]; } function wikiplugin_convene($data, $params): string { global $page; /** @var HeaderLib $headerlib */ $headerlib = TikiLib::lib('header'); /** @var TikiLib $tikilib */ $tikilib = TikiLib::lib('tiki'); /** @var Smarty_Tiki $smarty */ $smarty = TikiLib::lib('smarty'); $smarty->loadPlugin('smarty_function_icon'); $smarty->loadPlugin('smarty_modifier_userlink'); $smarty->loadPlugin('smarty_modifier_avatarize'); if (! isset($params['voteoptions'])) { $params['voteoptions'] = default_voteoptions(); } if (! is_array($params['voteoptions'])) { $params['voteoptions'] = explode(',', $params['voteoptions']); } //in case there is any feedback from a previous ajax action since this plugin does not refresh the page upon edit Feedback::sendHeaders(); //Test if vote options are numeric value foreach ($params['voteoptions'] as $voteoption) { $optionvalue = explode('=', $voteoption); if (!is_numeric($optionvalue[0])) { Feedback::error(tr('Plugin convene: one or more of your option values must be numeric values')); } } static $convenePluginIndex = 0; ++$convenePluginIndex; //set defaults $plugininfo = wikiplugin_convene_info(); $defaults = []; foreach ($plugininfo['params'] as $key => $param) { $defaults[$key] = $param['default']; } $params = array_merge($defaults, $params); $params['index'] = $convenePluginIndex; $params['id'] = empty($params['id']) ? 'pluginConvene' . $convenePluginIndex : $params['id']; $dataArrays = json_decode($data, true); $dataArray = $dataArrays[0]; // Default data votes $dataArrayComments = $dataArrays[1]; //Data comments if (! is_array($dataArray)) { //start flat static text to prepared array $dataString = $data . ''; $dataArray = []; $lines = explode("\n", trim($data)); sort($lines); foreach ($lines as $line) { $line = trim($line); if (! empty($line)) { $parts = explode(':', $line); $dataArray[trim($parts[0])] = trim($parts[1]); } } $data = TikiFilter_PrepareInput::delimiter('_')->prepare($dataArray); //end flat static text to prepared array $data = $data['dates']; } else { $data = $dataArray; } $tikiDate = new TikiDate(); $gmformat = str_replace($tikiDate->search, $tikiDate->replace, $tikilib->get_short_datetime_format()); //start votes summed together $votes = []; $dateLabels = []; foreach ($data as $stamp => & $date) { foreach ($date as $user => $vote) { if (empty($votes[$stamp])) { $votes[$stamp] = 0; } $votes[$stamp] += $vote; } $dateLabels[$stamp] = []; if ($params['dateformat'] === "long") { $dateLabels[$stamp]['formatted'] = $tikilib->get_long_datetime($stamp); } elseif ($params['dateformat'] === 'other') { $format = $params['dateformatother']; if (strpos($format, '%') === 0) { // assuming a strftime format starts with % $dateLabels[$stamp]['formatted'] = TikiLib::date_format($format, $stamp); } else { $dateLabels[$stamp]['formatted'] = TikiLib::date_format2($format, $stamp); } } else { $dateLabels[$stamp]['formatted'] = $tikilib->get_short_datetime($stamp); } $dateLabels[$stamp]['gmdate'] = tr('UTC date time: %0', gmdate($gmformat, $stamp)); } //end votes summed together //start find top vote stamps $topVoteStamps = []; $topVotes = max($votes); foreach ($votes as $stamp => $vote) { if ($vote === $topVotes) { $topVoteStamps[] = $stamp; } } //end find top vote stamp //start reverse array for easy listing as table $rows = []; unset($date); foreach ($data as $stamp => $date) { foreach ($date as $user => $vote) { if (isset($rows[$user][$stamp])) { $rows[$user][$stamp] = []; } $rows[$user][$stamp] = $vote; } } //end reverse array for easy listing as table $autolockMessage = ''; if ($params['autolock']) { if (! preg_match('/\d{4}-\d{2}-\d{2} \d{2}:\d/', $params['autolock'])) { $autolock = TikiLib::date_format('%Y-%m-%d %H:%M', strtotime($params['autolock'])); if (! $autolock) { Feedback::error(tr('Plugin convene: autolock date format not recognised')); } else { $params['autolock'] = $autolock; } } $lockDate = new TikiDate(); $lockDate->setDate($params['autolock']); $smarty->loadPlugin('smarty_modifier_tiki_short_datetime'); if ($lockDate < $tikiDate) { $params['locked'] = 'y'; $autolockMessage = tr('Voting ended: %0', smarty_modifier_tiki_short_datetime($params['autolock'])); } else { $autolockMessage = tr('Voting ends: %0', smarty_modifier_tiki_short_datetime($params['autolock'])); } } $smarty->assign('autolockMessage', $autolockMessage); // perms for this object $currentObject = current_object(); $perms = Perms::get($currentObject); $canEdit = $perms->edit; if ($params['adminperms'] !== 'y') { $canAdmin = $canEdit; } elseif ($currentObject['type'] === 'wiki page') { $canAdmin = $perms->admin_wiki; } elseif ($currentObject['type'] === 'trackeritem') { $canAdmin = $perms->admin_trackers; } else { $canAdmin = $perms->admin; // global for other object types } if ($params['calendarid'] > 0) { $calperms = Perms::get([ 'type' => 'calendar', 'object' => $params['calendarid'], ]); $canAddEvents = $calperms->add_events; } $smarty->assign('canEdit', $canEdit); $smarty->assign('canAdmin', $canAdmin); $smarty->assign('canAddEvents', $canAddEvents); $smarty->assign('dates', $data); $smarty->assign('dateLabels', $dateLabels); $smarty->assign('rows', $rows); $smarty->assign('votes', $votes); $smarty->assign('topVoteStamps', $topVoteStamps); $smarty->assign('params', $params); $smarty->assign('comments', $dataArrayComments); if($params['locked'] === "y"){ $vote_infos=[ "autolock" => $params['autolock'], "object" => $currentObject['object'], "users" => array_keys($rows), "votes" => $votes ]; send_email_result_vote($vote_infos); } $conveneData = json_encode($params); $headerlib->add_jsfile('lib/jquery_tiki/wikiplugin-convene.js') ->add_js("\$('#{$params['id']}').setupConvene($conveneData)"); return $smarty->fetch('wiki-plugins/wikiplugin_convene.tpl'); } function default_voteoptions() { return '-1=Not OK,0=Unconfirmed,1=OK'; } /** * This module will help to send message to all member who participate on vote * when lock time reached. * * @param $vote_infos * * @throws Exception */ function send_email_result_vote($vote_infos){ $date_start = TikiLib::date_format('%Y-%m-%d %H:%M',strtotime("now")); if ($vote_infos["autolock"] === $date_start) { $users=$vote_infos["users"]; $votes=$vote_infos["votes"]; include_once('lib/webmail/tikimaillib.php'); $userlib = TikiLib::lib('user'); $smarty = TikiLib::lib('smarty'); $tikilib = TikiLib::lib('tiki'); $mail = new TikiMail(); $machine = parse_url($_SERVER['REQUEST_URI']); $machine = $tikilib->httpPrefix(true) . dirname($machine['path']); $smarty->assign_by_ref('machine', $machine); $machine = preg_replace("!/$!", "", $machine); $smarty->assign('mail_machine', $machine); $smarty->assign('mail_site', $_SERVER["SERVER_NAME"]); $object_event = $vote_infos['object']; $event_path = str_replace(" ","-",$object_event); $max_vote = 0; $vote_result = ""; arsort($votes); $i = 0; foreach($votes as $date => $vote) { if ($i === 0) { $max_vote = $vote; } if ($max_vote === $vote) { $date_vote = TikiLib::date_format('%Y-%m-%d %H:%M', $date); if ($i === 0) { $vote_result = $vote . tra("votes on date of ") . $date_vote." "; } else { $vote_result.= tra("and"). " ".$date_vote; } } $i++; } foreach ($users as $user) { $userinfo = $userlib->get_user_email($user); if ($userinfo) { $smarty->assign('mail_user', $user); $smarty->assign('event_link_path', $event_path); $smarty->assign('vote_result', $vote_result); $mail->setUser($userinfo); $subject = sprintf($smarty->fetch('mail/convene_vote_result_subject.tpl'),$object_event,$_SERVER['SERVER_NAME']); $mail->setSubject($subject); $txt = $smarty->fetch('mail/convene_vote_result.tpl'); $mail->setText($txt); $mail->send([$userinfo]); } } } }