1<?php 2/** 3 * DokuWiki Plugin structtasks 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Chris MacMackin <cmacmackin@gmail.com> 7 * 8 */ 9 10namespace dokuwiki\plugin\structtasks\meta; 11 12use dokuwiki\plugin\struct\types\Date; 13use dokuwiki\plugin\struct\types\DateTime; 14use dokuwiki\plugin\struct\types\Dropdown; 15use dokuwiki\plugin\struct\types\User; 16use dokuwiki\plugin\struct\types\Mail; 17use dokuwiki\plugin\struct\types\Text; 18 19/** 20 * Class with various useful static methods. 21 */ 22class Utilities 23{ 24 protected $struct; 25 /// Date-time formata for the due-date, extracted from the 26 /// most-recently validated schema and cached here. 27 protected $duedate_formats = []; 28 29 /** 30 * Pass in an instance of the struct_helper plugin when building this class; 31 * @param mixed $helper 32 */ 33 public function __construct($helper) { 34 $this->struct = $helper; 35 } 36 37 /** 38 * Tests whether the specified schema meets the requirements for 39 * describing tasks. 40 * @return bool 41 * @param mixed $schema 42 */ 43 function isValidSchema($schema): bool { 44 $schemas_found = $this->struct->getSchema($schema); 45 $s = $schemas_found[$schema]; 46 if ($s->getTimeStamp() == 0) { 47 msg("Schema '${schema}', needed for structtasks, does not exist.", -1); 48 return false; 49 } 50 $col_names = ['duedate', 'assignees', 'status']; 51 $col_types = [ 52 'duedate' => [Date::class, DateTime::class], 53 'assignees' => [User::class, Mail::class], 54 'status' => [Dropdown::class, Text::class] 55 ]; 56 $accepts_multi = [ 57 'duedate' => false, 58 'assignees' => true, 59 'status' => false, 60 ]; 61 $columns = []; 62 $valid = true; 63 foreach ($col_types as $name => $types) { 64 $col = $s->findColumn($name); 65 if ($col === false) { 66 msg("structtasks schema '$schema' has no column '$name'.", -1); 67 $valid = false; 68 } else { 69 $coltype = get_class($col->getType()); 70 if (!in_array($coltype, $types)) { 71 msg("Column '${name}' of structtasks schema '$schema' has invalid type ${coltype}", -1); 72 $valid = false; 73 } 74 if ($accepts_multi[$name] xor $col->isMulti()) { 75 msg("Column '${name}' of structtasks schema '$schema' must not accept multiple values; change the configurations", -1); 76 $valid = false; 77 } 78 } 79 } 80 if ($valid) $this->duedate_formats[$schema] = $s->findColumn('duedate')->getType()->getConfig()['format']; 81 return $valid; 82 } 83 84 /** 85 * Gets the date format for the specified schema. Throws an error 86 * if schema is not valid for use by structtasks. 87 */ 88 function dateFormat($schema) { 89 if (!array_key_exists($schema, $this->duedate_formats)) { 90 $this->isValidSchema($schema); 91 } 92 return $this->duedate_formats[$schema]; 93 } 94 95 /** 96 * Safely fetches the old and new struct metadata for this 97 * event. Also returns a flag indicating if this page is even a 98 * valid task for which notifications could be sent. 99 */ 100 function getMetadata($id, $schema, $old_rev, $new_rev) { 101 if (!$this->isValidSchema($schema)) { 102 return [NULL, NULL, false]; 103 } 104 $old_data = $this->struct->getData($id, null, $old_rev); 105 $new_data = $this->struct->getData($id, null, $new_rev); 106 if (!array_key_exists($schema, $old_data) or !array_key_exists($schema, $new_data)) { 107 return [NULL, NULL, false]; 108 } 109 $dateformat = $this->dateFormat($schema); 110 $old_data[$schema]['date_format'] = 111 $new_data[$schema]['date_format'] = $this->dateFormat($schema); 112 return [$this->formatData($old_data[$schema], $dateformat), 113 $this->formatData($new_data[$schema], $dateformat), 114 true]; 115 } 116 117 /** 118 * Return a string with the real name and email address of $user, 119 * suitable for using to send them an email. 120 */ 121 function getUserEmail($user) { 122 global $auth; 123 $userData = $auth->getUserData($user, false); 124 if ($userData === false) { 125 if (mail_isvalid($user)) { 126 return $user; 127 } else { 128 return ''; 129 } 130 } 131 $realname = $userData['name']; 132 $email = $userData['mail']; 133 if ($realname === '') return $email; 134 if (strpos($userData['name'], ',')) $realname = '"' . $realname; 135 return "${realname} <${email}>"; 136 } 137 138 /** 139 * Convert a list of usernames into a list of formatted email 140 * addresses. 141 */ 142 function assigneesToEmails($assignees) { 143 if (!is_array($assignees)) { 144 $assignees = [$assignees]; 145 } 146 return array_values(array_filter(array_map([$this, 'getUserEmail'], $assignees))); 147 } 148 149 /** 150 * Processes the data returned by the struct plugin to put it in a 151 * format useful for this plugin. 152 */ 153 function formatData($structdata, $dateformat) { 154 if ($structdata['duedate'] !== '') { 155 $d = date_create($structdata['duedate']); 156 $df = $d->format($dateformat); 157 } else { 158 $d = null; 159 $df = ''; 160 } 161 return [ 162 'duedate' => $d, 163 'duedate_formatted' => $df, 164 'assignees' => $this->assigneesToEmails($structdata['assignees']), 165 'status' => $structdata['status'], 166 ]; 167 } 168} 169