Changeset 606
- Timestamp:
- Sep 25, 2007 12:42:01 AM (6 years ago)
- Location:
- trunk/jpdd
- Files:
-
- 2 added
- 4 edited
-
class.dkg.broadcast.php (added)
-
class.dkg.site.php (modified) (7 diffs)
-
class.jpdd.broadcast.php (added)
-
class.jpdd.php (modified) (2 diffs)
-
config.inc.php (modified) (1 diff)
-
sql/db.sql (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/jpdd/class.dkg.site.php
r603 r606 100 100 'table' => $this->_users['tablename'], 101 101 'sort' => $this->_users['username'])); 102 $this->addClassMapEntry('broadcast', array('classname' => 'DKG_Broadcast', 103 'filename' => 'class.dkg.broadcast.php', 104 'table' => 'broadcast', 105 'sort' => 'id DESC')); 102 106 $this->addClassMapEntry('privilege', array('classname' => 'DKG_Privilege', 103 107 'filename' => 'class.dkg.privilege.php', … … 197 201 198 202 function getAllowedActions() { 199 return array('edit', 'login', 'logout', 'resetpass', 'newacct', ' broadcast');203 return array('edit', 'login', 'logout', 'resetpass', 'newacct', 'send', 'copy'); 200 204 } 201 205 … … 983 987 return $this->getLoginForm(); // login form shows logout form if currently logged in. 984 988 } 989 } elseif ($this->_action == 'copy') { 990 if ($this->isEmpty($this->_type) || $this->isEmpty($this->_identifier)) 991 $this->error('Nothing to copy'); 992 if (!$this->canCreate($this->_type)) 993 return $this->permissionDenied('Creating '.$this->_type.' not allowed.'); 994 995 // must be able to edit and create in order to copy? 996 $item = $this->getItem($this->_type, $this->_identifier); 997 // unset the ID. 998 $item->_id = NULL; 999 return $item->getCreationForm(); 1000 985 1001 } elseif ($this->_action == 'edit') { 986 1002 if ($this->isEmpty($this->_type)) { … … 1011 1027 } 1012 1028 } 1013 } elseif ($this->_action == ' broadcast') {1029 } elseif ($this->_action == 'send') { 1014 1030 if ($this->isAuthenticated() && $this->_authenticated_user->HasAllOfThesePrivileges('Send Broadcast')) { 1015 if ($_SERVER['REQUEST_METHOD'] == 'POST') { 1016 // verify form token, or just quit: 1017 if (!$this->verifyFormToken()) { 1018 $this->addWarning('Bad form token mismatch!'); 1019 return ''; 1020 } 1021 if ($_POST['submit'] == 'Send') { 1022 return $this->sendBroadcastEmails(); 1023 } else { 1024 return $this->getBroadcastEmailForm(); 1025 } 1031 $item = $this->getItem('broadcast', $this->_identifier); 1032 if ($_SERVER['REQUEST_METHOD'] != 'POST') { 1033 $this->addWarning('You must POST all broadcast sending pages.'); 1034 } else if ($this->_type != 'broadcast') { 1035 $this->addWarning('You can only send broadcast items'); 1036 } else if (!$this->verifyFormToken()) { 1037 $this->addWarning('Bad form token mismatch!'); 1026 1038 } else { 1027 return $this->getBroadcastEmailForm(); 1039 // need to actually send the damn e-mails here. 1040 $item->sendEmailsToOutstandingPeople(); 1028 1041 } 1042 return $item->getDetailView(); 1029 1043 } else 1030 1044 return $this->permissionDenied('Broadcast not allowed.'); … … 1034 1048 } 1035 1049 1036 function getBroadcastSelectors() { 1037 // override to return an array that maps internal keys to 1038 // visible labels and SQL statements. For example: 1039 return array('all' => array('description' => 'Every account with a confirmed e-mail', 1040 'sql' => 'SELECT * FROM person WHERE pass IS NOT NULL')); 1041 } 1042 1043 function getAllowedTemplates() { 1044 // override to return an array that maps selectors to 1045 // array('description' = "human readable", 'function' => actual 1046 // php function) 1047 return array('[[NAME]]' => array('description' => 'The person\'s name', 1048 'function' => create_function('$x', 'return $x->getTitle();')), 1049 // FIXME: during the preview display, this feature 1050 // actually allows the previewer to see the reset 1051 // link for the user being previewed. This is a 1052 // security flaw. 1053 '[[PASSWORD_RESET]]' => array('description' => 'A link that lets the person change hir password', 1054 'function' => create_function('$x', 'global $dkg_site; return $dkg_site->handleResetPassRequest($x->_email, false);'))); 1055 } 1056 1057 function getAllowedTemplateLegend() { 1058 $temps = $this->getAllowedTemplates(); 1059 return "<div class=\"template-legend\">Allowed personalization terms:<dl>\n". 1060 join('', array_map(create_function('$x,$y', 'return "<dt>".$x."</dt>\n<dd>".$y["description"]."</dd>\n";'), 1061 array_keys($temps), $temps))."</dl>\n</div>\n"; 1062 } 1063 1064 function getBroadcastSelectorInput($selector_name = NULL) { 1065 $selectors = $this->getBroadcastSelectors(); 1066 return '<select name="selector"> 1067 '.join("\n", array_map(create_function('$v, $l', 'global $dkg_site; return "<option value=\"".$v."\" ".($v == "'.$selector_name.'" ? "selected" : "").">".$l["description"]." (".$dkg_site->getValueFromSQL("SELECT COUNT(*) AS count FROM (".$l["sql"].") AS selector", "count").")</option>";'), array_keys($selectors), $selectors)).' 1068 </select> 1069 '; 1070 } 1071 1072 // $txt can be either a string or an array of strings. the return 1073 // value will match. 1074 function applyBroadcastTemplate($txt, $user) { 1075 $temps = $this->getAllowedTemplates(); 1076 $vals = array(); 1077 reset($temps); 1078 while(list($temp,$x) = each($temps)) { 1079 $vals[] = $x['function']($user); 1080 } 1081 return str_ireplace(array_keys($temps), $vals, $txt); 1082 } 1083 1084 function sendBroadcastEmails() { 1085 if ($_SERVER['REQUEST_METHOD'] != 'POST') { 1086 $this->addWarning('You cannot send broadcasts with a GET request.'); 1087 return ''; 1088 } 1089 1090 $subj = $_POST['subject']; 1091 $content = $_POST['content']; 1092 $personal = ($_POST['personal'] == 'personal'); 1093 1094 $selector_name = $_POST['selector']; 1095 $selectors = $this->getBroadcastSelectors(); 1096 if (!array_key_exists($selector_name, $selectors)) { 1097 $this->addWarning('You chose an unavailable selector!'); 1098 return ''; 1099 } 1100 $selector = $selectors[$selector_name]; 1101 1102 // store this broadcast template in the database: 1103 $bid = $this->insertBroadcast($subj, $content, $selector_name); 1104 1105 // we're gonna grab some peops: 1106 $map = $this->prepClass('person'); 1107 $cname = $map['classname']; 1108 $objs = $this->getSeriesFromSQL($selector['sql'], $cname); 1109 $attempted = 0; 1110 $succeeded = 0; 1111 $skipped = array(); 1112 reset($objs); 1113 while(list(,$obj) = each($objs)) { 1114 $to = $obj->_email; 1115 if (is_null($to) || !is_null($this->isValid('email', $to))) { 1116 $skipped[] = $obj; 1117 } else { 1118 $subject = trim(str_replace("\n", '', $this->applyBroadcastTemplate($subj, $obj))); 1119 $body = trim(wordwrap($this->applyBroadcastTemplate($content, $obj))); 1120 $attempted++; 1121 if ($this->mail('broadcast', $to, $subject, $body, array(), $personal, $bid)) 1122 $succeeded++; 1123 } 1124 } 1125 return $succeeded.' out of '.$attempted.' mails sent.'. 1126 (count($skipped) > 0 ? '<br/>Did not try the following people because they had no valid e-mail address: <ul>'. 1127 join('', array_map(create_function('$x', 'return "<li>".$x->getLinkedTitle()."\n";'), $skipped)).'</ul>': ''); 1128 } 1050 1129 1051 1130 1052 function getFromAddressSelector($personal = false) { … … 1133 1055 <label><input name="personal" type="radio" value="personal" '.($personal ? 'checked' : '').'>'.htmlentities(trim(str_replace("\n", '', $this->_authenticated_user->getTitle().' <'.$this->_authenticated_user->_email.'>'))).'</label> 1134 1056 </div>'; 1135 }1136 1137 function getBroadcastEmailForm() {1138 $subj = '';1139 $content = '';1140 $preview = '';1141 $ret = '';1142 $selector_name = '';1143 $from = trim(str_replace("\n", '', $this->getSiteName().' <'.$this->_site_email_from.'>'));1144 $personal = false;1145 1146 if ($_SERVER['REQUEST_METHOD'] == 'POST') {1147 if ($this->_actually_send_email)1148 $this->addWarning('Sending e-mail is actually enabled. Please be careful with this!');1149 else1150 $ret .= '<div>Sending e-mail is currently disabled. Messages will be logged, but not actually sent.</div>';1151 $subj = $_POST['subject'];1152 $content = $_POST['content'];1153 $personal = (($_POST['personal'] == 'personal') && $this->isAuthenticated());1154 1155 if ($personal)1156 $from = trim(str_replace("\n", '', $this->_authenticated_user->getTitle().' <'.$this->_authenticated_user->_email.'>'));1157 1158 1159 $selector_name = $_POST['selector'];1160 $selectors = $this->getBroadcastSelectors();1161 if (!array_key_exists($selector_name, $selectors)) {1162 $this->addWarning('You chose an unavailable selector!');1163 return '';1164 }1165 $selector = $selectors[$selector_name];1166 1167 $preview = '<fieldset><legend>Preview Example:</legend>';1168 1169 // we're gonna grab a person:1170 $map = $this->prepClass('person');1171 $cname = $map['classname'];1172 $data = $this->getSingletonFromSQL($selector['sql'].' LIMIT 1', false);1173 if (is_null($data)) {1174 $preview .= '<span class="error">There are no selectors which match <q>'.$selector['description'].'</q></span>';1175 } else {1176 $obj = new $cname(array('data' => $data));1177 $preview .= '<pre>To: '.$obj->_email.'1178 From: '.htmlentities($from).'1179 Subject: '.htmlentities(trim(str_replace("\n", '', $this->applyBroadcastTemplate($subj, $obj)))).'1180 1181 '.htmlentities(trim(wordwrap($this->applyBroadcastTemplate($content, $obj)))).'</pre>';1182 }1183 $preview .= '</fieldset>';1184 } elseif (!$this->isEmpty($this->_type)) {1185 $template = $this->getSingletonFromSQL('SELECT * FROM broadcast WHERE id = '.(int)$this->_type);1186 $subj = $template['subj'];1187 $content = $template['body'];1188 }1189 1190 $alternates = $this->getMultiSeriesFromSQLByValue('SELECT broadcast.id AS id,MAX(subj) AS subj,DATE(whattime) AS date, COUNT(*) AS count from broadcast JOIN mail_log ON (broadcast_id = broadcast.id) GROUP BY broadcast.id,DATE(whattime) ORDER BY broadcast.id DESC', 'id');1191 if (count($alternates) > 0) {1192 $altout = '<div class="collapse" id="previous-broadcasts"><div class="title">Previous Broadcast E-mails:</div><div class="notes">click message subject to see or resubmit text from these messages</div><ul>';1193 reset($alternates);1194 while(list($id,$temp) = each($alternates)) {1195 $altout .= '<li'.((!$this->isEmpty($this->_type)) && ($this->_type == $id) ? ' class="selected"' : '' ).'><a href="'.$this->Path('broadcast', (int)$id).'">'.htmlentities($temp[0]['subj']).'</a><ul>'.1196 join("\n", array_map(create_function('$x', 'return $x["date"]."<div class=\"notes\">[sent to: ".$x["count"].($x["count"] == 1 ? " person" : " people")."]</div>";'), $temp)).'</ul></li>';1197 }1198 $altout .= '</ul></div>';1199 $ret .= $altout;1200 }1201 1202 return $ret.'<form name="broadcast" action="'.$this->Path('broadcast').'" method="post">1203 '.$this->getFormTokenHiddenInput().'1204 <fieldset><legend>Send to:</legend>1205 '.$this->getBroadcastSelectorInput($selector_name).'1206 </fieldset>1207 '.$preview.'1208 <fieldset><legend>Message Content:</legend>1209 '.$this->getAllowedTemplateLegend().'1210 From: '.$this->getFromAddressSelector($personal).'<br />1211 <label>Subject:<br />1212 <input name="subject" type="text" size="60" value="'.htmlentities($subj).'" /><br />1213 <label>Body:<br />1214 <textarea name="content" rows="20" cols="72">'.htmlentities($content).1215 '</textarea>1216 </label><br/>1217 <input type="submit" class="submit" name="submit" value="Preview"/>1218 '.($_SERVER['REQUEST_METHOD'] == 'POST' ? '<input class="submit" type="submit" name="submit" value="Send"/>' : '').'1219 </fieldset>1220 </form>';1221 1057 } 1222 1058 … … 1289 1125 } 1290 1126 1291 function insertBroadcast($subj, $body, $selector) {1292 $this->executeSQL('INSERT INTO broadcast (subj, body, selector, sender_id) VALUES ('.$this->escStr($subj).', '.1293 $this->escStr($body).', '.1294 $this->escStr($selector).', '.1295 (int)$this->_authenticated_user->getID().')');1296 // return the last id from the log:1297 return (int)$this->getValueFromSQL('SELECT currval(\'broadcast_id_seq\') AS broadcast_id', 'broadcast_id');1298 }1299 1300 1127 function log($data) { 1301 1128 $this->executeSQL('INSERT INTO log (data, backtrace, servervars) VALUES ('.$this->escStr($data).', '. -
trunk/jpdd/class.jpdd.php
r605 r606 24 24 'table' => 'person', 25 25 'sort' => 'lower(last_name),lower(first_name)')); 26 // likewise for DKG_Broadcast: 27 $this->addClassMapEntry('broadcast', array('classname' => 'JPDD_Broadcast', 28 'filename' => 'class.jpdd.broadcast.php', 29 'table' => 'broadcast', 30 'sort' => 'id DESC')); 26 31 $this->addClassMapEntry('category', array('classname' => 'JPDD_Category', 27 32 'filename' => 'class.jpdd.category.php', … … 56 61 $this->_stylesheets[] = 'jpdd.css'; 57 62 } 58 59 60 function getBroadcastSelectors() {61 // override to return an array that maps internal keys to62 // visible labels and SQL statements. For example:63 $roles = $this->getAll('role');64 $rsel = array(); // the per-role selectors65 reset($roles);66 while(list(,$role) = each($roles)) {67 $rsel['role:'.$role->getID()] = array('description' => 'All people acting as '.$role->getTitle(),68 'sql' => 'SELECT person.* FROM person JOIN person_role ON (person_id = person.id) WHERE role_id = '.$role->getID().69 ' AND event_id = '.$this->getActiveEventID());70 }71 // get a list of all72 73 return array_merge(array('presenters' => array('description' => 'Workshop Presenters',74 'sql' => 'SELECT person.* FROM person JOIN presenter ON (person.id = presenter.person_id) JOIN workshop ON (workshop_id = workshop.id) WHERE event_id = '.$this->getActiveEventID()),75 'attendees' => array('description' => 'Workshop Attendees',76 'sql' => 'SELECT person.* FROM person JOIN audience ON (person.id = audience.person_id) JOIN workshop ON (workshop_id = workshop.id) WHERE event_id = '.$this->getActiveEventID()),77 'jpdd_admins' => array('description' => 'People named Gillmor or Tashlik',78 'sql' => 'SELECT * FROM person WHERE last_name IN (\'Gillmor\', \'Tashlik\')')),79 $rsel,80 parent::getBroadcastSelectors()81 );82 }83 84 function getAllowedTemplates() {85 // override to return an array that maps selectors to86 // array('description' = "human readable", 'function' => actual87 // php function)88 return array_merge(parent::getAllowedTemplates(),89 // FIXME: these are pretty broken, actually, particularly if there is more than one workshop being attended.90 array('[[WORKSHOP]]' => array('description' => 'The workshop the person is attending (or "no workshop")',91 'function' => create_function('$x', '$ws = $x->getM2MPeers("workshop", "attendance"); if (count($ws) == 0) return "no workshop"; return join(", ", array_map(create_function(\'$x\', \'return html_entity_decode($x->getTitle());\'), $ws));')),92 '[[ROOM]]' => array('description' => 'The room number of the attended workshop (e.g. "Room 143" or "no room")',93 'function' => create_function('$x', '$ws = $x->getM2MPeers("workshop", "attendance"); if (count($ws) == 0) return "no room"; return join(", ", array_map(create_function(\'$x\', \'$rr = $x->getAssignedRoom(); return (is_null($rr) ? "no room" : "Room ".$rr->getTitle());\'), $ws));')))94 );95 }96 97 63 98 64 function getNavLink($title,$targ) { -
trunk/jpdd/config.inc.php
r560 r606 32 32 // if this is set to false, no e-mail will actually go out, though 33 33 // it will be written to the log. Defaults to true. 34 'actually_send_email' => true,34 'actually_send_email' => false, 35 35 36 36 // signup closed message: if not null, the signups will be closed, -
trunk/jpdd/sql/db.sql
r598 r606 925 925 926 926 ALTER TABLE attendance_requirements ADD CONSTRAINT attendence_requirements_category_event_unique UNIQUE (category_id,event_id); 927 928 -- remember whether each broadcast was sent out as a personalized 929 -- mail, (false means it was sent out from the site-wide e-mail address): 930 ALTER TABLE broadcast ADD COLUMN personal boolean; 931 UPDATE broadcast SET personal = true; 932 ALTER TABLE broadcast ALTER COLUMN personal SET NOT NULL; 933 934 -- we're allowing editing of broadcast templates now: 935 GRANT UPDATE ON broadcast TO "www-data";
Note: See TracChangeset
for help on using the changeset viewer.

