From e58bd8628a43f36782f71e7442a5bdef7741e33e Mon Sep 17 00:00:00 2001
From: Coding with Peter
Date: Mon, 18 Dec 2023 11:02:11 -0800
Subject: [PATCH] Initial commit
---
.htaccess | 7 +
act.php | 67 +
admin.php | 102 +
api2.php | 407 ++
bio.php | 82 +
cal.php | 65 +
chart.php | 101 +
css/chart.css | 187 +
css/intranet2021.css | 200 +
default_welcome_letter.json | 7 +
dir.php | 125 +
dir_api.20211021php | 822 +++
dir_api.php | 1765 +++++
dir_api20211102.php | 1235 ++++
ed_act.php | 78 +
flex.php | 81 +
graf/X_simple_2.png | Bin 0 -> 637 bytes
graf/bird_logo.png | Bin 0 -> 21803 bytes
graf/flag_1_red.png | Bin 0 -> 217 bytes
graf/pic_1.png | Bin 0 -> 542 bytes
graf/pic_1_add.png | Bin 0 -> 571 bytes
graf/play_video.png | Bin 0 -> 607 bytes
graf/profile_card.png | Bin 0 -> 544 bytes
graf/profile_close_2.png | Bin 0 -> 660 bytes
graf/smile_happy_1.png | Bin 0 -> 674 bytes
graf/smile_meh.png | Bin 0 -> 657 bytes
graf/smile_sad_1.png | Bin 0 -> 761 bytes
graf/textlogo_120.gif | Bin 0 -> 9725 bytes
graf/time_1.png | Bin 0 -> 658 bytes
graf/time_2.png | Bin 0 -> 733 bytes
graf/video_2.png | Bin 0 -> 514 bytes
graf/zm.png | Bin 0 -> 863 bytes
graf/zoom.png | Bin 0 -> 1764 bytes
index.php | 99 +
index20211021.php | 94 +
js/dir_app.js | 2296 +++++++
js/dir_app20211021.js | 767 +++
js/dir_app202111022.js | 878 +++
js/dir_app20220118.js | 1477 +++++
js/intranet_libs.js | 831 +++
js/intranet_libs_bottom.js | 6 +
js/vue27max.js | 11909 ++++++++++++++++++++++++++++++++++
list.php | 78 +
nav.php | 20 +
old/bio.php | 82 +
old/dir.php | 125 +
old/dir_api.20211021php | 822 +++
old/dir_api20211102.php | 1235 ++++
old/index20211021.php | 94 +
old/list.php | 78 +
old/test.php | 295 +
old/test2.php | 321 +
old/test_sched.php | 192 +
old/welcome.php | 94 +
overview.php | 82 +
report.php | 73 +
semester.php | 32 +
sessions.php | 74 +
settings.php | 81 +
static.php | 165 +
survey.php | 76 +
test.php | 295 +
test2.php | 321 +
test_sched.php | 192 +
underscore.php | 1120 ++++
welcome.php | 94 +
66 files changed, 29729 insertions(+)
create mode 100644 .htaccess
create mode 100644 act.php
create mode 100644 admin.php
create mode 100644 api2.php
create mode 100644 bio.php
create mode 100644 cal.php
create mode 100644 chart.php
create mode 100644 css/chart.css
create mode 100644 css/intranet2021.css
create mode 100644 default_welcome_letter.json
create mode 100644 dir.php
create mode 100644 dir_api.20211021php
create mode 100644 dir_api.php
create mode 100644 dir_api20211102.php
create mode 100644 ed_act.php
create mode 100644 flex.php
create mode 100644 graf/X_simple_2.png
create mode 100644 graf/bird_logo.png
create mode 100644 graf/flag_1_red.png
create mode 100644 graf/pic_1.png
create mode 100644 graf/pic_1_add.png
create mode 100644 graf/play_video.png
create mode 100644 graf/profile_card.png
create mode 100644 graf/profile_close_2.png
create mode 100644 graf/smile_happy_1.png
create mode 100644 graf/smile_meh.png
create mode 100644 graf/smile_sad_1.png
create mode 100644 graf/textlogo_120.gif
create mode 100644 graf/time_1.png
create mode 100644 graf/time_2.png
create mode 100644 graf/video_2.png
create mode 100644 graf/zm.png
create mode 100644 graf/zoom.png
create mode 100644 index.php
create mode 100644 index20211021.php
create mode 100644 js/dir_app.js
create mode 100644 js/dir_app20211021.js
create mode 100644 js/dir_app202111022.js
create mode 100644 js/dir_app20220118.js
create mode 100644 js/intranet_libs.js
create mode 100644 js/intranet_libs_bottom.js
create mode 100644 js/vue27max.js
create mode 100644 list.php
create mode 100644 nav.php
create mode 100644 old/bio.php
create mode 100644 old/dir.php
create mode 100644 old/dir_api.20211021php
create mode 100644 old/dir_api20211102.php
create mode 100644 old/index20211021.php
create mode 100644 old/list.php
create mode 100644 old/test.php
create mode 100644 old/test2.php
create mode 100644 old/test_sched.php
create mode 100644 old/welcome.php
create mode 100644 overview.php
create mode 100644 report.php
create mode 100644 semester.php
create mode 100644 sessions.php
create mode 100644 settings.php
create mode 100644 static.php
create mode 100644 survey.php
create mode 100644 test.php
create mode 100644 test2.php
create mode 100644 test_sched.php
create mode 100644 underscore.php
create mode 100644 welcome.php
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 0000000..ff0cd5a
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,7 @@
+LimitRequestBody 20971520
+
+RewriteEngine On
+RewriteEngine on
+RewriteRule ^calendar([0-9]+).ics$ calendar4.php?u=$1 [QSA]
+
+RewriteRule ^api/(.*)$ api2.php?query=$1 [L,QSA]
\ No newline at end of file
diff --git a/act.php b/act.php
new file mode 100644
index 0000000..fd99cd3
--- /dev/null
+++ b/act.php
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/admin.php b/admin.php
new file mode 100644
index 0000000..b4d7526
--- /dev/null
+++ b/admin.php
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public
+
+
+
Admin
+
+
+
Unused
+
+
+
+
+
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/api2.php b/api2.php
new file mode 100644
index 0000000..eb7b669
--- /dev/null
+++ b/api2.php
@@ -0,0 +1,407 @@
+connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+mysqli_set_charset($c, 'utf8');
+
+$server = $_SERVER['SERVER_NAME'];
+$DEBUG = 0;
+function p($s) { echo "{$s}
\n"; }
+function p2($val){ echo ''; print_r($val); echo "
\n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
- ')); }
+function okh($str) { global $c; return mysqli_real_escape_string($c, $str); }
+function sanitizeAndValidate($s) { return okh($s); }
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function single_row_select($qry, $j=1) {
+ global $c;
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (!$r) { return $r; }
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+function single_row_insert($qry) { global $c;
+ $r = mysqli_query($c, $qry);
+ return mysqli_insert_id($c); }
+
+function single_row_update($qry, $j=1) { global $c;
+ $r = mysqli_query($c, $qry);
+ return 1; }
+
+function multi_row_select($qry, $j=1) { global $c; $rows = array();
+ $result = mysqli_query($c, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+function multi_row_1d($qry) { global $c;
+ $savedQuery = mysqli_query($c, $qry);
+ while($savedResult = mysqli_fetch_array($savedQuery)) {
+ $savedArray[] = $savedResult[0]; }
+ return $savedArray; }
+
+
+// _____ _____ _ _ _____ _ ______ _ ____ _ _
+// / ____|_ _| \ | |/ ____| | | ____| (_) / __ \| \ | |
+// | (___ | | | \| | | __| | | |__ ___ _ __ _ _ __ | | | | \| |
+// \___ \ | | | . ` | | |_ | | | __| / __| |/ _` | '_ \ | | | | . ` |
+// ____) |_| |_| |\ | |__| | |____| |____ \__ \ | (_| | | | | | |__| | |\ |
+// |_____/|_____|_| \_|\_____|______|______| |___/_|\__, |_| |_| \____/|_| \_|
+// __/ |
+// |___/
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+
+
+if ( $server == 'intranet1.gavilan.edu' ) { // The SSO check should have happened on the actual page. If it gets
+// // stuck on an api call the app will break.
+ if ( session_id() == '' ) { // session_status() == PHP_SESSION_ACTIVE // newer php uses this
+ require 'mAuth.php';
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = $attributes['http://wso2.org/claims/emailaddress'][0];
+ ?>
+
+ 'SELECT * FROM users WHERE id = :id',
+ '/users' => 'SELECT * FROM users',
+ '/products' => 'SELECT * FROM products',
+ '/sessions' => 'SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag GROUP BY c.id ORDER BY c.track, c.starttime;',
+ '/ses/{day}' => 'SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime LIKE \'%:day%\' GROUP BY c.id ORDER BY c.track, c.starttime;',
+ '/settings' => 'SELECT * FROM conf_uinforecord;'
+];
+
+$functions = [
+ '/app' => 'appdata',
+ '/start' => 'startup',
+ '/update/activity' => 'set_sessioninfo',
+];
+
+
+if (1) { //// ($_SERVER['REQUEST_METHOD'] === 'GET') {
+
+ if (isset($_REQUEST['query'])) {
+ $requestUrl = '/' . $_REQUEST['query']; /// $_SERVER['REQUEST_URI'];
+
+ // Check if a matching URL template exists
+ // Execute corresponding SQL query based on the request URL
+ foreach ($queries as $urlTemplate => $sqlTemplate) {
+ $pattern = preg_replace('/{([\-_\w]+)}/', '([\-_\w]+)', $urlTemplate);
+
+ if (preg_match("#^$pattern$#", $requestUrl, $matches)) {
+ // Extract parameter values
+ $params = [];
+ preg_match_all('/{([\-_\w]+)}/', $urlTemplate, $paramNames);
+ foreach ($paramNames[1] as $index => $paramName) {
+ $paramValue = $matches[$index + 1];
+ //echo ". . index:" . $index . ". . paramName:" . $paramName . ". . paramValue:" . $paramValue . "
";
+
+ // Sanitize and validate the parameter value
+ // Store the sanitized value in the $params array
+ $params[':' . $paramName] = sanitizeAndValidate($paramValue);
+ }
+
+ // Prepare the SQL query with the parameter values
+ $sql = strtr($sqlTemplate, $params);
+ // Execute the SQL query and retrieve data
+ //echo "query:" . $sql . "
";
+
+ $result = mysqli_query($c, $sql);
+ $rows = array();
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ $jsonString = json_encode($rows);
+ $sizeInBytes = strlen($jsonString);
+
+ echo json_encode(array(
+ "size" => $sizeInBytes,
+ "result" => "success",
+ //"query" => $sql,
+ "data" => $rows,
+ "err" => mysqli_error($c)
+ ));
+
+
+ }
+ }
+
+ foreach ($functions as $urlTemplate => $functionCall) {
+ $pattern = preg_replace('/{([\-_\w]+)}/', '([\-_\w]+)', $urlTemplate);
+
+ if (preg_match("#^$pattern$#", $requestUrl, $matches)) {
+ // Extract parameter values
+ $params = [];
+ preg_match_all('/{([\-_\w]+)}/', $urlTemplate, $paramNames);
+ foreach ($paramNames[1] as $index => $paramName) {
+ $paramValue = $matches[$index + 1];
+ // Sanitize and validate the parameter value
+ // Store the sanitized value in the $params array
+ $params[':' . $paramName] = sanitizeAndValidate($paramValue);
+ }
+
+ $rows = call_user_func($functionCall);
+ $jsonString = json_encode($rows);
+ $sizeInBytes = strlen($jsonString);
+
+ echo json_encode(array(
+ "size" => $sizeInBytes,
+ "result" => "success",
+ "data" => $rows,
+ "err" => mysqli_error($c)
+ ));
+
+
+ }
+ }
+ }
+} /*elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // Handle updates / inserts
+ $tableName = $_GET['table'];
+ $postData = $_POST;
+ $recordId = isset($postData['id']) ? $postData['id'] : null;
+
+ $date = date('Y-m-d H:i:s');
+ $columns = explode(',', $_REQUEST['cols']);
+ $values = explode(',', $_REQUEST['vals']);
+ $values = array_map('unescape_commas', $values);
+ $columnValuePairs = array_combine($columns, $values);
+
+ // Build the update/insert query
+ if ($recordId) {
+ $query = "UPDATE $tableName SET ";
+ $query .= join(", ", array_map(function ($column, $value) {
+ return okh($column) . " = '" . okh($value) . "'";
+ }, array_keys($columnValuePairs), $columnValuePairs));
+ $query .= ", changed = '$date'";
+ $query .= " WHERE id = $recordId";
+ } else {
+ $query = "INSERT INTO $tableName (";
+ $query .= join(", ", array_map('okh', $columns));
+ $query .= ", changed) VALUES ('";
+ $query .= join("', '", array_map('okh', $values));
+ $query .= "', '$date')";
+ }
+
+ // Execute the query
+ echo "Query: " . $query . "
";
+ exit();
+ $r = mysqli_query($c, $query);
+ echo json_encode(array(
+ "rawvalstr" => $_REQUEST['vals'],
+ "result" => "success",
+ "action" => ($recordId ? "updated" : "inserted"),
+ "logaction" => $logaction,
+ "query" => $query,
+ "err" => mysqli_error($c)
+ ));
+ exit();
+
+
+} */
+
+function startup() {
+ global $USER;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0);
+ $sss = multi_row_select('SELECT * FROM conf_sessiontypes ORDER BY id',0);
+ $aya = multi_row_select('SELECT * FROM conf_academicyears ORDER BY id',0);
+ $set = multi_row_select('SELECT id,label,value FROM conf_uinforecord',0);
+ $ppp = multi_row_select("SELECT * FROM `conf_sessions` WHERE `type` = '20' OR `type` = '21' ORDER BY starttime",0);
+
+ $SET = array();
+ foreach ($set as $setting) {
+ $SET[$setting['label']] = $setting['value'];
+ }
+ echo json_encode( array( 'user'=>$USER, 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc,
+ 'sessiontypes'=>$sss, 'settings'=>$SET, 'ay'=>$aya, 'parents'=>$ppp ) );
+ exit();
+}
+
+function appdata() {
+ global $USER;
+
+ // mysessions
+ $m = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER['conf_id']}' OR sup.user='{$USER['conf_id']}') GROUP BY c.id ORDER BY c.track, c.starttime;",0);
+
+ // sessions
+ $s = multi_row_select('SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag GROUP BY c.id ORDER BY c.track, c.starttime;',0);
+
+ // hosts
+ $hh = multi_row_1d("select session FROM conf_hosts WHERE host='{$USER['conf_id']}';");
+
+ // conferences
+ $c = multi_row_select('SELECT * FROM conf_conferences;',0);
+
+ $y = multi_row_select('SELECT * FROM conf_academicyears',0);
+
+ // options
+ $o = multi_row_select('SELECT * FROM conf_uinforecord',0);
+
+ echo json_encode(array(
+ "mysessions" => $m,
+ "sessions" => $s,
+ "host" => $hh,
+ "user" => $USER,
+ "conference" => $c,
+ "ay" => $y,
+ "options" => $o,
+ ));
+ exit();
+}
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function reducer ($memo, $a) { return $memo . "`" . ok($a[0]) . "` = '" . okh($a[1]) . "', "; }
+
+function set_sessioninfo() {
+ global $c, $USER;
+ $table = 'conf_sessions';
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = array_map('unescape_commas', $vals);
+ $cv = array_map(null,$cols,$vals);
+ $q = array_reduce($cv, 'reducer', "UPDATE `{$table}` SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated", "query"=>$q,"err"=>mysqli_error($c2)));
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit();
+}
+
+
+
+
+
+
+
+
+
+
+// Return an appropriate response indicating success or failure
+// ...
+
+
+
+
+// Close the database connection
+// ...
+
+
+
+// later... permission check
+
+ // Check if the user has permission to update the record
+ /*if (isset($_POST['id'])) { // Editing another person's data
+ if (!check_permission($USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode(array("result" => "fail", "err" => "You don't have permission to edit this"));
+ exit();
+ } else {
+ $logaction = log_it("Updating $tableName record with id {$_POST['id']}");
+ $recordId = $_POST['id'];
+ }
+ } else {
+ $logaction = log_it("Updating $tableName record");
+ $recordId = $USER->id;
+ }*/
+
+
diff --git a/bio.php b/bio.php
new file mode 100644
index 0000000..63faf54
--- /dev/null
+++ b/bio.php
@@ -0,0 +1,82 @@
+
+
+
+
+ Personnel Directory > Staff Bio Page";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+ Alert message
+
+
+
+
+
diff --git a/cal.php b/cal.php
new file mode 100644
index 0000000..8a47e48
--- /dev/null
+++ b/cal.php
@@ -0,0 +1,65 @@
+
+
+
+
+ Personnel Directory > Activity Signups";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Calendar View
+
+
Sign up for events here
+
+
+
+
+
+
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/chart.php b/chart.php
new file mode 100644
index 0000000..30d4244
--- /dev/null
+++ b/chart.php
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/css/chart.css b/css/chart.css
new file mode 100644
index 0000000..2dff293
--- /dev/null
+++ b/css/chart.css
@@ -0,0 +1,187 @@
+/*************************
+ * GRID SCHEDULE LAYOUT
+ *************************/
+@media screen and (min-width:700px) {
+ .schedule {
+ display: grid;
+ column-gap: 0.5em;
+ row-gap:0.7em;
+ grid-template-rows:
+ [tracks] auto
+ /*[time-0800] 0.005fr
+ [time-0805] 0.005fr
+ [time-0810] 0.005fr
+ [time-0815] 0.005fr
+ [time-0820] 0.005fr
+ [time-0825] 0.005fr
+ [time-0830] 0.005fr
+ [time-0835] 0.005fr
+ [time-0840] 0.005fr
+ [time-0845] 0.005fr
+ [time-0850] 0.005fr
+ [time-0855] 0.005fr */
+ [time-0900] 0.005fr
+ [time-0905] 0.005fr
+ [time-0910] 0.005fr
+ [time-0915] 0.005fr
+ [time-0920] 0.005fr
+ [time-0925] 0.005fr
+ [time-0930] 0.005fr
+ [time-0935] 0.005fr
+ [time-0940] 0.005fr
+ [time-0945] 0.005fr
+ [time-0950] 0.005fr
+ [time-0955] 0.005fr
+ [time-1000] 0.005fr
+ [time-1005] 0.005fr
+ [time-1010] 0.005fr
+ [time-1015] 0.005fr
+ [time-1020] 0.005fr
+ [time-1025] 0.005fr
+ [time-1030] 0.005fr
+ [time-1035] 0.005fr
+ [time-1040] 0.005fr
+ [time-1045] 0.005fr
+ [time-1050] 0.005fr
+ [time-1055] 0.005fr
+ [time-1100] 0.005fr
+ [time-1105] 0.005fr
+ [time-1110] 0.005fr
+ [time-1115] 0.005fr
+ [time-1120] 0.005fr
+ [time-1125] 0.005fr
+ [time-1130] 0.005fr
+ [time-1135] 0.005fr
+ [time-1140] 0.005fr
+ [time-1145] 0.005fr
+ [time-1150] 0.005fr
+ [time-1155] 0.005fr
+ [time-1200] 0.005fr
+ [time-1205] 0.005fr
+ [time-1210] 0.005fr
+ [time-1215] 0.005fr
+ [time-1220] 0.005fr
+ [time-1225] 0.005fr
+ [time-1230] 0.005fr
+ [time-1235] 0.005fr
+ [time-1240] 0.005fr
+ [time-1245] 0.005fr
+ [time-1250] 0.005fr
+ [time-1255] 0.005fr
+ [time-1300] 0.005fr
+ [time-1305] 0.005fr
+ [time-1310] 0.005fr
+ [time-1315] 0.005fr
+ [time-1320] 0.005fr
+ [time-1325] 0.005fr
+ [time-1330] 0.005fr
+ [time-1335] 0.005fr
+ [time-1340] 0.005fr
+ [time-1345] 0.005fr
+ [time-1350] 0.005fr
+ [time-1355] 0.005fr
+ [time-1400] 0.005fr
+ [time-1405] 0.005fr
+ [time-1410] 0.005fr
+ [time-1415] 0.005fr
+ [time-1420] 0.005fr
+ [time-1425] 0.005fr
+ [time-1430] 0.005fr
+ [time-1435] 0.005fr
+ [time-1440] 0.005fr
+ [time-1445] 0.005fr
+ [time-1450] 0.005fr
+ [time-1455] 0.005fr
+ [time-1500] 0.005fr
+ [time-1505] 0.005fr
+ [time-1510] 0.005fr
+ [time-1515] 0.005fr
+ [time-1520] 0.005fr
+ [time-1525] 0.005fr
+ [time-1530] 0.005fr
+ [time-1535] 0.005fr
+ [time-1540] 0.005fr
+ [time-1545] 0.005fr
+ [time-1550] 0.005fr
+ [time-1555] 0.005fr
+ [time-1600] 0.005fr
+ [time-1605] 0.005fr
+ [time-1610] 0.005fr
+ [time-1615] 0.005fr
+ [time-1620] 0.005fr
+ [time-1625] 0.005fr
+ [time-1630] 0.005fr
+ [time-1635] 0.005fr
+ [time-1640] 0.005fr
+ [time-1645] 0.005fr
+ [time-1650] 0.005fr
+ [time-1655] 0.005fr
+ [time-1700] 0.005fr
+ [time-1705] 0.005fr
+ [time-1710] 0.005fr
+ [time-1715] 0.005fr
+ [time-1720] 0.005fr
+ [time-1725] 0.005fr
+ [time-1730] 0.005fr
+ [time-1735] 0.005fr
+ [time-1740] 0.005fr
+ [time-1745] 0.005fr
+ [time-1750] 0.005fr
+ [time-1755] 0.005fr;
+ /* Note 1:
+ Use 24hr time for gridline names for simplicity
+
+ Note 2: Use "auto" instead of "1fr" for a more compact schedule where height of a slot is not proportional to the session length.
+ Implementing a "compact" shortcode attribute might make sense for this!
+ Try 0.5fr for more compact equal rows. I don't quite understand how that works :)
+ */
+
+ grid-template-columns:
+ [times] 4em
+ [track-1-start] 1fr
+ [track-1-end track-2-start] 1fr
+ [track-2-end track-3-start] 1fr
+ [track-3-end track-4-start] 1fr
+ [track-4-end track-5-start] 1fr
+ [track-5-end track-6-start] 1fr
+ [track-6-end];
+ }
+}
+.time-slot { grid-column: times; }
+.track-slot { display: none; }
+ /* hidden on small screens and browsers without grid support */
+
+@supports(display:grid ) { @media screen and(min-width:700px) {
+ .track-slot { display: block; padding: 10px 5px 5px; position: sticky; top: 0; z-index: 1000; background-color: rgba(255,255,255,.9); } } }
+/* Small-screen & fallback styles */
+@supports(display:grid ) { @media screen and(min-width: 700px) { .session { margin: 0; } } }
+
+/* VISUAL STYLES * Design-y stuff ot particularly important to the demo */
+
+body { padding: 50px; /*max-width: 1100px;*/ margin: 0 auto; line-height: 1.5; }
+.session { padding: .5em; border-radius: 2px; font-size: 14px; }
+
+ /* box-shadow: rgba(255,255,255,.6) 1px 1px 0, rgba(0,0,0,.3) 4px 4px 0; */
+
+.session-title, .session-time, .session-track, .session-presenter { display: block; }
+.session-title, .time-slot { margin: 0; font-size: 1em; }
+.session-title a { color: #fff; text-decoration-style: dotted; &:hover { font-style: italic; }
+ &:focus { outline: 2px dotted rgba(255,255,255,.8); }
+ }
+.track-slot, .time-slot { font-weight: bold; font-size:.75em; }
+.track-123 { background-color: #ffa8ca; color: #000; }
+.track-0 { background-color: #ffa8ca; color: #000; }
+.track-1 { background-color: #f3ba59; color: #fff; }
+.track-2 { background-color: #e96b8f; color: #fff; }
+.track-3 { background-color: #ff9ffc; color: #fff; }
+.track-4 { background-color: #b4d3c0; color: #fff; }
+.track-5 { background-color: #dad9ff; color: #fff; }
+.track-6 { background-color: #9ccae1; color: #fff; }
+.track-all { display: flex; justify-content: center; align-items: center; background: #ccc; color: #000; box-shadow: none; }
+.text { max-width: 750px; font-size: 18px; margin: 0 auto 50px; }
+.session h3, .session { color: #272727; }
+.meta { color: #555; font-style: italic; }
+.meta a { color: #555; }
+.chart_timebox { color:lightgrey; border:1px solid lightgrey; padding:5px; }
+.chart_time { color:#5c5b5b; font-size: 80%; }
+hr { margin: 40px 0; }
\ No newline at end of file
diff --git a/css/intranet2021.css b/css/intranet2021.css
new file mode 100644
index 0000000..f557be0
--- /dev/null
+++ b/css/intranet2021.css
@@ -0,0 +1,200 @@
+
+
+
+/* GAV INTRANET CUSTOMIZATIONS BELOW....
+
+ ph 10 / 2021
+
+
+ */
+
+
+
+/*!
+Pure v2.0.6
+https://github.com/pure-css/pure/blob/master/LICENSE
+*/
+html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}html{font-family:sans-serif}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-line-pack:start;align-content:flex-start}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){table .pure-g{display:block}}.opera-only :-o-prefocus,.pure-g{word-spacing:-0.43em}.pure-u{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class*=pure-u]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}.pure-button{display:inline-block;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-0.43em}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:rgba(0,0,0,.8);border:none transparent;background-color:#e6e6e6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;opacity:.4;cursor:not-allowed;-webkit-box-shadow:none;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{margin:0;border-radius:0;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=color]:focus,.pure-form input[type=date]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=email]:focus,.pure-form input[type=month]:focus,.pure-form input[type=number]:focus,.pure-form input[type=password]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=text]:focus,.pure-form input[type=time]:focus,.pure-form input[type=url]:focus,.pure-form input[type=week]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129fea}.pure-form input:not([type]):focus{outline:0;border-color:#129fea}.pure-form input[type=checkbox]:focus,.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=color][disabled],.pure-form input[type=date][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=email][disabled],.pure-form input[type=month][disabled],.pure-form input[type=number][disabled],.pure-form input[type=password][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=text][disabled],.pure-form input[type=time][disabled],.pure-form input[type=url][disabled],.pure-form input[type=week][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=color],.pure-form-stacked input[type=date],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=email],.pure-form-stacked input[type=file],.pure-form-stacked input[type=month],.pure-form-stacked input[type=number],.pure-form-stacked input[type=password],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=text],.pure-form-stacked input[type=time],.pure-form-stacked input[type=url],.pure-form-stacked input[type=week],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline{display:inline-block;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-3-4{width:75%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=color],.pure-group input[type=date],.pure-group input[type=datetime-local],.pure-group input[type=datetime],.pure-group input[type=email],.pure-group input[type=month],.pure-group input[type=number],.pure-group input[type=password],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=text],.pure-group input[type=time],.pure-group input[type=url],.pure-group input[type=week]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0 0}.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;padding:.5em 0}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent;cursor:default}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected>.pure-menu-link,.pure-menu-selected>.pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0}
+
+/*! Pure v2.0.6 */
+@media screen and (min-width:35.5em){.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-1-12,.pure-u-sm-1-2,.pure-u-sm-1-24,.pure-u-sm-1-3,.pure-u-sm-1-4,.pure-u-sm-1-5,.pure-u-sm-1-6,.pure-u-sm-1-8,.pure-u-sm-10-24,.pure-u-sm-11-12,.pure-u-sm-11-24,.pure-u-sm-12-24,.pure-u-sm-13-24,.pure-u-sm-14-24,.pure-u-sm-15-24,.pure-u-sm-16-24,.pure-u-sm-17-24,.pure-u-sm-18-24,.pure-u-sm-19-24,.pure-u-sm-2-24,.pure-u-sm-2-3,.pure-u-sm-2-5,.pure-u-sm-20-24,.pure-u-sm-21-24,.pure-u-sm-22-24,.pure-u-sm-23-24,.pure-u-sm-24-24,.pure-u-sm-3-24,.pure-u-sm-3-4,.pure-u-sm-3-5,.pure-u-sm-3-8,.pure-u-sm-4-24,.pure-u-sm-4-5,.pure-u-sm-5-12,.pure-u-sm-5-24,.pure-u-sm-5-5,.pure-u-sm-5-6,.pure-u-sm-5-8,.pure-u-sm-6-24,.pure-u-sm-7-12,.pure-u-sm-7-24,.pure-u-sm-7-8,.pure-u-sm-8-24,.pure-u-sm-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-sm-1-24{width:4.1667%}.pure-u-sm-1-12,.pure-u-sm-2-24{width:8.3333%}.pure-u-sm-1-8,.pure-u-sm-3-24{width:12.5%}.pure-u-sm-1-6,.pure-u-sm-4-24{width:16.6667%}.pure-u-sm-1-5{width:20%}.pure-u-sm-5-24{width:20.8333%}.pure-u-sm-1-4,.pure-u-sm-6-24{width:25%}.pure-u-sm-7-24{width:29.1667%}.pure-u-sm-1-3,.pure-u-sm-8-24{width:33.3333%}.pure-u-sm-3-8,.pure-u-sm-9-24{width:37.5%}.pure-u-sm-2-5{width:40%}.pure-u-sm-10-24,.pure-u-sm-5-12{width:41.6667%}.pure-u-sm-11-24{width:45.8333%}.pure-u-sm-1-2,.pure-u-sm-12-24{width:50%}.pure-u-sm-13-24{width:54.1667%}.pure-u-sm-14-24,.pure-u-sm-7-12{width:58.3333%}.pure-u-sm-3-5{width:60%}.pure-u-sm-15-24,.pure-u-sm-5-8{width:62.5%}.pure-u-sm-16-24,.pure-u-sm-2-3{width:66.6667%}.pure-u-sm-17-24{width:70.8333%}.pure-u-sm-18-24,.pure-u-sm-3-4{width:75%}.pure-u-sm-19-24{width:79.1667%}.pure-u-sm-4-5{width:80%}.pure-u-sm-20-24,.pure-u-sm-5-6{width:83.3333%}.pure-u-sm-21-24,.pure-u-sm-7-8{width:87.5%}.pure-u-sm-11-12,.pure-u-sm-22-24{width:91.6667%}.pure-u-sm-23-24{width:95.8333%}.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-24-24,.pure-u-sm-5-5{width:100%}}@media screen and (min-width:48em){.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-1-12,.pure-u-md-1-2,.pure-u-md-1-24,.pure-u-md-1-3,.pure-u-md-1-4,.pure-u-md-1-5,.pure-u-md-1-6,.pure-u-md-1-8,.pure-u-md-10-24,.pure-u-md-11-12,.pure-u-md-11-24,.pure-u-md-12-24,.pure-u-md-13-24,.pure-u-md-14-24,.pure-u-md-15-24,.pure-u-md-16-24,.pure-u-md-17-24,.pure-u-md-18-24,.pure-u-md-19-24,.pure-u-md-2-24,.pure-u-md-2-3,.pure-u-md-2-5,.pure-u-md-20-24,.pure-u-md-21-24,.pure-u-md-22-24,.pure-u-md-23-24,.pure-u-md-24-24,.pure-u-md-3-24,.pure-u-md-3-4,.pure-u-md-3-5,.pure-u-md-3-8,.pure-u-md-4-24,.pure-u-md-4-5,.pure-u-md-5-12,.pure-u-md-5-24,.pure-u-md-5-5,.pure-u-md-5-6,.pure-u-md-5-8,.pure-u-md-6-24,.pure-u-md-7-12,.pure-u-md-7-24,.pure-u-md-7-8,.pure-u-md-8-24,.pure-u-md-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-md-1-24{width:4.1667%}.pure-u-md-1-12,.pure-u-md-2-24{width:8.3333%}.pure-u-md-1-8,.pure-u-md-3-24{width:12.5%}.pure-u-md-1-6,.pure-u-md-4-24{width:16.6667%}.pure-u-md-1-5{width:20%}.pure-u-md-5-24{width:20.8333%}.pure-u-md-1-4,.pure-u-md-6-24{width:25%}.pure-u-md-7-24{width:29.1667%}.pure-u-md-1-3,.pure-u-md-8-24{width:33.3333%}.pure-u-md-3-8,.pure-u-md-9-24{width:37.5%}.pure-u-md-2-5{width:40%}.pure-u-md-10-24,.pure-u-md-5-12{width:41.6667%}.pure-u-md-11-24{width:45.8333%}.pure-u-md-1-2,.pure-u-md-12-24{width:50%}.pure-u-md-13-24{width:54.1667%}.pure-u-md-14-24,.pure-u-md-7-12{width:58.3333%}.pure-u-md-3-5{width:60%}.pure-u-md-15-24,.pure-u-md-5-8{width:62.5%}.pure-u-md-16-24,.pure-u-md-2-3{width:66.6667%}.pure-u-md-17-24{width:70.8333%}.pure-u-md-18-24,.pure-u-md-3-4{width:75%}.pure-u-md-19-24{width:79.1667%}.pure-u-md-4-5{width:80%}.pure-u-md-20-24,.pure-u-md-5-6{width:83.3333%}.pure-u-md-21-24,.pure-u-md-7-8{width:87.5%}.pure-u-md-11-12,.pure-u-md-22-24{width:91.6667%}.pure-u-md-23-24{width:95.8333%}.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-24-24,.pure-u-md-5-5{width:100%}}@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-12,.pure-u-lg-1-2,.pure-u-lg-1-24,.pure-u-lg-1-3,.pure-u-lg-1-4,.pure-u-lg-1-5,.pure-u-lg-1-6,.pure-u-lg-1-8,.pure-u-lg-10-24,.pure-u-lg-11-12,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-2-24,.pure-u-lg-2-3,.pure-u-lg-2-5,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24,.pure-u-lg-3-24,.pure-u-lg-3-4,.pure-u-lg-3-5,.pure-u-lg-3-8,.pure-u-lg-4-24,.pure-u-lg-4-5,.pure-u-lg-5-12,.pure-u-lg-5-24,.pure-u-lg-5-5,.pure-u-lg-5-6,.pure-u-lg-5-8,.pure-u-lg-6-24,.pure-u-lg-7-12,.pure-u-lg-7-24,.pure-u-lg-7-8,.pure-u-lg-8-24,.pure-u-lg-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%}.pure-u-lg-1-5{width:20%}.pure-u-lg-5-24{width:20.8333%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%}.pure-u-lg-7-24{width:29.1667%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%}.pure-u-lg-2-5{width:40%}.pure-u-lg-10-24,.pure-u-lg-5-12{width:41.6667%}.pure-u-lg-11-24{width:45.8333%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%}.pure-u-lg-13-24{width:54.1667%}.pure-u-lg-14-24,.pure-u-lg-7-12{width:58.3333%}.pure-u-lg-3-5{width:60%}.pure-u-lg-15-24,.pure-u-lg-5-8{width:62.5%}.pure-u-lg-16-24,.pure-u-lg-2-3{width:66.6667%}.pure-u-lg-17-24{width:70.8333%}.pure-u-lg-18-24,.pure-u-lg-3-4{width:75%}.pure-u-lg-19-24{width:79.1667%}.pure-u-lg-4-5{width:80%}.pure-u-lg-20-24,.pure-u-lg-5-6{width:83.3333%}.pure-u-lg-21-24,.pure-u-lg-7-8{width:87.5%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%}.pure-u-lg-23-24{width:95.8333%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-24-24,.pure-u-lg-5-5{width:100%}}@media screen and (min-width:80em){.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-1-12,.pure-u-xl-1-2,.pure-u-xl-1-24,.pure-u-xl-1-3,.pure-u-xl-1-4,.pure-u-xl-1-5,.pure-u-xl-1-6,.pure-u-xl-1-8,.pure-u-xl-10-24,.pure-u-xl-11-12,.pure-u-xl-11-24,.pure-u-xl-12-24,.pure-u-xl-13-24,.pure-u-xl-14-24,.pure-u-xl-15-24,.pure-u-xl-16-24,.pure-u-xl-17-24,.pure-u-xl-18-24,.pure-u-xl-19-24,.pure-u-xl-2-24,.pure-u-xl-2-3,.pure-u-xl-2-5,.pure-u-xl-20-24,.pure-u-xl-21-24,.pure-u-xl-22-24,.pure-u-xl-23-24,.pure-u-xl-24-24,.pure-u-xl-3-24,.pure-u-xl-3-4,.pure-u-xl-3-5,.pure-u-xl-3-8,.pure-u-xl-4-24,.pure-u-xl-4-5,.pure-u-xl-5-12,.pure-u-xl-5-24,.pure-u-xl-5-5,.pure-u-xl-5-6,.pure-u-xl-5-8,.pure-u-xl-6-24,.pure-u-xl-7-12,.pure-u-xl-7-24,.pure-u-xl-7-8,.pure-u-xl-8-24,.pure-u-xl-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xl-1-24{width:4.1667%}.pure-u-xl-1-12,.pure-u-xl-2-24{width:8.3333%}.pure-u-xl-1-8,.pure-u-xl-3-24{width:12.5%}.pure-u-xl-1-6,.pure-u-xl-4-24{width:16.6667%}.pure-u-xl-1-5{width:20%}.pure-u-xl-5-24{width:20.8333%}.pure-u-xl-1-4,.pure-u-xl-6-24{width:25%}.pure-u-xl-7-24{width:29.1667%}.pure-u-xl-1-3,.pure-u-xl-8-24{width:33.3333%}.pure-u-xl-3-8,.pure-u-xl-9-24{width:37.5%}.pure-u-xl-2-5{width:40%}.pure-u-xl-10-24,.pure-u-xl-5-12{width:41.6667%}.pure-u-xl-11-24{width:45.8333%}.pure-u-xl-1-2,.pure-u-xl-12-24{width:50%}.pure-u-xl-13-24{width:54.1667%}.pure-u-xl-14-24,.pure-u-xl-7-12{width:58.3333%}.pure-u-xl-3-5{width:60%}.pure-u-xl-15-24,.pure-u-xl-5-8{width:62.5%}.pure-u-xl-16-24,.pure-u-xl-2-3{width:66.6667%}.pure-u-xl-17-24{width:70.8333%}.pure-u-xl-18-24,.pure-u-xl-3-4{width:75%}.pure-u-xl-19-24{width:79.1667%}.pure-u-xl-4-5{width:80%}.pure-u-xl-20-24,.pure-u-xl-5-6{width:83.3333%}.pure-u-xl-21-24,.pure-u-xl-7-8{width:87.5%}.pure-u-xl-11-12,.pure-u-xl-22-24{width:91.6667%}.pure-u-xl-23-24{width:95.8333%}.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-24-24,.pure-u-xl-5-5{width:100%}}
+
+.pell{border:1px solid hsla(0,0%,4%,.1)}.pell,.pell-content{box-sizing:border-box}.pell-content{height:300px;outline:0;overflow-y:auto;padding:10px}.pell-actionbar{background-color:#fff;border-bottom:1px solid hsla(0,0%,4%,.1)}.pell-button{background-color:transparent;border:none;cursor:pointer;height:30px;outline:0;width:30px;vertical-align:bottom}.pell-button-selected{background-color:#f0f0f0}
+
+/* DropZone */
+@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:2px solid rgba(0,0,0,.3);background:#fff;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-message .dz-button{background:none;color:inherit;border:none;padding:0;font:inherit;cursor:pointer;outline:inherit}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:#fff}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity 0.2s linear;-moz-transition:opacity 0.2s linear;-ms-transition:opacity 0.2s linear;-o-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,.8);background-color:rgba(255,255,255,.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,.4);padding:0 .4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05, 1.05);-moz-transform:scale(1.05, 1.05);-ms-transform:scale(1.05, 1.05);-o-transform:scale(1.05, 1.05);transform:scale(1.05, 1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all 0.2s linear;-moz-transition:all 0.2s linear;-ms-transition:all 0.2s linear;-o-transition:all 0.2s linear;transition:all 0.2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity 0.4s ease-in;-moz-transition:opacity 0.4s ease-in;-ms-transition:opacity 0.4s ease-in;-o-transition:opacity 0.4s ease-in;transition:opacity 0.4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;-ms-animation:pulse 6s ease infinite;-o-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,.9);-webkit-transform:scale(1);border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:linear-gradient(to bottom, #666, #444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;-ms-transition:width 300ms ease-in-out;-o-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity 0.3s ease;-moz-transition:opacity 0.3s ease;-ms-transition:opacity 0.3s ease;-o-transition:opacity 0.3s ease;transition:opacity 0.3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:linear-gradient(to bottom, #be2626, #a92222);padding:.5em 1.2em;color:#fff}.dropzone .dz-preview .dz-error-message:after{content:"";position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626}
+
+
+
+
+
+
+html {background: #ddd;}
+body { margin-top: 0em; }
+a {color: #0000ff;text-decoration: none;}
+a:hover {color: #ff0000;text-decoration: underline;}
+h1 {font-size: 182%;}
+h2 {font-size: 153.9%;}
+h3 {font-size: 123.1%;}
+.content { color: #000;background: #fff; border:1px solid black; border-radius: 0.5em; padding:1em; margin:1em; }
+.main-content { margin-top: -1.2em; padding-left:1.5em; }
+.headerimg { max-width:100%; margin: 2em auto 2em auto; display: block; }
+.staffpic { max-width:175px; height:auto; }
+.breadcrumb { font-size:85%; }
+.navigation { color: #3C7BCF;}
+.navigation ul { padding-inline-start: 0em; }
+.navigation li {list-style: none;margin-bottom: 0.5em;}
+.navigation li a {display: block;padding: 0.5em 0.5em;border-top: 1px solid #eee;border-left: 1px solid #eee;border-bottom: 1px solid #999;border-right: 1px solid #999;background-color: #E3E3E3;}
+.navigation li a:hover {background-color: #ffffff;}
+.footer {margin-top: 2.5em; margin-bottom:2.5em; text-align: center;font-size: 75%;}
+.footer a {text-decoration: none;color: #3C7BCF;}
+.spacer { display:none; }
+.report { margin-bottom:2em; }
+.day_title { margin: 0.5em 0 0.2em 0; font-weight:bold; font-size:110%; background:#ddd; padding:0.3em; }
+.exp_header { margin:0.3em 0em 0em 0em; }
+ a, .exp_header a:hover { color:#000; text-decoration:none; }
+.decorate { width:0.85em; display:inline-block; }
+.highlight { font-weight:bold; }
+
+h1.main_header {color: #A32638;margin-top: 0.9em;margin-bottom: 0.75em;padding-top: 0;text-align: left;
+ font-family: Verdana, Arial, Helvetica, sans-serif; font-size:140%;}
+div#gav_main_content li {margin-bottom: 1em;}
+.formpush { margin-left:11em; }
+.pure-form-aligned textarea { width: 90%; max-width: 33em; height: 10em; }
+.pure-form-aligned input[type=text] { width: 90%; max-width: 33em; }
+.pure-form-aligned select { width: 90%; max-width: 33em; }
+
+.form-control.pell { width:90%; max-width:33em; display:inline-block; }
+.pure-form-aligned .pure-control-group label { vertical-align: top; margin-top: 0.65em; }
+.pell { border: 1px solid #ccc; }
+.fake_pcg { margin-top:0px!important; display: inline-block; width: 100%; max-width: 33em; }
+
+.activitylist { margin-bottom:2em; }
+.activitylist a { text-decoration: underline; }
+.rhs_grey { display:inline-block; float:right; color:#aaa; font-size:0.8rem; }
+.controls { }
+.controls input[type=checkbox] { margin-left:1em; }
+.controls input[type=text] { border:1px solid grey; width:100%; }
+.controls h3 { font-size:100%; margin-bottom:6px; padding-top: 0.75em; padding-right: 1em; }
+.linky { font-weight:bold; color:blue; text-decoration:underline; }
+
+.itn_day {}
+.itn_item { background-color: #eeeeee42; margin: 0.2em 0 1em 0; padding: 0.75em 0 0.75em 0; }
+.itn_icon {}
+.itn_info {}
+.itn_title { display: block; margin-bottom:0.3em; }
+.itn_body { display: block; margin-bottom:0.3em; }
+.itn_foot { display: block; }
+.itn_controls {}
+.itn_now { color:#999; font-size:90%; font-weight:bold; padding: 0 0 1em 0; margin-top: -1em; }
+.actionicon { width: auto; height: 0.9rem; }
+
+
+.session-survey { margin-bottom:1.5em; }
+.question { display:block; margin-bottom:0.3em; }
+
+.even.pure-g { background-color: #ffdfff; }
+.even, .odd { min-height: 2.5em; padding: 2px; }
+.listing input, .listing select { width: 99%; }
+.listing input.double { width: 48%; }
+.listing input[type=checkbox] { width: initial; }
+.clicky { cursor:pointer; }
+.subtle { font-size:90%; line-height: 100%; color:grey; }
+.lighter { color:#676; }
+
+.list-editor input, .list-editor select { width:initial; margin-bottom:0.25em; }
+
+
+.pure-button-primary { }
+.btn_float { display: inline-block; }
+.btn_rhs { display: inline-block; float:right; }
+.btn_container { text-align: right; margin-top: -2em; margin-right: 7em; }
+.calendar td { width: 14%; vertical-align: top; height: 5.6rem; border: 1px solid #ffcdcd; padding:0.25em; }
+.calendar table { width: 100%; border-collapse: collapse; }
+.calendar thead { font-weight:bold; }
+.do_month { text-align: center; }
+.cal_evt { font-size: 80%; margin-top:0.4em; color:#333; }
+
+#alert { width:10em; max-width:50%; position:fixed; top:10px; left:50%; transform: translateX(-50%); padding:10px;
+ background-color: yellow; color: black; font-size: 16px; text-align:center; font-weight:bold; opacity:0.0; /* visibility:hidden; */ }
+.success { background-color: pink; padding: 0.5em; margin: 0.5em; /*visibility:hidden;*/ opacity:0.0; }
+
+
+.button-inlist { font-size: 90%; color: white; border-radius: 4px;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); background: rgb(66, 184, 221);
+ padding: .25em 0.5em; line-height:200%; }
+.button-inlist-action { font-size: 90%; color: white; border-radius: 4px;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); background: rgb(28, 184, 65);
+ padding: .25em 0.5em; line-height:200%; }
+.button-inlist:hover, .button-inlist-action:hover {color: white ;}
+.dup_line { background-color:yellow!important; }
+
+
+/* Tablets and smaller screens */
+@media only screen and (max-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) {
+ .main-content { margin-top: 0em; }
+}
+
+@media only screen and (max-width: 768px) {
+}
+
+@media only screen and (max-width: 640px) {
+ .navigation { position:fixed; display:block; width:100%; height:20%; left:0px; bottom:0px; background:#fff; border-top:1px solid grey; }
+ .navigation>a { display:none; }
+ .navigation ul { display:block; }
+ .navigation ul li { line-height:3em; width:30%; padding:0em; margin:0em; display:inline; border:0px solid white; }
+ .navigation ul li a { display:initial; }
+ .footer { display:none; }
+ .spacer { height:14em; display: block; }
+ .main-content { padding-left:0px; }
+ .pure-form .pure-u-1-6:first-child { display:none; }
+ .pure-u-19-24.main-content { width:100%; }
+}
+@media only screen and (max-width: 72em) {
+ .pure-form-aligned label { text-align: left!important; }
+ .pure-form-aligned input { }
+ .main-content { margin-top: 0.3em; /*padding-left:1.5em;*/ }
+}
+
+@media (max-width: 500px) {
+ .button-inlist, .button-inlist-action { font-size:75%; padding: 0.5em; }
+}
+
+
+
+.gavBlueText {color: #002868;}
+.gavRedText {color: #A32638;}
+.redText {color: #ff0000;}
+.greenText {color: #009900;}
+.blueText {color: #0000ff;}
+.yellowText {color: #ffff00;}
+.cyanText {color: #00ffff;}
+.magentaText {color: #ff00ff;}
+.whiteText {color: #fff;}
+.blackText {color: #000;}
+.whiteBkgd {background-color: #fff;}
+.blackBkgd {background-color: #000;}
+.greyBkgd {background-color: #ccc;}
+.lightGreyBkgd {background-color: #e9e9e9;}
+.gavRedBkgd {background-color: #A32638;}
+.gavBlueBkgd {background-color: #002868;}
+
+.overviewtable th.rotate {
+ /* Something you can count on */
+ height: 140px;
+ white-space: nowrap;
+}
+
+.overviewtable th.rotate > div {
+ transform:
+ /* Magic Numbers */
+ translate(5px, 57px)
+ /* 45 is really 360 - 45 */
+ rotate(315deg);
+ width: 30px;
+}
+.overviewtable th.rotate > div > span {
+ border-bottom: 1px solid #ccc;
+ padding: 5px 10px;
+}
+.overviewtable td {border: 1px solid lightgrey; }
diff --git a/default_welcome_letter.json b/default_welcome_letter.json
new file mode 100644
index 0000000..0e9d45b
--- /dev/null
+++ b/default_welcome_letter.json
@@ -0,0 +1,7 @@
+{ "what_expect": "sample text for what to expect",
+ "assessments": "the assessments",
+ "textbook": "textbook or oei",
+ "other_info": "oi",
+ "introduction": "Introduction to this class",
+ "additional_resources": "Subsections like AEC, Tutoring/STEM/Academic Success/ Library Fresh success and more"
+}
\ No newline at end of file
diff --git a/dir.php b/dir.php
new file mode 100644
index 0000000..8463c2c
--- /dev/null
+++ b/dir.php
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/dir_api.20211021php b/dir_api.20211021php
new file mode 100644
index 0000000..2c7a13c
--- /dev/null
+++ b/dir_api.20211021php
@@ -0,0 +1,822 @@
+{$s}
\n"; }
+function p2($val){ echo ''; print_r($val); echo "
\n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+include('underscore.php');
+
+////////////////////
+////////////////////
+//
+// PHP SESSIONS .... needed?
+//
+
+/*
+header("Access-Control-Allow-Credentials: true");
+header("Access-Control-Allow-Methods: get,post");
+header("Access-Control-Allow-Headers: Content-Type, Accept");
+session_start();
+
+function logout() { session_destroy(); }
+*/
+
+
+////////////////////
+////////////////////
+//
+// DATABASE
+//
+// Yes, there's two different databases.
+//
+// $c = gavi_db
+// $c2 = PeterDB
+//
+// Why? Just to keep you on your toes.
+//
+// The $j argument is true for a json result, or false for a raw db object result.
+//
+
+
+$DBServer = 'localhost'; $DBUser = 'www';
+$DBPass = '@$df'; $DBName = 'gavi_db';
+
+$c = new mysqli($DBServer, $DBUser, $DBPass, $DBName);
+if ($c->connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+
+$c2 = new mysqli($DBServer, "phowell", 'p^howell', 'PeterDB');
+if ($c2->connect_error) { die('Database connection failed: ' . $c2->connect_error ); }
+if (!mysqli_select_db($c2, 'PeterDB')) { die("Uh oh, couldn't select database 'PeterDB'"); }
+
+// Generic string cleaner
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
- ')); }
+
+// 1. lookups, like a username
+function single_row_select($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 1a. inserts
+function single_row_insert($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $a = mysqli_fetch_assoc($c);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 2. grid or fancier joins, like get all sessions, rosters, todos, etc
+function multi_row_select($qry, $j=1, $db) {
+ $rows = array();
+ $result = mysqli_query($db, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+// 3. Check if an entry exists
+function does_exist($qry, $full_record=0, $db) { global $c, $c2;
+ $r = mysqli_query($db, $qry);
+ $a = mysqli_num_rows($r);
+ $row = mysqli_fetch_array($r, MYSQLI_NUM);
+ $id = $row[0]; // getting the id of that which exists... assuming first column has it.
+ d_err("does exist: {$a}");
+ $e = mysqli_error($db); if($e) { d_err("sql error: " . $e); }
+ if ($a && $full_record) { return $row; } if ($a) { return $id; } return 0; }
+
+
+
+////////////////////
+////////////////////
+//
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+$server = $_SERVER['SERVER_NAME'];
+
+
+if ( preg_match('/intranet1/', $server )) {
+
+ require 'mAuth.php';
+
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = strtolower($attributes['http://wso2.org/claims/emailaddress'][0]);
+
+ /*$USER_TYPE = "FACULTY"; //$attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = "G00102586"; //$attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = "phowell@gavilan.edu"; //$attributes['http://wso2.org/claims/emailaddress'][0];
+
+ $status = "ID:{$USER_GOO}
";
+ $status .= "Email:{$USER_EMAIL}
";
+ $status .= "Employee type:{$USER_TYPE}
";
+
+ d_err($status); */
+} else {
+ echo json_encode( array("result"=>"not on intranet1") );
+ //exit();
+
+ $USER = 0;
+ $USER_NAME = 0;
+ $USER_PERS_ID = 0;
+ $USER_CONF_U_ID = 0;
+ $USER_PERS_EXT_ID = 0;
+
+}
+
+
+
+// Current academic year
+$AY = single_row_select("SELECT * FROM conf_academicyears WHERE label='2021-2022';",0, $c2);
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// Fetching a person's records
+//
+// 1. use their email to lookup PERSONNEL
+// - basic directory info
+//
+// 2. use their email to lookup CONF_USERS
+// - flex app, workshop signups
+//
+// 3. use conf_users.id to lookup in gavi_personnel_ext.c_users
+// - goo, depts, job title, image active
+//
+// 4. use personnel.id to lookup [webpages, welcomepages, etc]
+
+
+function user_record() { global $USER, $USER_EMAIL, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, LOWER(email) AS email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $USER_EMAIL . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, LOWER(email) AS email_c_users, name, active FROM conf_users WHERE LOWER(email)='" . $USER_EMAIL . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, role, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, general_photo_release, etc FROM gavi_personnel_ext WHERE c_users=' . $mega->id_c_users;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ $USER = $mega;
+}
+
+
+if ($USER_EMAIL) { user_record(); }
+
+
+
+
+// //
+// //
+// // LOG ENTRIES
+// //
+// //
+
+
+
+// Enter or get browser log entry
+function insert_or_get_browser($b) {
+ global $c2;
+ $BROWSER = ok($b);
+ $existing = does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'", 0, $c2);
+ if ($existing) {
+ return $existing;
+ } else {
+ $q = "INSERT INTO www_browsers (string) VALUES ('$BROWSER')";
+ single_row_select($q,0,$c2);
+ return does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'",0,$c2);
+ }
+ return 0; }
+
+
+// Log everything!
+function log_it($action,$extra='') {
+ global $USER, $c2;
+
+ if (! $USER) {
+ $USER = array( 'name'=>'unknown', 'id'=>-1 ); }
+ $user_browser = $_SERVER['HTTP_USER_AGENT'];
+ $user_ip = $_SERVER['REMOTE_ADDR'];
+
+ $BROWSER = insert_or_get_browser($user_browser);
+ $ACTION = ok($action);
+ $EXTRA = ok($extra);
+
+ //$id = ok($_POST['id']);
+ $qupdate = "INSERT INTO gavi_logs SET action='{$action}', personnel_id='{$USER->id}', name='{$USER->name}', extra='{$EXTRA}', browser=$BROWSER, ip='$user_ip'";
+ single_row_select($qupdate,0,$c2);
+ return array("result"=>"success","action"=>"logged","query"=>$qupdate,"err"=>mysqli_error($c2));
+}
+
+
+
+
+
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function name_to_lc($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln;
+}
+function name_to_file($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln . ".jpg";
+}
+
+function check_dir_photo($fn,$ln) { global $USER;
+ $filename = name_to_file( $fn,$ln );
+ $path = '/gavilan.edu/staff/images_sm/' . $filename;
+ $dir_pic_exists = 0;
+ $dir_pic_path = 'images_sm/nobody.jpg';
+
+ if (file_exists($path)) {
+ $dir_pic_exists = 1;
+ $dir_pic_path = 'images_sm/' . $filename; }
+ $USER->dir_pic_exists = $dir_pic_exists;
+ $USER->dir_pic_path = $dir_pic_path;
+ return $dir_pic_exists;
+}
+
+check_dir_photo($USER->first_name, $USER->last_name);
+
+//
+//
+//
+////////////////////
+////////////////////
+
+
+
+//require __DIR__ . '/vendor/autoload.php';
+
+
+
+
+// Sample URL
+//
+// https://www.gavilan.edu/staff/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+//
+// https://intranet1.gavilan.edu/dir/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+
+
+
+
+
+/*
+
+
+NEXT STEPS:
+
+- figure out permissions system
+
+ - which means knowing dept / hierarchy
+
+ - which means cross referencing PERSONNEL and EXT and CONF_USERS.....
+
+
+
+## Permissions summary
+
+0. There is a list of table+column combos that users are allowed to edit.
+0.5 An activity "belongs" to the user who owns it (or created it).
+
+1. Simple cases:
+ - current user is updating their own (allowable) record. Allow.
+2. Superuser:
+ - current user is executive, hr, it, or root. (7,2,8,3) Allow.
+3. User is "Dept Editor" (4) and
+ -is updating a record belonging to someone in their dept. Allow.
+4. Harder: Updating events
+
+5. Updating attendance, approvals, or other restricted tables. Only FPLC (1) or superusers.
+
+*/
+
+
+function check_permission( $acting_user, $target_user, $table ) {
+
+ // TODO
+ return true;
+}
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Everyone. Basic dir. Include status==0 which is unpublished.
+function staff_dir() { global $c;
+ return multi_row_select('SELECT first_name,last_name,department,status, room,phone_number,email,web_on,id FROM personnel',1, $c);
+ // WHERE status IS null OR status=1
+}
+
+
+// Everyone. Basic dir
+function staff_dir_ext() { global $c;
+ //return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,p.email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel ORDER BY p.last_name LIMIT 5000',1, $c);
+
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,p.email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) ORDER BY p.last_name LIMIT 5000',1, $c);
+ // WHERE p.status IS null OR p.status=1
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list') {
+ echo staff_dir_ext(); exit(); }
+
+
+// TODO what about people who don't have all three rows?
+//
+//
+
+//
+//
+//
+//
+//
+// Helper tables
+function sub_menus() { global $c2;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0, $c2);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0, $c2);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0, $c2);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0, $c2);
+
+ return json_encode( array( 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc ) );
+ exit();
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='menus') {
+ echo sub_menus(); exit(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS / WORKSHOPS / EVENTS
+//
+function get_sessions() {
+ global $c2, $AY;
+ echo json_encode( multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0, $c2)); exit(); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/sessions') { get_sessions(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// LIST THE CURRENT USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+function get_user_sessions() {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER->id_c_users}' OR sup.user='{$USER->id_c_users}') AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/mysessions') { get_user_sessions(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIGNUP for (possibly overlapping time) session ...
+//
+function signup() {
+ global $c2, $AY, $USER;
+ preg_match('/signup\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $ts = date("Y-m-d H:i:s");
+ $logaction = log_it("Signed up for session: {$ses}");
+
+ $existing = does_exist(
+ "SELECT i.id FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.id={$ses} AND i.user={$USER->id_c_users}",0,$c2);
+ if ($existing) {
+ $qupdate = "UPDATE conf_signups SET session={$ses}, timestamp='{$ts}' WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($qupdate,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$qupdate,"err"=>mysqli_error($c2)));
+ } else {
+ $q = "INSERT INTO conf_signups (session,user,timestamp) VALUES ({$ses},{$USER->id_c_users},'{$ts}')";
+ single_row_select($q,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"inserted","logaction"=>$logaction, "ses"=>$_SESSION,"query"=>$q,"err"=>mysqli_error($c2)));
+ } exit(); }
+
+if (isset($_GET['a']) && preg_match('/signup\/(\d+)$/', $_GET['a'], $matches)) { signup(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// CANCEL a signup
+//
+function signdown() {
+ global $c2, $AY, $USER;
+ preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $q = "DELETE FROM conf_signups WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($q,1,$c2);
+ $logaction = log_it("Canceled signup for session: $ses");
+
+ echo json_encode( array("result"=>"success","action"=>"deleted","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches)) { signdown(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// NEW SESSION
+//
+function new_session() {
+ global $c2, $AY, $USER;
+
+
+ $title = ok($_POST['title']); $starttime = ok($_POST['starttime']);
+ $length = ok($_POST['length']); if ($length=='') { $length=1; }
+ $track = ok($_POST['track']); $gets_survey = ok($_POST['gets_survey']);
+ $is_flex_approved = ok($_POST['is_flex_approved']); $category = ok($_POST['title']);
+ if ($category=='') { $category=0; }
+ $author = ok($_POST['author']); if ($author=='') { $author=1; } // $USER->id_c_users; }
+ $is_custom = ok($_POST['is_custom']); $parent = ok($_POST['parent']);
+ $desc = ok($_POST['desc']); $location = ok($_POST['location']);
+ $recording = ok($_POST['recording']); $instructions = ok($_POST['instructions']);
+ $type = ok($_POST['type']); if ($type=='') { $type=19; }
+ $cal_uid = ok($_POST['cal_uid']);
+
+
+ $q = "INSERT INTO conf_sessions (`title`,`starttime`,`length`,`track`,`gets_survey`,`is_flex_approved`,`category`,`author`,`is_custom`,`parent`,`desc`,`location`,`recording`,`instructions`,`type`,`cal_uid`) VALUES ('{$title}', '{$starttime}', '{$length}', '{$track}', '{$gets_survey}', '{$is_flex_approved}', '{$category}', '{$author}', '{$is_custom}', '{$parent}', '{$desc}', '{$location}', '{$recording}', '{$instructions}', '{$type}', '{$cal_uid}');";
+ $ins = single_row_insert($q,0,$c2);
+ $logaction = log_it("created new session: {$title}");
+ echo json_encode( array("result"=>"success","action"=>"inserted new session","insert"=>$ins, "query"=>$q,"logaction"=>$logaction,"err"=>mysqli_error($c2)));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/newsession') { new_session(); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function set_sessioninfo() {
+ global $c, $c2, $AY, $USER;
+ $table = 'conf_sessions';
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if (! check_permission( $USER->id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE {$table} SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_select($q,0,$c1);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit();
+}
+
+
+
+ /*$title = ok($_POST['title']);
+ $desc = ok($_POST['desc']);
+ $location = ok($_POST['location']);
+ $recording = ok($_POST['recording']);
+ $instructions = ok($_POST['instructions']);
+ $id = ok($_POST['id']);
+ $qupdate = "UPDATE conf_sessions SET title='$title', `desc`='$desc', location='$location', recording='$recording', instructions='$instructions' WHERE id=$id";
+ single_row_select($qupdate,0,$c2);
+ $logaction = log_it("edited session id: {$id}");
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction,"query"=>$qupdate,"err"=>mysqli_error($c2)));
+ //print_r($_POST);
+ exit();}
+ */
+
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a name, lname, dept, phone, extension, email, type, room, status, user_id, or web_on
+function update_dir() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE personnel SET ");
+ //$q = substr($q, 0, -2);
+ $q .= "time_updated='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update personnel record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update') { update_dir(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update') { update_dir(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update goo, dept1/dept2, title, active, use_dir_photo
+function update_dir_ext() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->ext_id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel_ext record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel_ext record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE gavi_personnel_ext SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ if ($USER->ext_id) {
+ single_row_select($q,0,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ else {
+ $logaction2 = log_it("failed to update gavi_personnel_ext record. dont have id for user.",var_dump($USER) );
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_xt') { update_dir_ext(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_xt') { update_dir_ext(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update person, officehours, title, picture, education, bio, courses, personal_page, changed
+function update_webpage() {
+ global $USER_PERS_ID, $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE person={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating bio webpage record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE person={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating bio webpage record");
+ }
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE webpages SET ");
+ $q .= "changed='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update bio webpage record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_web') { update_webpage(); }
+
+
+
+
+
+
+
+
+function handle_pic_upload() { global $USER;
+ $uploaddir = '/gavilan.edu/staff/uploads/';
+ $date = date('Ymd_Hi');
+ $uploadfile = $uploaddir . name_to_lc($USER->first_name,$USER->last_name) . "_" . $date . "_" . basename($_FILES['file']['name']);
+
+
+ echo '';
+ if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
+ echo "File is valid, and was successfully uploaded.\n";
+ } else {
+ echo "Possible file upload attack!\n";
+ }
+
+ echo 'Here is some more debugging info:';
+ print_r($_FILES);
+
+ print "";
+
+}
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+//if (isset($_REQUEST['file'])) { handle_pic_upload(); }
+if (isset($_FILES['file'])) { handle_pic_upload(); }
+
+
+
+
+
+
+function get_a_user($user_email) { global $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $user_email . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='" . $user_email . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, title, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel=' . $mega->id;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+
+ return $mega;
+
+}
+
+
+function insert_c2($q) {
+ global $c2;
+ $result = single_row_insert($q,0,$c2);
+ return $result; }
+
+function merge_tables() { global $c;
+ $all_personnel = multi_row_select('SELECT first_name,last_name,department,room,phone_number,email,web_on,id FROM personnel WHERE status IS null OR status=1',0, $c);
+
+ $emails = __::pluck($all_personnel, 'email');
+ //echo json_encode($emails);
+ //exit();
+
+ //$emails = array_slice($emails, 0, 10);
+
+ $full = __::map( $emails, get_a_user );
+
+ //echo json_encode($full);
+
+ //$results = __::map( __::pluck($full,'aaqueryfix'), insert_c2);
+
+ //$results = __::pluck($full,'bbqueryfix');
+ //$results = __::map( $results, insert_c2);
+ echo json_encode( $full );
+ exit();
+
+}
+
+if (isset($_REQUEST['merge'])) { merge_tables(); }
+
+
+
+
+
+//echo json_encode($_FILES);
+
+//echo json_encode($_REQUEST);
+
+
+// If no arguments were given:
+
+
+if ($USER_EMAIL) {
+// log it as an access
+ $logaction = log_it("accessed personnel record editor");
+
+ $USER->logresult = $logaction;
+
+ // Default case is current user data to be embedded in editor page
+ echo json_encode($USER);
+} else {
+ echo json_encode( array("result"=>"not logged in") );
+ exit();
+}
+?>
diff --git a/dir_api.php b/dir_api.php
new file mode 100644
index 0000000..f750773
--- /dev/null
+++ b/dir_api.php
@@ -0,0 +1,1765 @@
+connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+
+$c2 = new mysqli($DBServer, $DBUser2, $DBPass2, $DBName2);
+if ($c2->connect_error) { die('Database connection failed: ' . $c2->connect_error ); }
+if (!mysqli_select_db($c2, $DBName2)) { die("Uh oh, couldn't select database 'PeterDB'"); }
+mysqli_set_charset($c, 'utf8');
+mysqli_set_charset($c2, 'utf8');
+
+include('underscore.php');
+$_ = new __();
+
+// _ _
+// | | | |
+// | |__ ___| |_ __ ___ _ __ ___
+// | '_ \ / _ \ | '_ \ / _ \ '__/ __|
+// | | | | __/ | |_) | __/ | \__ \
+// |_| |_|\___|_| .__/ \___|_| |___/
+// | |
+// |_|
+
+// Generic string cleaner
+// keep HTML tags string cleaner
+
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
- ')); }
+function okh($str) { global $c; return mysqli_real_escape_string($c, $str); }
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function p($s) { echo "
{$s}
\n"; }
+function p2($val){ echo ''; print_r($val); echo "
\n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+function logout() { session_destroy(); }
+
+// Some helpful globals
+
+$server = $_SERVER['SERVER_NAME'];
+$options_query = "SELECT label,value FROM `conf_uinforecord` WHERE id>1";
+$options_array = multi_row_select($options_query, 0, $c2);
+
+$OPTIONS = array_reduce($options_array, function ($result, $item) {
+ $result[$item["label"]] = $item["value"];
+ return $result; }, []);
+
+$default_ay_query = "SELECT begin,end FROM conf_academicyears ca JOIN conf_uinforecord cu ON cu.value=ca.id WHERE cu.label='default_ay';";
+$AY = single_row_select($default_ay_query,0, $c2);
+$OPTIONS['year'] = $AY;
+
+$conf_query = "SELECT semester,date1,date2,title FROM conf_conferences cc JOIN conf_uinforecord cu ON cu.value=cc.id WHERE cu.label='default_conference';";
+$CONF = single_row_select($conf_query,0, $c2);
+$OPTIONS['conf'] = $CONF;
+
+
+function name_to_lc($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln; }
+
+function name_to_file($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln . ".jpg"; }
+
+
+// 1. lookups, like a username
+function single_row_select($qry, $j, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (!$r) { return $r; }
+ //echo("\n\n\n");
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 1a. inserts
+function single_row_insert($qry, $j, $c) {
+ $r = mysqli_query($c, $qry);
+ //d_err($qry);
+ //$e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $new_id = mysqli_insert_id($c);
+ return $new_id; }
+
+ /*$a = mysqli_fetch_assoc($c);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); } */
+
+// 1b. updates
+function single_row_update($qry, $j, $c) {
+ $r = mysqli_query($c, $qry);
+ return 1; }
+
+// 2. grid or fancier joins, like get all sessions, rosters, todos, etc
+function multi_row_select($qry, $j, $db) {
+ $rows = array();
+ $result = mysqli_query($db, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+// 3. Check if an entry exists
+function does_exist($qry, $full_record, $db) { global $c, $c2;
+ $r = mysqli_query($db, $qry);
+ $a = mysqli_num_rows($r);
+ if (! $a ) { return 0; }
+ $row = mysqli_fetch_array($r, MYSQLI_NUM);
+ $id = $row[0]; // getting the id of that which exists... assuming first column has it.
+ $e = mysqli_error($db); if($e) { d_err("sql error: " . $e); }
+ if ($a && $full_record) { return $row; } if ($a) { return $id; } return 0; }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// //
+// // LOG ENTRIES
+// //
+// // Enter or get browser log entry
+function insert_or_get_browser($b) {
+ global $c2;
+ $BROWSER = ok($b);
+ $existing = does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'", 0, $c2);
+ if ($existing) { return $existing;
+ } else {
+ $q = "INSERT INTO www_browsers (string) VALUES ('$BROWSER')";
+ single_row_insert($q,0,$c2);
+ return does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'",0,$c2); } }
+
+function dumpit($var) {
+ ob_start();
+ var_dump($var);
+ $a=ob_get_contents();
+ ob_end_clean();
+ return $a;
+}
+// //
+// // Log everything!
+function log_it($action) {
+ global $USER, $USER_GOO, $USER_EMAIL, $c2;
+ //echo("\n\n\n");
+
+ if (! $USER) {
+ $USER = array( 'user_id'=>'unknown', 'id'=>-1 ); }
+ $user_browser = $_SERVER['HTTP_USER_AGENT'];
+ $user_ip = $_SERVER['REMOTE_ADDR'];
+
+ $BROWSER = insert_or_get_browser($user_browser);
+ $ACTION = ok($action) . " / " . dumpit($USER) . " / " . $USER_GOO . " / " . $USER_EMAIL;
+
+ //$persid = $USER->id;
+ //if (! $persid) { $persid = -1; }
+ $qupdate = "INSERT INTO gavi_logs SET action='{$ACTION}', " /*personnel_id='{$persid}',name='{$USER->user_id}', */ . "browser=$BROWSER, ip='$user_ip'";
+ single_row_insert($qupdate,0,$c2);
+ return array("result"=>"success","action"=>"logged","query"=>$qupdate,"err"=>mysqli_error($c2)); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Look in various folders for STAFF PICTURES
+function user_pic_look($first,$last,$g) {
+
+ $images = array();
+ $images[] = 'images_sm/missing.jpg';
+
+ $sm_exists = file_exists("/gavilan.edu/staff/images_sm");
+ $goo_exists = file_exists("/gavilan.edu/staff/images_goo");
+
+ if ($sm_exists && $goo_exists) {
+
+ $name_name = str_replace(' ','',str_replace('-','', strtolower($first) )) . "_" . str_replace(' ','',str_replace('-','', strtolower($last) ));
+ $name_name1 = $name_name . ".jpg";
+ $name_name2 = $name_name . "2" . ".jpg";
+ $name_name3 = $name_name . "3" . ".jpg";
+ $name_name4 = $name_name . "4" . ".jpg";
+
+ $name_dir = scandir("/gavilan.edu/staff/images_sm");
+ if ($name_dir && in_array($name_name1,$name_dir)) { $images[] = 'images_sm/' . $name_name1; }
+ if ($name_dir && in_array($name_name2,$name_dir)) { $images[] = 'images_sm/' . $name_name2; }
+ if ($name_dir && in_array($name_name3,$name_dir)) { $images[] = 'images_sm/' . $name_name3; }
+ if ($name_dir && in_array($name_name4,$name_dir)) { $images[] = 'images_sm/' . $name_name4; }
+
+ $badge_dir = scandir("/gavilan.edu/staff/images_goo");
+ $badge_name = $g . ".jpg";
+ if ($badge_dir && in_array($badge_name,$badge_dir)) { $images[] = 'images_goo/' . $badge_name; }
+ }
+ return $images; }
+
+
+//
+// Photos stuff. This shouldn't be needed anymore since we store pic path in the database.
+//
+function check_dir_photo($fn,$ln) { global $USER;
+ $filename = name_to_file( $fn,$ln );
+ $path = '/gavilan.edu/staff/images_sm/' . $filename;
+ $dir_pic_exists = 0;
+ $dir_pic_path = 'images_sm/nobody.jpg';
+
+ if (file_exists($path)) {
+ $dir_pic_exists = 1;
+ $dir_pic_path = 'images_sm/' . $filename; }
+ $USER->dir_pic_exists = $dir_pic_exists;
+ $USER->dir_pic_path = $dir_pic_path;
+ return $dir_pic_exists; }
+
+
+
+/////
+/////
+//
+// Insert new user
+//
+// For whatever reason, we haven't seen this person before. Insert their conf_user row
+// so they can have their choices recorded.
+//
+function insert_new_user() { global $USER, $USER_EMAIL, $USER_GOO, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $LC_EMAIL = strtolower($USER_EMAIL);
+ single_row_insert("INSERT INTO conf_users (goo, email, name) VALUES ('{$USER_GOO}','{$LC_EMAIL}','{$USER_NAME}');", 1, $c2);
+ $logaction = log_it("Made a new conf_users row for {$USER_NAME} / {$LC_EMAIL} / {$USER_GOO}");
+}
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Fetching a person's records
+//
+// 1. use their email to lookup PERSONNEL
+// - basic directory info
+//
+// 2. use their email to lookup CONF_USERS
+// - flex app, workshop signups
+//
+// 3. use conf_users.id to lookup in gavi_personnel_ext.c_users
+// - goo, depts, job title, image active
+//
+// 4. use personnel.id to lookup [webpages, welcomepages, etc]
+//
+//
+// Ultimately the user's data goes into the global $USER
+
+function user_record() { global $USER, $USER_EMAIL, $USER_GOO, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $LC_EMAIL = strtolower($USER_EMAIL);
+
+ if (! $USER_EMAIL) {
+ $goo = substr($USER_GOO, 3);
+ $q0 = "SELECT email FROM conf_users WHERE goo='{$goo}'";
+ $temp_usr = single_row_select($q0,0,$c2);
+
+ if (is_null($temp_usr)) {
+ // we have a new user here...
+ // and the missing email might be a problem....
+ insert_new_user();
+ }
+ //echo($goo);
+ //print_r($temp_usr);
+ //echo($temp_usr->email);
+ //echo("\n");
+ $LC_EMAIL = strtolower($temp_usr['email']);
+ }
+
+ $usr_check = single_row_select("SELECT id FROM conf_users WHERE LOWER(email)='{$LC_EMAIL}';",0,$c2);
+ if (is_null($usr_check)) {
+ // we have a new user here...
+ insert_new_user();
+ }
+
+ //$q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on, status FROM personnel WHERE LOWER(email)='{$LC_EMAIL}'";
+ //$usr_dir = single_row_select($q1, 0, $c);
+
+ $q2 = "SELECT id AS conf_id, goo AS conf_goo, email AS conf_email, name AS conf_name, active AS conf_active FROM conf_users WHERE LOWER(email)='{$LC_EMAIL}'";
+ $USER = single_row_select($q2, 0, $c2);
+ //$mega = $_->extend( (object) $usr_dir, (object) $usr_conf );
+
+ //$q3 = 'SELECT id AS ext_id, personnel AS personnel_id, role, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, general_photo_release, etc, espanol, zoom, preferred_contact FROM gavi_personnel_ext WHERE personnel=' . $mega->id . ';'; // c_users={$mega->conf_id}';
+ //$usr_ext = single_row_select($q3,0,$c2);
+ //$mega = $_->extend( (object) $mega, (object) $usr_ext );
+
+ //$q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id . ';'; // '{$mega->id}'"; // personnel=1');
+ //$usr_web = single_row_select($q4,0,$c);
+ //$mega = $_->extend( (object) $mega, (object) $usr_web );
+ //$USER = $mega;
+ }
+
+
+
+
+
+
+// _____ _____ _ _ _____ _ ______ _ ____ _ _
+// / ____|_ _| \ | |/ ____| | | ____| (_) / __ \| \ | |
+// | (___ | | | \| | | __| | | |__ ___ _ __ _ _ __ | | | | \| |
+// \___ \ | | | . ` | | |_ | | | __| / __| |/ _` | '_ \ | | | | . ` |
+// ____) |_| |_| |\ | |__| | |____| |____ \__ \ | (_| | | | | | |__| | |\ |
+// |_____/|_____|_| \_|\_____|______|______| |___/_|\__, |_| |_| \____/|_| \_|
+// __/ |
+// |___/
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+
+
+if ( $server == 'intranet1.gavilan.edu' ) { // The SSO check should have happened on the actual page. If it gets
+// // stuck on an api call the app will break.
+ if ( session_id() == '' ) { // session_status() == PHP_SESSION_ACTIVE // newer php uses this
+ require 'mAuth.php';
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = $attributes['http://wso2.org/claims/emailaddress'][0];
+ ?>
+
+ first_name, $USER->last_name);
+ }
+
+//
+//
+//
+//
+
+
+
+
+
+
+
+
+
+// _ _
+// (_) (_)
+// _ __ ___ _ __ _ __ ___ _ ___ ___ _ ___ _ __ ___
+// | '_ \ / _ \ '__| '_ ` _ \| / __/ __| |/ _ \| '_ \/ __|
+// | |_) | __/ | | | | | | | \__ \__ \ | (_) | | | \__ \
+// | .__/ \___|_| |_| |_| |_|_|___/___/_|\___/|_| |_|___/
+// | |
+// |_|
+
+
+/*
+
+
+NEXT STEPS:
+
+- figure out permissions system
+
+ - which means knowing dept / hierarchy
+
+ - which means cross referencing PERSONNEL and EXT and CONF_USERS.....
+
+
+
+## Permissions summary
+
+0. There is a list of table+column combos that users are allowed to edit.
+0.5 An activity "belongs" to the user who owns it (or created it).
+
+1. Simple cases:
+ - current user is updating their own (allowable) record. Allow.
+2. Superuser:
+ - current user is executive, hr, it, or root. (7,2,8,3) Allow.
+3. User is "Dept Editor" (4) and
+ -is updating a record belonging to someone in their dept. Allow.
+4. Harder: Updating events
+
+5. Updating attendance, approvals, or other restricted tables. Only FPLC (1) or superusers.
+
+
+
+
+## Calls which edit the database
+
+Everything is sent in two arguments: cols and vals. They are comma separated and actual commas are replaced with [CMA]
+
+This relies on the app knowing the correct columns for the given table.
+
+Everything goes through the permission checker, which uses the: current user, target table, and target table row id
+to figure out if its allowed.
+
+
+TODO: permissions function
+
+TODO: prefer to POST these calls just to be a little cleaner.
+
+
+
+TODO: psuedo permissions but just to decide which navigation buttons to show:
+
+
+ - faculty see the welcome letters editor
+ - certain permissions see: big staff dir list editor (filtered per their dept), activities big list editor or results
+ - who sees the logs page?
+
+ also... determine who sees a particular "edit" button show up for activities...
+ who sees the "survey results, attendees reports" show up for past activities...
+
+
+Sample URLs:
+
+ https://www.gavilan.edu/staff/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+
+ https://intranet1.gavilan.edu/dir/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+*/
+
+
+function check_permission( $acting_user, $target_id, $table ) {
+
+ // TODO
+ return true;
+}
+
+
+
+
+
+
+
+
+
+
+// _ _ _
+// (_) | | | |
+// _ __ ___ _ ___ ___ | |__ ___| |_ __
+// | '_ ` _ \| / __|/ __| | '_ \ / _ \ | '_ \
+// | | | | | | \__ \ (__ | | | | __/ | |_) |
+// |_| |_| |_|_|___/\___| |_| |_|\___|_| .__/
+// | |
+//
+
+
+
+
+//
+// Helper tables
+//
+// JOB TITLES LIST
+function job_titles() { global $c2;
+ return multi_row_select("SELECT DISTINCT id, name FROM gavi_titles ORDER BY name",1, $c2); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='get/jobtitles') {
+ echo job_titles(); exit(); }
+
+// all SUB MENUS
+//
+function sub_menus() { global $c2;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0, $c2);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0, $c2);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0, $c2);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0, $c2);
+ $sss = multi_row_select('SELECT * FROM conf_sessiontypes ORDER BY id',0, $c2);
+ $ppp = multi_row_select("SELECT * FROM `conf_sessions` WHERE `type` = '20' OR `type` = '21' ORDER BY starttime",0, $c2);
+
+
+ return json_encode( array( 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc, 'sessiontypes'=>$sss, 'parents'=>$ppp ) ); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='menus') { echo sub_menus(); exit(); }
+
+
+
+// all NAMES
+//
+function get_names() {
+ global $c2, $AY, $USER;
+ $q = "SELECT u.id, u.name FROM conf_users AS u ORDER BY u.name";
+ echo json_encode( array("users"=>multi_row_select($q,0,$c2), "result"=>"success","err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/names') { get_names(); }
+
+
+// get most RECENT LOGS
+//
+function get_recent_logs() {
+ global $c2, $USER;
+ $my_sessions = multi_row_select("SELECT * FROM `gavi_logs` ORDER BY `id` DESC LIMIT 150",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/logs') { get_recent_logs(); }
+
+
+// gavilan college EVENTS
+//
+function get_events() { global $c;
+ echo json_encode( multi_row_select("SELECT * FROM events WHERE date >= CURDATE() AND visible='1' ORDER BY time LIMIT 6;",0, $c)); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/gavevents') { get_events(); exit(); }
+
+
+
+
+
+// GOTT and workshop signups
+// Export MySQL table as JSON grouped by 'training' + 'date_req' with unique 'email' within each group
+function signups()
+{
+ global $c;
+
+ // SQL query to fetch data from the table
+ $sql = "SELECT * FROM rsvp WHERE DATE(date_rsvp) >= '2023-01-01'";
+ $result = mysqli_query($c, $sql);
+
+ // Create an associative array to hold the grouped data
+ $groupedData = array();
+
+ // Loop through the result rows
+ while ($row = mysqli_fetch_assoc($result)) {
+ // Generate the group key by concatenating 'training' and 'date_req'
+ $groupKey = $row['training'] . $row['date_rsvp'];
+
+ // Check if the group key already exists in the grouped data array
+ if (!array_key_exists($groupKey, $groupedData)) {
+ // If the group key doesn't exist, create a new array for the group
+ $groupedData[$groupKey] = array();
+ }
+
+ // Check if the 'email' already exists within the group
+ $emailExists = false;
+ foreach ($groupedData[$groupKey] as $existingRow) {
+ if ($existingRow['email'] === $row['email']) {
+ $emailExists = true;
+ break;
+ }
+ }
+
+ // Add the row data to the corresponding group if the 'email' doesn't already exist
+ if (!$emailExists) {
+ $groupedData[$groupKey][] = $row;
+ }
+ }
+
+ // Return the grouped data as JSON
+ return json_encode($groupedData);
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='signups') {
+ echo signups(); exit(); }
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ___ | | | |
+// ___ ___ _ _ _ __ ___ ___ ___ ( _ ) | |_ ___ __ _ ___| |__ ___ _ __ ___
+// / __/ _ \| | | | '__/ __|/ _ \/ __| / _ \/\ | __/ _ \/ _` |/ __| '_ \ / _ \ '__/ __|
+// | (_| (_) | |_| | | \__ \ __/\__ \ | (_> < | || __/ (_| | (__| | | | __/ | \__ \
+// \___\___/ \__,_|_| |___/\___||___/ \___/\/ \__\___|\__,_|\___|_| |_|\___|_| |___/
+//
+//
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Courses in a semester
+function semester_sections() { global $c2;
+ return multi_row_select("SELECT * FROM `gavi_sections` s WHERE s.sem='fa21' ORDER BY s.teacher_id",1, $c2); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/semester') {
+ echo semester_sections(); exit(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// STAFF + COURSES COMBINED
+function staff_dir_w_sections() { global $c;
+
+ // just one semesters sections?
+ $WHERE = "WHERE pgs.sem='fa21'";
+
+ // all recorded semesters
+ $WHERE = "";
+
+ return multi_row_select("SELECT p.first_name,p.last_name,p.department,p.status,p.staff_type, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent, GROUP_CONCAT(DISTINCT s.code SEPARATOR ', ') AS sections, COUNT(s.code) AS num_taught FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id LEFT JOIN ( SELECT * FROM PeterDB.gavi_sections pgs {$WHERE}) s ON e.id=s.teacher_id GROUP BY p.id ORDER BY p.last_name LIMIT 2500",0, $c); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/staffsemester') {
+ echo json_encode(staff_dir_w_sections()); exit(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SEARCH AN INSTRUCTOR BY NAME IN SCHEDULE
+//
+function get_instructor() { global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias='{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/name' ) { get_instructor(); }
+
+function get_instructor_fuzzy() {
+ global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias LIKE '{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/fuzzyname' ) { get_instructor_fuzzy(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// COURSE SECTIONS in a semester
+//
+function get_sections($semester) { global $c;
+ $semester = ok($semester);
+ return multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,p.personnel AS personnel_id,p.use_dir_photo,p.dir_photo_path,d.last_name,d.first_name,d.phone_number,d.email,d.room,d.web_on,s.sem FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel WHERE sem='{$semester}' ORDER BY code;",0, $c); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\w\w\d\d)$/', $_REQUEST['a'], $matches)) { echo json_encode( get_sections( $matches[1] ) ); exit(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS by semester and crn only
+//
+function get_all_sections() { global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.crn,s.sem,s.teacher_id,s.delivery,s.status,p.personnel AS personnel_id,d.last_name,d.first_name FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel ORDER BY sem,code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/sections') { get_all_sections(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS of a single INSTRUCTOR
+//
+// use their gavi_personnel_ext id
+//
+function get_instructor_sections($teacherid) {
+ global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.times,s.link,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.xlist_to,s.status,s.pnp,s.note,s.crn,s.sem,s.year FROM PeterDB.gavi_sections s WHERE s.teacher_id='{$teacherid}' ORDER BY s.sem,s.code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_instructor_sections( $matches[1] ); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// COURSE SINGLE SECTION including welcome letter
+//
+// Housekeeping: if the gavi_welcome_letters row doesn't exist, we need to make it and populate it with the example text.
+//
+//
+function get_section($sem,$crn) {
+ global $c, $c2;
+ $sem = ok($sem);
+ $crn = ok($crn);
+ $sched_id = 0;
+
+ $sched_entry = single_row_select( "SELECT * FROM PeterDB.gavi_sections gs WHERE sem='{$sem}' AND crn='{$crn}';",0, $c2);
+ if ($sched_entry) {
+ $sched_id = $sched_entry['id']; }
+ else {
+ echo json_encode( array( "result"=>"fail", "reason"=>"no row for that section {$sem} {$crn}.") );
+ exit(); }
+
+ $wl_entry = single_row_select( "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id,w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.section_id='{$sched_id}';",0, $c2);
+
+ if ($wl_entry) {
+ echo json_encode($wl_entry);
+ exit(); }
+ else {
+
+ // no WL row for that section
+ $logaction = log_it("Creating default welcome letter for Semester: $sem CRN: $crn");
+
+ $default = json_decode( file_get_contents('default_welcome_letter.json') );
+ $default->what_expect = okh($default->what_expect);
+ $default->assessments = okh($default->assessments);
+ $default->textbook = okh($default->textbook);
+ $default->other_info = okh($default->other_info);
+ $default->introduction = okh($default->introduction);
+ $default->additional_resources = okh($default->additional_resources);
+
+ $q = "INSERT INTO PeterDB.gavi_welcome_letters (section_id,format,length,text_title,course_desc,what_expect,assessments,textbook,other_info,introduction,additional_resources) VALUES ('{$sched_id}', '', '', '', '', '{$default->what_expect}', '{$default->assessments}', '{$default->textbook}', '{$default->other_info}', '{$default->introduction}', '{$default->additional_resources}');";
+ $new_id = single_row_insert($q,0,$c2);
+
+ $q4 = "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id, w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.id=" . $new_id . ";";
+
+ $wl_entry = single_row_select( $q4, 0, $c2);
+ echo json_encode($wl_entry);
+ exit();
+ } }
+if (isset($_REQUEST['a']) && preg_match('/^get\/section\/(\w\w\d\d)\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_section( $matches[1], $matches[2] ); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a course section record
+/*function update_section($update=1) {
+ global $USER, $c2;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_sections SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_sections')) {
+ if ($update) {
+ $START = "UPDATE webpages SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating section id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new section");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_insert($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/section') { update_section(0); }
+
+*/
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a WELCOME LETTER
+//
+/*function update_welcome_letter($update=1) {
+ global $USER, $c2, $_;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_welcome_letters SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_welcome_letters')) {
+ if ($update) {
+ $START = "UPDATE gavi_welcome_letters SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating welcome letter id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new welcome letter");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_insert($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/letter') { update_welcome_letter(0); }
+
+*/
+
+
+
+
+
+
+
+
+
+
+
+// __ _ __ _ _
+// / _| | / / | | (_)
+// | |_| | _____ __ / / _ __ __| | ___ ___ ___ ___ _ ___ _ __ ___
+// | _| |/ _ \ \/ / / / | '_ \ / _` | / __|/ _ \/ __/ __| |/ _ \| '_ \/ __|
+// | | | | __/> < / / | |_) | (_| | \__ \ __/\__ \__ \ | (_) | | | \__ \
+// |_| |_|\___/_/\_\ /_/ | .__/ \__,_| |___/\___||___/___/_|\___/|_| |_|___/
+// | |
+// |_|
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS / WORKSHOPS / EVENTS
+//
+function get_sessions() { global $c2, $AY;
+ return multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/sessions') { echo json_encode(get_sessions()); exit(); }
+
+
+function multi_row_1d($qry, $c) {
+ $savedQuery = mysqli_query($c, $qry);
+ while($savedResult = mysqli_fetch_array($savedQuery)) {
+ $savedArray[] = $savedResult[0]; }
+ return $savedArray; }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS + HOSTS
+//
+function get_ses_hosts() { global $c2, $AY;
+ return multi_row_select("select s.id, s.title, s.starttime, u.name, u.email, u.id AS hostid from conf_sessions as s LEFT OUTER JOIN conf_hosts as h ON h.session=s.id LEFT OUTER JOIN conf_users AS u ON h.host=u.id WHERE s.id>1319 ORDER BY u.name;",1, $c2); }
+ //return multi_row_1d("select DISTINCT(u.email) from conf_sessions as s LEFT OUTER JOIN conf_hosts as h ON h.session=s.id LEFT OUTER JOIN conf_users AS u ON h.host=u.id WHERE s.id>1319 ORDER BY u.name;", $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/hosts') { echo get_ses_hosts(); exit(); }
+
+//
+// ALL HOST ENTRIES
+//
+/*function get_all_hosts() { global $c2, $_;
+ $hh = multi_row_select("select host,session FROM conf_hosts ORDER BY host;",0, $c2);
+ $byhost = $_->groupBy($hh, function($n) { return $n['host']; });
+ $_->map( $byhost, function($v,$k) use (&$allhost) { global $_;
+ $allhost[$k] = $_->pluck($v,'session');
+ return array( $k => $_->pluck($v,'session')); });
+ return $allhost; }
+if (isset($_GET['a']) && $_GET['a'] == 'get/allhosts') { echo json_encode(get_all_hosts()); exit(); }
+
+*/
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// LIST THE CURRENT USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+function get_user_sessions() { global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER->conf_id}' OR sup.user='{$USER->conf_id}') AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/mysessions') { get_user_sessions(); }
+
+
+//
+// GET ROSTERS OF ALL SESSIONS
+function get_rosters() {
+ global $AY, $c2;
+
+ /* "SELECT i.user, i.session, i.timestamp, u.goo, u.email, u.name, s.title, s.track, s.starttime, s.location, s.id AS sesid FROM conf_signups as i LEFT JOIN conf_users as u ON i.user=u.id RIGHT JOIN conf_sessions as s ON i.session=s.id WHERE s.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) {$where} ORDER BY sesid;" */
+
+ $where = '';
+ if (isset($_REQUEST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ $where = "AND s.id={$ID}"; }
+ return multi_row_select(
+ "SELECT i.user, i.session, u.goo, u.email, u.name, s.id AS sesid FROM conf_signups as i LEFT JOIN conf_users as u ON i.user=u.id RIGHT JOIN conf_sessions as s ON i.session=s.id WHERE s.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) {$where} ORDER BY sesid;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/rosters') { echo json_encode(get_rosters()); exit(); }
+
+
+
+//
+// GET ALL SIGNUPS
+function get_signups() {
+ global $AY, $c2;
+ $where = '';
+ if (isset($_REQUEST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ $where = "WHERE s.id={$ID}"; }
+ return multi_row_select(
+ "SELECT i.id, i.user, i.session, i.timestamp, i.certified_at, i.badged_at, i.not_flex FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) {$where} ORDER BY i.id DESC;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/signups') { echo json_encode(get_signups()); exit(); }
+
+
+
+//
+// GET ALL USERS
+function get_users() {
+ global $AY, $c2;
+ return multi_row_select(
+ "SELECT * FROM conf_users AS u ORDER BY u.email;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/users') { echo json_encode(get_users()); exit(); }
+
+
+//
+// GET ALL HOSTS
+function get_hosttable() {
+ global $AY, $c2;
+ return multi_row_select(
+ "SELECT * FROM conf_hosts;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/hosttable') { echo json_encode(get_hosttable()); exit(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ARBITRARY USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+// all years
+//
+function get_anyuser_sessions($usr) {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$usr}' OR sup.user='{$usr}') GROUP BY c.id ORDER BY c.starttime LIMIT 150;",0,$c2);
+ // AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME)
+
+ return $my_sessions; }
+if (isset($_GET['a']) && preg_match('/get\/sessions\/(\d+)$/', $_GET['a'], $matches)) { echo json_encode( get_anyuser_sessions($matches[1])); exit(); }
+
+
+// MY Survey ANSWERS
+function get_questions() { global $c2, $USER;
+ //return $USER->id;
+ return multi_row_select( "SELECT ses.id as ses_id, sup.id as sup_id, sup.certified_at as cert, sup.surveyed_at as surveyed, cus.id as user, qset.order, qq.id, qq.question, qq.type, qq.id as qid, ans.answer FROM conf_sessions as ses JOIN conf_signups as sup on ses.id = sup.session JOIN conf_users as cus on cus.id = sup.user JOIN conf_q_set as qset on ses.gets_survey = qset.q_set RIGHT JOIN conf_questions as qq on qset.question = qq.id LEFT OUTER JOIN conf_answers as ans on ans.user = sup.user AND ans.question = qq.id AND ans.session = ses.id WHERE (cus.id='{$USER->conf_id}') ORDER BY ses.starttime, ses.track asc, qset.order", 0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/questions') { echo json_encode(get_questions()); exit(); }
+
+
+// Single session QUESTIONS and possibly ansers
+function get_session_questions($id) { global $c2, $USER;
+ //print_r($USER); exit();
+ $u = $USER->conf_id;
+ return multi_row_select( "SELECT ses.title, {$u} AS user, ses.id as session, q.id AS qid, q.question, q.type, ans.answer FROM conf_sessions AS ses JOIN conf_q_set AS qset ON ses.gets_survey=qset.q_set JOIN conf_questions AS q ON q.id=qset.question LEFT OUTER JOIN conf_answers AS ans ON ans.user={$u} AND ans.question=q.id AND ans.session=ses.id WHERE ses.id={$id}", 0, $c2); }
+
+if (isset($_GET['a'])&& preg_match('/get\/questions\/(\d+)$/', $_GET['a'], $matches)) { echo json_encode(get_session_questions($matches[1])); exit(); }
+
+
+// ALL Survey ANSWERS
+function get_answers_all() { global $c2;
+ return multi_row_select( "SELECT ses.id AS ses_id, ses.title as s_title, ses.starttime, qq.id as q_id, qq.question as question, qq.type as type, ans.answer AS answer FROM conf_sessions AS ses JOIN conf_signups as sup on ses.id = sup.session JOIN conf_users as cus on cus.id = sup.user JOIN conf_q_set as qset on ses.gets_survey = qset.q_set RIGHT JOIN conf_questions as qq on qset.question = qq.id LEFT OUTER JOIN conf_answers as ans on ans.user = sup.user AND ans.question = qq.id AND ans.session = ses.id WHERE ans.answer is not null ORDER BY ses.starttime, ses.track asc, qset.order", 0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/answers/all') { echo json_encode(get_answers_all()); exit(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+
+function set_answers() { global $c, $c2;
+ $ses_id = ok($_REQUEST['session']);
+ $u = ok($_REQUEST['user']);
+ $q = ok($_REQUEST['qid']);
+ $answer = ok($_REQUEST['answer']);
+
+ $existing = does_exist( "select * from `conf_answers` where `user`='$u' and `session`='$ses_id' and `question`='$q';",0,$c2 );
+
+ if ($existing) {
+ $qupdate = "UPDATE conf_answers SET answer='$answer' WHERE session=$ses_id AND user=$u AND question=$q";
+ single_row_update($qupdate,0, $c2);
+ $logaction = log_it("updated answer for session: $ses_id");
+ } else {
+ $qupdate = "INSERT INTO conf_answers SET user='$u', question='$q', session='$ses_id', answer='$answer'";
+ single_row_insert($qupdate,0,$c2);
+ $logaction = log_it("Saved answer for session: $ses_id");
+ }
+ echo json_encode( array("result"=>"success", "logaction"=>$logaction, "action"=>"save survey answer","query"=>$qupdate,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/answers') { set_answers(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+
+function set_cert() {
+ #echo "saving";
+ global $USER, $c2;
+ $ses_id = ok($_REQUEST['ses_id']);
+ $cert = ok($_REQUEST['cert']);
+ $date = "'" . date('Y-m-d H:i:s') . "'";
+ if ($cert=="null") { $date = "NULL"; }
+ $qupdate = "UPDATE conf_signups SET `certified_at`=$date where `user`='$USER' and `session`='$ses_id'";
+ single_row_update($qupdate, 0, $c2);
+ $logaction = log_it("updated certified state for session: $ses_id");
+ echo json_encode( array("result"=>"success", "logaction"=>$logaction, "action"=>"save cert","query"=>$qupdate,"err"=>mysqli_error($c2)));
+ //print_r($_POST);
+ exit(); }
+
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/cert') { set_cert(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIGNUP for (possibly overlapping time) session ... /// id_c_users
+//
+function signup() {
+ global $c2, $AY, $USER;
+ preg_match('/signup\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $ts = date("Y-m-d H:i:s");
+ $logaction = log_it("Signed up for session: " . $ses);
+
+ $sesh = "";
+ if (isset($_SESSION)) { $sesh = $_SESSION; }
+
+ $existing = does_exist(
+ "SELECT i.id FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.id={$ses} AND i.user=" . $USER->conf_id,0,$c2);
+ if ($existing) {
+ $qupdate = "UPDATE conf_signups SET session={$ses}, timestamp='{$ts}' WHERE session={$ses} AND user=" . $USER->conf_id;
+ single_row_select($qupdate,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$qupdate,"err"=>mysqli_error($c2)));
+ } else {
+ $q = "INSERT INTO conf_signups (session,user,timestamp) VALUES ({$ses}," . $USER->conf_id . ",'{$ts}')";
+ single_row_insert($q,1,$c2);
+ echo json_encode( array( /* "userglobal"=>$USER, */ "result"=>"success","action"=>"inserted", /* "logaction"=>$logaction, */
+ "ses"=>$sesh,"query"=>$q,"err"=>mysqli_error($c2)));
+ } exit(); }
+
+if (isset($_GET['a']) && preg_match('/signup\/(\d+)$/', $_GET['a'], $matches)) { signup(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// CANCEL a signup
+//
+function signdown() {
+ global $c2, $AY, $USER;
+ preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $q = "DELETE FROM conf_signups WHERE session={$ses} AND user=" . $USER->conf_id;
+ single_row_update($q,1,$c2);
+ $logaction = log_it("Canceled signup for session: $ses");
+
+ echo json_encode( array("result"=>"success","action"=>"deleted","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches)) { signdown(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// add a HOST for a session ...
+//
+function addhost($sesid,$hostid) {
+ global $c2;
+ $sesid = ok($sesid); $hostid = ok($hostid);
+ $existing = does_exist("SELECT h.host, h.session FROM conf_hosts AS h WHERE h.host={$hostid} AND h.session={$sesid}",0,$c2);
+ if ($existing) { return array("result"=>"success","action"=>"already a host"); }
+ else {
+ $qupdate = "INSERT INTO conf_hosts SET session='{$sesid}', host='{$hostid}';";
+ $new_id = single_row_insert($qupdate,0,$c2);
+ $e = mysqli_error($c2);
+ if ($new_id) { $success = " with new id {$new_id}"; }
+ else { $success = " -- error: {$e}"; }
+ $logaction = log_it("Added host {$hostid} to session: {$sesid}");
+ return array("result"=>"success".$success,"action"=>"added host","query"=>$qupdate,"err"=>$e); } }
+
+if (isset($_GET['a']) && preg_match('/add\/host\/(\d+)\/(\d+)$/', $_GET['a'], $matches)) {
+ echo json_encode(addhost($matches[1], $matches[2])); exit(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// REMOVE a HOST for a session ...
+//
+function removehost($sesid,$hostid) {
+ global $c2;
+ $sesid = ok($sesid); $hostid = ok($hostid);
+ $qupdate = "DELETE FROM conf_hosts WHERE session='{$sesid}' AND host='{$hostid}';";
+ $new_id = single_row_update($qupdate,0,$c2);
+ $e = mysqli_error($c2);
+ $logaction = log_it("Removed host {$hostid} to session: {$sesid}");
+ return array("result"=>"success","action"=>"removed host","query"=>$qupdate,"err"=>$e); }
+
+if (isset($_GET['a']) && preg_match('/remove\/host\/(\d+)\/(\d+)$/', $_GET['a'], $matches)) {
+ echo json_encode(removehost($matches[1], $matches[2])); exit(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// NEW SESSION
+//
+function new_session() {
+ global $c2, $AY, $USER;
+
+
+ $title = ok($_POST['title']); $starttime = ok($_POST['starttime']);
+ $length = ok($_POST['length']); if ($length=='') { $length=1; }
+ $track = ok($_POST['track']); $gets_survey = ok($_POST['gets_survey']);
+ $is_flex_approved = ok($_POST['is_flex_approved']); $category = ok($_POST['title']);
+ if ($category=='') { $category=0; }
+ $author = ok($_POST['author']); if ($author=='') { $author=1; } // $USER->id_c_users; }
+ $is_custom = ok($_POST['is_custom']); $parent = ok($_POST['parent']);
+ $desc = okh($_POST['desc']); $location = okh($_POST['location']);
+ $recording = okh($_POST['recording']); $instructions = okh($_POST['instructions']);
+ $type = ok($_POST['type']); if ($type=='') { $type=19; }
+ $cal_uid = ok($_POST['cal_uid']); $mode = okh($_POST['mode']);
+ $location_irl = okh($_POST['location_irl']);
+
+
+ $q = "INSERT INTO conf_sessions (`title`,`starttime`,`length`,`track`,`gets_survey`,`is_flex_approved`,`category`,`author`,`is_custom`,`parent`,`desc`,`location`,`mode`,`recording`,`instructions`,`type`,`cal_uid`) VALUES ('{$title}', '{$starttime}', '{$length}', '{$track}', '{$gets_survey}', '{$is_flex_approved}', '{$category}', '{$author}', '{$is_custom}', '{$parent}', '{$desc}', '{$location}', '{$location_irl}', '{$mode}', '{$recording}', '{$instructions}', '{$type}', '{$cal_uid}');";
+
+ $ins = single_row_insert($q,0,$c2);
+ $logaction = log_it("created new session id: {$ins}: {$title}");
+ echo json_encode( array( /*"all_args"=>$_POST,*/ "result"=>"success","action"=>"inserted new session","new_id"=>$ins, "query"=>$q,"logaction"=>$logaction,"err"=>mysqli_error($c2)));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/newsession') { new_session(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function reducer ($memo, $a) { return $memo . "`" . ok($a[0]) . "` = '" . okh($a[1]) . "', "; }
+
+function set_sessioninfo() {
+ global $c, $c2, $AY, $USER, $_;
+ $table = 'conf_sessions';
+
+ $DO_CHECKING = 0;
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if ($DO_CHECKING) {
+ // (! check_permission( $USER->conf_id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = array_map('unescape_commas', $vals);
+ $cv = array_map(null,$cols,$vals);
+ $q = array_reduce($cv, 'reducer', "UPDATE `{$table}` SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated", "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit(); }
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// App SETTINGS
+//
+
+
+//
+// GET
+function get_settings() { global $AY, $c2;
+ return multi_row_select( "SELECT * FROM conf_uinforecord;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/settings') { echo json_encode(get_settings()); exit(); }
+
+
+
+
+function set_settings() {
+ global $c, $c2, $AY, $USER, $_;
+ $table = 'conf_uinforecord';
+
+ $DO_CHECKING = 0;
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if ($DO_CHECKING) {
+ // (! check_permission( $USER->conf_id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = array_map('unescape_commas', $vals);
+ $cv = array_map(null,$cols,$vals);
+ $q = array_reduce($cv, 'reducer', "UPDATE `{$table}` SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated", "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit(); }
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+
+
+
+// _ __ __ ______ ___________ _____ _____ _____ _____________ __
+// | | / _|/ _| | _ \_ _| ___ \ ___/ __ \_ _| _ | ___ \ \ / /
+// ___| |_ __ _| |_| |_ | | | | | | | |_/ / |__ | / \/ | | | | | | |_/ /\ V /
+// / __| __/ _` | _| _| | | | | | | | /| __|| | | | | | | | / \ /
+// \__ \ || (_| | | | | | |/ / _| |_| |\ \| |___| \__/\ | | \ \_/ / |\ \ | |
+// |___/\__\__,_|_| |_| |___/ \___/\_| \_\____/ \____/ \_/ \___/\_| \_| \_/
+//
+//
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Everyone. Basic dir. Include status==0 which is unpublished.
+function staff_dir() { global $c;
+ return multi_row_select('SELECT first_name,last_name,department,status, room,phone_number,email,web_on,id FROM personnel',1, $c); }
+
+
+// Everyone. Basic dir
+function staff_dir_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) ORDER BY p.last_name LIMIT 5000',1, $c); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list') {
+ echo staff_dir_ext(); exit(); }
+
+
+// Everyone. Directory info with DEPTS and TITLES added
+function staff_dir_full_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id ORDER BY p.last_name LIMIT 5000',1, $c); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list2') { echo staff_dir_full_ext(); exit(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a name, lname, dept, phone, extension, email, type, room, status, user_id, or web_on
+/*function update_dir() {
+ global $USER, $c, $c2, $_;
+
+ $WHERECLAUSE = " WHERE id={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE personnel SET ");
+ //$q = substr($q, 0, -2);
+ $q .= "time_updated='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_update($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update personnel record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update') { update_dir(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update') { update_dir(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update goo, dept1/dept2, title, active, use_dir_photo
+function update_dir_ext() {
+ global $USER, $c, $c2, $_;
+
+ $WHERECLAUSE = " WHERE id={$USER->ext_id}";
+
+ #print_r($_REQUEST);
+
+ if (isset($_REQUEST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_REQUEST['id'], 'personnel_ext')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel_ext record of personnel id {$_REQUEST['id']}");
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel_ext record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE gavi_personnel_ext SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_xt') { update_dir_ext(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_xt') { update_dir_ext(); }
+
+*/
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update person, officehours, title, picture, education, bio, courses, personal_page, changed
+/*function update_webpage() {
+ global $USER_PERS_ID, $USER, $c, $c2, $_;
+
+ $WHERECLAUSE = " WHERE person={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating bio webpage record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE person={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating bio webpage record");
+ }
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, "UPDATE webpages SET ");
+ $q .= "changed='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_update($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update bio webpage record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_web') { update_webpage(); }
+
+
+
+*/
+
+
+
+
+
+
+// _ _ __ __
+// | | | | / _|/ _|
+// _ __ __ _ _ __ __| | ___ _ __ ___ ___| |_ _ _| |_| |_
+// | '__/ _` | '_ \ / _` |/ _ \| '_ ` _ \ / __| __| | | | _| _|
+// | | | (_| | | | | (_| | (_) | | | | | | \__ \ |_| |_| | | | |
+// |_| \__,_|_| |_|\__,_|\___/|_| |_| |_| |___/\__|\__,_|_| |_|
+//
+//
+
+
+
+
+//
+//
+//
+// Next couple functions are for importing, merging, or just dealing w/ historical data
+//
+// and/or transition tasks......
+//
+//
+
+function handle_pic_upload() { global $USER;
+ $uploaddir = '/gavilan.edu/staff/uploads/';
+ $date = date('Ymd_Hi');
+ $uploadfile = $uploaddir . name_to_lc($USER->first_name,$USER->last_name) . "_" . $date . "_" . basename($_FILES['file']['name']);
+
+
+ echo '';
+ if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
+ echo "File is valid, and was successfully uploaded.\n";
+ } else {
+ echo "Possible file upload attack!\n";
+ }
+
+ echo 'Here is some more debugging info:';
+ print_r($_FILES);
+
+ print "";
+
+}
+//if (isset($_REQUEST['file'])) { handle_pic_upload(); }
+if (isset($_FILES['file'])) { handle_pic_upload(); }
+
+function get_a_user_by_pid($user_pid) { global $c, $c2, $_;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE id='{$user_pid}'";
+ $usr_dir = single_row_select($q1, 0, $c);
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='{$usr_dir['email']}'";
+ $usr_conf = single_row_select($q2, 0, $c2);
+ $mega = $_->extend( (object) $usr_dir, (object) $usr_conf );
+ $q3 = "SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel='{$mega->id}'";
+ $usr_ext = single_row_select($q3,0,$c2);
+ $mega = $_->extend( (object) $mega, (object) $usr_ext );
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ $usr_web = single_row_select($q4,0,$c);
+ $mega = $_->extend( (object) $mega, (object) $usr_web );
+
+ // ?????
+
+
+ /* if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+ */
+
+ echo json_encode( $mega );
+ exit();
+
+}
+if (isset($_REQUEST['a']) && preg_match('/^get\/user\/(\d+)$/', $_REQUEST['a'], $matches)) { get_a_user_by_pid( $matches[1] ); }
+
+
+function get_a_user($user_email) { global $c, $c2, $_;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $user_email . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='" . $user_email . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = $_->extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel=' . $mega->id;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = $_->extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = $_->extend( (object) $mega, (object) $usr_web );
+
+ /*
+ if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }*/
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+
+
+ return $mega; }
+
+
+function insert_c2($q) {
+ global $c2;
+ $result = single_row_insert($q,0,$c2);
+ return $result; }
+
+function merge_tables() { global $c, $_;
+ $all_personnel = multi_row_select('SELECT first_name,last_name,department,room,phone_number,email,web_on,id FROM personnel WHERE status IS null OR status=1',0, $c);
+
+ $emails = $_->pluck($all_personnel, 'email');
+ echo json_encode($emails);
+ //exit();
+
+ $emails = array_slice($emails, 0, 10);
+
+ $full = $_->map( $emails, "get_a_user" );
+
+ echo json_encode($full);
+
+ //$results = $_->map( $_->pluck($full,'aaqueryfix'), insert_c2);
+
+ //$results = $_->pluck($full,'bbqueryfix');
+ //$results = $_->map( $results, insert_c2);
+ //echo json_encode( $full );
+ exit(); }
+if (isset($_REQUEST['merge'])) { merge_tables(); }
+
+
+
+
+
+
+
+function fetch_personnel_dir() { global $c;
+ $all_personnel = multi_row_select('SELECT * FROM personnel',0, $c);
+ echo json_encode($all_personnel);
+ exit(); }
+if (isset($_REQUEST['personnel'])) { fetch_personnel_dir(); }
+
+function fetch_conf_users() { global $c2;
+ $all_personnel = multi_row_select('SELECT * FROM conf_users',0, $c2);
+ echo json_encode($all_personnel);
+ exit(); }
+if (isset($_REQUEST['users'])) { fetch_conf_users(); }
+
+function fetch_personnel_ext() { global $c2;
+ $all_personnel = multi_row_select('SELECT * FROM gavi_personnel_ext',0, $c2);
+ echo json_encode($all_personnel);
+ exit(); }
+if (isset($_REQUEST['personnelext'])) { fetch_personnel_ext(); }
+
+
+
+/*
+
+
+in ilearn but not personnel dir or others
+
+
+in personnel but not others
+
+
+
+
+*/
+
+
+
+//
+//
+// NAVIGATION
+
+function navigation($user) {
+?>
+
+
+
+
+
+';
+ var_dump($temp_usr);
+ echo '';
+
+ exit(); }
+if (isset($_REQUEST['test'])) { test_sso(); }
+
+// __ ____ ____ __ _ ____
+// ____/ /__ / __/___ ___ __/ / /_ ________ / /___ ___________ __ __________ _____ (_)___ / __/___
+// / __ / _ \/ /_/ __ `/ / / / / __/ ______ / ___/ _ \/ __/ / / / ___/ __ \ / / / / ___/ _ \/ ___/ / / __ \/ /_/ __ \
+// / /_/ / __/ __/ /_/ / /_/ / / /_ /_____/ / / / __/ /_/ /_/ / / / / / / / /_/ (__ ) __/ / / / / / / __/ /_/ /
+// \__,_/\___/_/ \__,_/\__,_/_/\__/ /_/ \___/\__/\__,_/_/ /_/ /_/ \__,_/____/\___/_/ /_/_/ /_/_/ \____/
+//
+//
+// ........finally, if no parameters were matched.......
+//
+// DO NOTHING IF FILE WAS INCLUDED from another php page.
+//
+// OTHERWISE, RETURN BASIC USER INFO
+//
+//
+if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
+ // Called directly as api or in browser
+ //
+ if ($USER_GOO) {
+ // Default case is current user data to be embedded in editor page. Log the access
+ //$USER->logresult = log_it("accessed dir app (in intranet folder)");
+ //$USER->pics = user_pic_look( $USER->first_name, $USER->last_name, $USER->conf_goo );
+ //$USER->options = $OPTIONS;
+ echo json_encode($USER); exit();
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"not logged in") ); exit(); } }
+
+
+
+//
+// ELSE it was "included"... do nothing.
+
+
+
+
+//
+// draw big text
+// https://patorjk.com/software/taag/#p=display&c=c%2B%2B&f=Doom&t=sup
+//
+
+
+
+// __ __ _______ ______ __ __ __
+// / /_/ /_ ___ / ____/ | / / __ \ / /_/ /_ ____ _____ / /__ __ ______ __ __
+// / __/ __ \/ _ \ / __/ / |/ / / / / / __/ __ \/ __ `/ __ \/ //_/ / / / / __ \/ / / /
+// / /_/ / / / __/ / /___/ /| / /_/ / / /_/ / / / /_/ / / / / ,< / /_/ / /_/ / /_/ /
+// \__/_/ /_/\___/ /_____/_/ |_/_____/ \__/_/ /_/\__,_/_/ /_/_/|_| \__, /\____/\__,_/
+// /____/
+
+
+
+// peter h 2021
+
+
+
+
+?>
diff --git a/dir_api20211102.php b/dir_api20211102.php
new file mode 100644
index 0000000..6fc903b
--- /dev/null
+++ b/dir_api20211102.php
@@ -0,0 +1,1235 @@
+{$s}\n"; }
+function p2($val){ echo ''; print_r($val); echo "
\n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+include('underscore.php');
+
+////////////////////
+////////////////////
+//
+// PHP SESSIONS .... needed?
+//
+
+/*
+header("Access-Control-Allow-Credentials: true");
+header("Access-Control-Allow-Methods: get,post");
+header("Access-Control-Allow-Headers: Content-Type, Accept");
+session_start();
+
+function logout() { session_destroy(); }
+*/
+
+
+////////////////////
+////////////////////
+//
+// DATABASE
+//
+// Yes, there's two different databases.
+//
+// $c = gavi_db
+// $c2 = PeterDB
+//
+// Why? Just to keep you on your toes.
+//
+// The $j argument is true for a json result, or false for a raw db object result.
+//
+
+
+$DBServer = 'localhost'; $DBUser = 'www';
+$DBPass = '@$df'; $DBName = 'gavi_db';
+
+$c = new mysqli($DBServer, $DBUser, $DBPass, $DBName);
+if ($c->connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+
+$c2 = new mysqli($DBServer, "phowell", 'p^howell', 'PeterDB');
+if ($c2->connect_error) { die('Database connection failed: ' . $c2->connect_error ); }
+if (!mysqli_select_db($c2, 'PeterDB')) { die("Uh oh, couldn't select database 'PeterDB'"); }
+
+mysqli_set_charset('utf8', $c);
+
+mysqli_set_charset('utf8', $c2);
+
+// Generic string cleaner
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
- ')); }
+
+
+// keep HTML tags string cleaner
+function okh($str) { global $c; return mysqli_real_escape_string($c, $str); }
+
+
+// 1. lookups, like a username
+function single_row_select($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 1a. inserts
+function single_row_insert($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry);
+ //d_err($qry);
+ //$e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $new_id = mysqli_insert_id($c);
+ return $new_id; }
+
+ /*$a = mysqli_fetch_assoc($c);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); } */
+
+// 2. grid or fancier joins, like get all sessions, rosters, todos, etc
+function multi_row_select($qry, $j=1, $db) {
+ $rows = array();
+ $result = mysqli_query($db, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+// 3. Check if an entry exists
+function does_exist($qry, $full_record=0, $db) { global $c, $c2;
+ $r = mysqli_query($db, $qry);
+ $a = mysqli_num_rows($r);
+ $row = mysqli_fetch_array($r, MYSQLI_NUM);
+ $id = $row[0]; // getting the id of that which exists... assuming first column has it.
+ d_err("does exist: {$a}");
+ $e = mysqli_error($db); if($e) { d_err("sql error: " . $e); }
+ if ($a && $full_record) { return $row; } if ($a) { return $id; } return 0; }
+
+
+
+////////////////////
+////////////////////
+//
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+
+
+$server = $_SERVER['SERVER_NAME'];
+
+
+if ( $server == 'intranet1.gavilan.edu' ) {
+
+ // The SSO check should have happened on the actual page. If it gets
+ // stuck on an api call the app will break.
+
+ if ( session_id() == '' ) { // session_status() == PHP_SESSION_ACTIVE
+
+ require 'mAuth.php';
+
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = $attributes['http://wso2.org/claims/emailaddress'][0];
+
+ session_start();
+
+ $_SESSION['USER_TYPE'] = $USER_TYPE;
+ $_SESSION['USER_GOO'] = $USER_GOO;
+ $_SESSION['USER_EMAIL'] = $USER_EMAIL;
+ } else {
+
+ $USER_TYPE = $_SESSION['USER_TYPE'];
+ $USER_GOO = $_SESSION['USER_GOO'];
+ $USER_EMAIL = $_SESSION['USER_EMAIL'];
+
+ }
+
+} else {
+ //echo json_encode( array("result"=>"not logged in") );
+ exit();
+
+
+
+ /*$USER = 0;
+ $USER_NAME = 0;
+ $USER_PERS_ID = 0;
+ $USER_CONF_U_ID = 0;
+ $USER_PERS_EXT_ID = 0; */
+
+}
+
+$status = "ID:{$USER_GOO}
";
+$status .= "Email:{$USER_EMAIL}
";
+$status .= "Employee type:{$USER_TYPE}
";
+
+d_err($status);
+
+
+// Current academic year
+$AY = single_row_select("SELECT * FROM conf_academicyears WHERE label='2021-2022';",0, $c2);
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// Fetching a person's records
+//
+// 1. use their email to lookup PERSONNEL
+// - basic directory info
+//
+// 2. use their email to lookup CONF_USERS
+// - flex app, workshop signups
+//
+// 3. use conf_users.id to lookup in gavi_personnel_ext.c_users
+// - goo, depts, job title, image active
+//
+// 4. use personnel.id to lookup [webpages, welcomepages, etc]
+
+
+function user_record() { global $USER, $USER_EMAIL, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $LC_EMAIL = strtolower($USER_EMAIL);
+
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on, status FROM personnel WHERE LOWER(email)='{$LC_EMAIL}'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS conf_id, goo AS conf_goo, email AS conf_email, name AS conf_name, active AS conf_active FROM conf_users WHERE LOWER(email)='{$LC_EMAIL}'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, role, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, general_photo_release, etc, espanol, zoom, preferred_contact FROM gavi_personnel_ext WHERE personnel=' . $mega->id . ';'; // c_users={$mega->conf_id}';
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id . ';'; // '{$mega->id}'"; // personnel=1');
+
+ //p2($q4);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ $USER = $mega;
+
+}
+
+
+if ($USER_EMAIL) { user_record(); }
+
+
+
+
+// //
+// //
+// // LOG ENTRIES
+// //
+// //
+
+
+
+// Enter or get browser log entry
+function insert_or_get_browser($b) {
+ global $c2;
+ $BROWSER = ok($b);
+ $existing = does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'", 0, $c2);
+ if ($existing) {
+ return $existing;
+ } else {
+ $q = "INSERT INTO www_browsers (string) VALUES ('$BROWSER')";
+ single_row_select($q,0,$c2);
+ return does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'",0,$c2);
+ }
+ return 0; }
+
+
+// Log everything!
+function log_it($action) {
+ global $USER, $c2;
+
+ if (! $USER) {
+ $USER = array( 'name'=>'unknown', 'id'=>-1 ); }
+ $user_browser = $_SERVER['HTTP_USER_AGENT'];
+ $user_ip = $_SERVER['REMOTE_ADDR'];
+
+ $BROWSER = insert_or_get_browser($user_browser);
+ $ACTION = ok($action);
+
+ //$id = ok($_POST['id']);
+ $qupdate = "INSERT INTO gavi_logs SET action='{$action}', personnel_id='{$USER->id}', name='{$USER->name}', browser=$BROWSER, ip='$user_ip'";
+ single_row_select($qupdate,0,$c2);
+ return array("result"=>"success","action"=>"logged","query"=>$qupdate,"err"=>mysqli_error($c2));
+}
+
+
+
+
+
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function name_to_lc($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln;
+}
+function name_to_file($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln . ".jpg";
+}
+
+function check_dir_photo($fn,$ln) { global $USER;
+ $filename = name_to_file( $fn,$ln );
+ $path = '/gavilan.edu/staff/images_sm/' . $filename;
+ $dir_pic_exists = 0;
+ $dir_pic_path = 'images_sm/nobody.jpg';
+
+ if (file_exists($path)) {
+ $dir_pic_exists = 1;
+ $dir_pic_path = 'images_sm/' . $filename; }
+ $USER->dir_pic_exists = $dir_pic_exists;
+ $USER->dir_pic_path = $dir_pic_path;
+ return $dir_pic_exists;
+}
+
+check_dir_photo($USER->first_name, $USER->last_name);
+
+//
+//
+//
+////////////////////
+////////////////////
+
+
+
+//require __DIR__ . '/vendor/autoload.php';
+
+
+
+
+// Sample URL
+//
+// https://www.gavilan.edu/staff/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+//
+// https://intranet1.gavilan.edu/dir/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+
+
+
+
+
+/*
+
+
+NEXT STEPS:
+
+- figure out permissions system
+
+ - which means knowing dept / hierarchy
+
+ - which means cross referencing PERSONNEL and EXT and CONF_USERS.....
+
+
+
+## Permissions summary
+
+0. There is a list of table+column combos that users are allowed to edit.
+0.5 An activity "belongs" to the user who owns it (or created it).
+
+1. Simple cases:
+ - current user is updating their own (allowable) record. Allow.
+2. Superuser:
+ - current user is executive, hr, it, or root. (7,2,8,3) Allow.
+3. User is "Dept Editor" (4) and
+ -is updating a record belonging to someone in their dept. Allow.
+4. Harder: Updating events
+
+5. Updating attendance, approvals, or other restricted tables. Only FPLC (1) or superusers.
+
+*/
+
+
+function check_permission( $acting_user, $target_user, $table ) {
+
+ // TODO
+ return true;
+}
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Everyone. Basic dir. Include status==0 which is unpublished.
+function staff_dir() { global $c;
+ return multi_row_select('SELECT first_name,last_name,department,status, room,phone_number,email,web_on,id FROM personnel',1, $c);
+ // WHERE status IS null OR status=1
+}
+
+
+// Everyone. Basic dir
+function staff_dir_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) ORDER BY p.last_name LIMIT 5000',1, $c);
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list') {
+ echo staff_dir_ext(); exit(); }
+
+
+// Everyone. Directory info with DEPTS and TITLES added
+function staff_dir_full_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id ORDER BY p.last_name LIMIT 5000',1, $c);
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list2') { echo staff_dir_full_ext(); exit(); }
+
+
+
+
+
+// Courses in a semester
+function semester_sections() { global $c2;
+ return multi_row_select("SELECT * FROM `gavi_sections` s WHERE s.sem='fa21' ORDER BY s.teacher_id",1, $c2); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/semester') {
+ echo semester_sections(); exit(); }
+
+
+
+
+
+
+// STAFF + COURSES COMBINED
+function staff_dir_w_sections() { global $c;
+
+ // just one semesters sections?
+ $WHERE = "WHERE pgs.sem='fa21'";
+
+ // all recorded semesters
+ $WHERE = "";
+
+ return multi_row_select("SELECT p.first_name,p.last_name,p.department,p.status,p.staff_type, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent, GROUP_CONCAT(DISTINCT s.code SEPARATOR ', ') AS sections, COUNT(s.code) AS num_taught FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id LEFT JOIN ( SELECT * FROM PeterDB.gavi_sections pgs {$WHERE}) s ON e.id=s.teacher_id GROUP BY p.id ORDER BY p.last_name LIMIT 2500",0, $c);
+
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/staffsemester') {
+ echo json_encode(staff_dir_w_sections()); exit(); }
+
+
+
+
+// JOB TITLES LIST
+function job_titles() { global $c2;
+
+ return multi_row_select("SELECT DISTINCT id, name FROM gavi_titles ORDER BY name",1, $c2);
+
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='get/jobtitles') {
+ echo job_titles(); exit(); }
+
+
+
+
+
+//
+//
+//
+//
+//
+// Helper tables
+function sub_menus() { global $c2;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0, $c2);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0, $c2);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0, $c2);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0, $c2);
+
+ return json_encode( array( 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc ) );
+ exit();
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='menus') {
+ echo sub_menus(); exit(); }
+
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GAVILAN COLLEGE EVENTS
+//
+function get_events() {
+ global $c;
+ echo json_encode( multi_row_select("SELECT * FROM events WHERE date >= CURDATE() AND visible='1' ORDER BY time LIMIT 6;",0, $c));
+ // no exit cause it gets called in pages
+}
+if (isset($_GET['a']) && $_GET['a'] == 'get/gavevents') { get_events(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SEARCH AN INSTRUCTOR BY NAME IN SCHEDULE
+//
+function get_instructor() {
+ global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias='{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/name' ) { get_instructor(); }
+
+function get_instructor_fuzzy() {
+ global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias LIKE '{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/fuzzyname' ) { get_instructor_fuzzy(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// COURSE SECTIONS in a semester
+//
+function get_sections($semester) {
+ global $c;
+ $semester = ok($semester);
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,p.personnel AS personnel_id,p.use_dir_photo,p.dir_photo_path,d.last_name,d.first_name,d.phone_number,d.email,d.room,d.web_on,s.sem FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel WHERE sem='{$semester}' ORDER BY code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\w\w\d\d)$/', $_REQUEST['a'], $matches)) {
+ get_sections( $matches[1] ); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS by semester and crn only
+//
+function get_all_sections() {
+ global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.crn,s.sem,s.teacher_id,s.delivery,s.status,p.personnel AS personnel_id,d.last_name,d.first_name FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel ORDER BY sem,code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && $_GET['a'] == 'get/sections') { get_all_sections(); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS of a single INSTRUCTOR
+//
+// use their gavi_personnel_ext id
+//
+function get_instructor_sections($teacherid) {
+ global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.times,s.link,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.xlist_to,s.status,s.pnp,s.note,s.crn,s.sem,s.year FROM PeterDB.gavi_sections s WHERE s.teacher_id='{$teacherid}' ORDER BY s.sem,s.code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_instructor_sections( $matches[1] ); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// get COURSE SINGLE SECTION including welcome letter
+//
+// Housekeeping: if the gavi_welcome_letters row doesn't exist, we need to make it and populate it with the example text.
+//
+//
+function get_section($sem,$crn) {
+ global $c, $c2;
+ $sem = ok($sem);
+ $crn = ok($crn);
+ //echo $sem;
+ //echo $crn;
+
+
+ $sched_id = 0;
+
+ $sched_entry = single_row_select( "SELECT * FROM PeterDB.gavi_sections gs WHERE sem='{$sem}' AND crn='{$crn}';",0, $c2);
+ if ($sched_entry) {
+ $sched_id = $sched_entry['id'];
+ }
+ else {
+ echo "no row for that section
";
+ exit();
+ }
+
+ $wl_entry = single_row_select( "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id,w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.section_id='{$sched_id}';",0, $c2);
+ if ($wl_entry) {
+ echo json_encode($wl_entry);
+ exit();
+ }
+ else {
+ // no WL row for that section
+
+ $logaction = log_it("Creating default welcome letter for Semester: $sem CRN: $crn");
+
+ $default = json_decode( file_get_contents('default_welcome_letter.json') );
+ $default->what_expect = okh($default->what_expect);
+ $default->assessments = okh($default->assessments);
+ $default->textbook = okh($default->textbook);
+ $default->other_info = okh($default->other_info);
+ $default->introduction = okh($default->introduction);
+ $default->additional_resources = okh($default->additional_resources);
+
+ $q = "INSERT INTO PeterDB.gavi_welcome_letters (section_id,format,length,text_title,course_desc,what_expect,assessments,textbook,other_info,introduction,additional_resources) VALUES ('{$sched_id}', '', '', '', '', '{$default->what_expect}', '{$default->assessments}', '{$default->textbook}', '{$default->other_info}', '{$default->introduction}', '{$default->additional_resources}');";
+ $new_id = single_row_insert($q,0,$c2);
+
+ $q4 = "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id, w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.id=" . $new_id . ";";
+
+ $wl_entry = single_row_select( $q4, 0, $c2);
+
+ echo json_encode($wl_entry);
+ exit();
+ }
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/section\/(\w\w\d\d)\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_section( $matches[1], $matches[2] ); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS / WORKSHOPS / EVENTS
+//
+function get_sessions() {
+ global $c2, $AY;
+ return multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/sessions') { echo json_encode(get_sessions()); exit(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// LIST THE CURRENT USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+function get_user_sessions() {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER->conf_id}' OR sup.user='{$USER->conf_id}') AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/mysessions') { get_user_sessions(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ARBITRARY USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+// all years
+//
+function get_anyuser_sessions($usr) {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$usr}' OR sup.user='{$usr}') GROUP BY c.id ORDER BY c.starttime LIMIT 150;",0,$c2);
+ // AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME)
+
+ return $my_sessions; }
+if (isset($_GET['a']) && preg_match('/get\/sessions\/(\d+)$/', $_GET['a'], $matches)) { echo json_encode( get_anyuser_sessions($matches[1])); exit(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// get most RECENT LOGS
+//
+function get_recent_logs() {
+ global $c2, $USER;
+ $my_sessions = multi_row_select("SELECT * FROM `gavi_logs` ORDER BY `id` DESC LIMIT 150",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/logs') { get_recent_logs(); }
+
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIGNUP for (possibly overlapping time) session ...
+//
+function signup() {
+ global $c2, $AY, $USER;
+ preg_match('/signup\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $ts = date("Y-m-d H:i:s");
+ $logaction = log_it("Signed up for session: {$ses}");
+
+ $existing = does_exist(
+ "SELECT i.id FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.id={$ses} AND i.user={$USER->id_c_users}",0,$c2);
+ if ($existing) {
+ $qupdate = "UPDATE conf_signups SET session={$ses}, timestamp='{$ts}' WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($qupdate,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$qupdate,"err"=>mysqli_error($c2)));
+ } else {
+ $q = "INSERT INTO conf_signups (session,user,timestamp) VALUES ({$ses},{$USER->id_c_users},'{$ts}')";
+ single_row_select($q,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"inserted","logaction"=>$logaction, "ses"=>$_SESSION,"query"=>$q,"err"=>mysqli_error($c2)));
+ } exit(); }
+
+if (isset($_GET['a']) && preg_match('/signup\/(\d+)$/', $_GET['a'], $matches)) { signup(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// CANCEL a signup
+//
+function signdown() {
+ global $c2, $AY, $USER;
+ preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $q = "DELETE FROM conf_signups WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($q,1,$c2);
+ $logaction = log_it("Canceled signup for session: $ses");
+
+ echo json_encode( array("result"=>"success","action"=>"deleted","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches)) { signdown(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// NEW SESSION
+//
+function new_session() {
+ global $c2, $AY, $USER;
+
+
+ $title = ok($_POST['title']); $starttime = ok($_POST['starttime']);
+ $length = ok($_POST['length']); if ($length=='') { $length=1; }
+ $track = ok($_POST['track']); $gets_survey = ok($_POST['gets_survey']);
+ $is_flex_approved = ok($_POST['is_flex_approved']); $category = ok($_POST['title']);
+ if ($category=='') { $category=0; }
+ $author = ok($_POST['author']); if ($author=='') { $author=1; } // $USER->id_c_users; }
+ $is_custom = ok($_POST['is_custom']); $parent = ok($_POST['parent']);
+ $desc = okh($_POST['desc']); $location = okh($_POST['location']);
+ $recording = okh($_POST['recording']); $instructions = okh($_POST['instructions']);
+ $type = ok($_POST['type']); if ($type=='') { $type=19; }
+ $cal_uid = ok($_POST['cal_uid']);
+
+
+ $q = "INSERT INTO conf_sessions (`title`,`starttime`,`length`,`track`,`gets_survey`,`is_flex_approved`,`category`,`author`,`is_custom`,`parent`,`desc`,`location`,`recording`,`instructions`,`type`,`cal_uid`) VALUES ('{$title}', '{$starttime}', '{$length}', '{$track}', '{$gets_survey}', '{$is_flex_approved}', '{$category}', '{$author}', '{$is_custom}', '{$parent}', '{$desc}', '{$location}', '{$recording}', '{$instructions}', '{$type}', '{$cal_uid}');";
+ $ins = single_row_insert($q,0,$c2);
+ $logaction = log_it("created new session: {$title}");
+ echo json_encode( array("result"=>"success","action"=>"inserted new session","insert"=>$ins, "query"=>$q,"logaction"=>$logaction,"err"=>mysqli_error($c2)));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/newsession') { new_session(); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function set_sessioninfo() {
+ global $c, $c2, $AY, $USER;
+ $table = 'conf_sessions';
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if (! check_permission( $USER->id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, "UPDATE {$table} SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_select($q,0,$c1);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit(); }
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a name, lname, dept, phone, extension, email, type, room, status, user_id, or web_on
+function update_dir() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE personnel SET ");
+ //$q = substr($q, 0, -2);
+ $q .= "time_updated='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update personnel record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update') { update_dir(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update') { update_dir(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update goo, dept1/dept2, title, active, use_dir_photo
+function update_dir_ext() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->ext_id}";
+
+ #print_r($_REQUEST);
+
+ if (isset($_REQUEST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_REQUEST['id'], 'personnel_ext')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel_ext record of personnel id {$_REQUEST['id']}");
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel_ext record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE gavi_personnel_ext SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_select($q,0,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_xt') { update_dir_ext(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_xt') { update_dir_ext(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update person, officehours, title, picture, education, bio, courses, personal_page, changed
+function update_webpage() {
+ global $USER_PERS_ID, $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE person={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating bio webpage record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE person={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating bio webpage record");
+ }
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, "UPDATE webpages SET ");
+ $q .= "changed='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update bio webpage record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_web') { update_webpage(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a course section record
+function update_section($update=1) {
+ global $USER, $c2;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_sections SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_sections')) {
+ if ($update) {
+ $START = "UPDATE webpages SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating section id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new section");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_select($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/section') { update_section(0); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a WELCOME LETTER
+//
+function update_welcome_letter($update=1) {
+ global $USER, $c2;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_welcome_letters SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_welcome_letters')) {
+ if ($update) {
+ $START = "UPDATE gavi_welcome_letters SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating welcome letter id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new welcome letter");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_select($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/letter') { update_welcome_letter(0); }
+
+
+
+
+
+
+
+
+function handle_pic_upload() { global $USER;
+ $uploaddir = '/gavilan.edu/staff/uploads/';
+ $date = date('Ymd_Hi');
+ $uploadfile = $uploaddir . name_to_lc($USER->first_name,$USER->last_name) . "_" . $date . "_" . basename($_FILES['file']['name']);
+
+
+ echo '';
+ if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
+ echo "File is valid, and was successfully uploaded.\n";
+ } else {
+ echo "Possible file upload attack!\n";
+ }
+
+ echo 'Here is some more debugging info:';
+ print_r($_FILES);
+
+ print "";
+
+}
+//if (isset($_REQUEST['file'])) { handle_pic_upload(); }
+if (isset($_FILES['file'])) { handle_pic_upload(); }
+
+
+
+
+
+
+function get_a_user_by_pid($user_pid) { global $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE id='{$user_pid}'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='{$usr_dir['email']}'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = "SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel='{$mega->id}'";
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ // ?????
+
+
+ /* if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+ */
+
+ echo json_encode( $mega );
+ exit();
+
+}
+if (isset($_REQUEST['a']) && preg_match('/^get\/user\/(\d+)$/', $_REQUEST['a'], $matches)) { get_a_user_by_pid( $matches[1] ); }
+
+
+function get_a_user($user_email) { global $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $user_email . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='" . $user_email . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel=' . $mega->id;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ /*
+ if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+ */
+
+ return $mega;
+
+}
+
+
+function insert_c2($q) {
+ global $c2;
+ $result = single_row_insert($q,0,$c2);
+ return $result; }
+
+function merge_tables() { global $c;
+ $all_personnel = multi_row_select('SELECT first_name,last_name,department,room,phone_number,email,web_on,id FROM personnel WHERE status IS null OR status=1',0, $c);
+
+ $emails = __::pluck($all_personnel, 'email');
+ //echo json_encode($emails);
+ //exit();
+
+ //$emails = array_slice($emails, 0, 10);
+
+ $full = __::map( $emails, get_a_user );
+
+ //echo json_encode($full);
+
+ //$results = __::map( __::pluck($full,'aaqueryfix'), insert_c2);
+
+ //$results = __::pluck($full,'bbqueryfix');
+ //$results = __::map( $results, insert_c2);
+ echo json_encode( $full );
+ exit(); }
+if (isset($_REQUEST['merge'])) { merge_tables(); }
+
+
+
+/*
+echo basename(__FILE__);
+echo "
";
+echo basename($_SERVER["SCRIPT_FILENAME"]);
+*/
+
+
+
+
+//
+//
+// DO NOTHING IF FILE WAS INCLUDED
+//
+// OTHERWISE, RETURN BASIC USER INFO
+//
+//
+if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
+ // Called directly as api or in browser
+ //
+ if ($USER_EMAIL) {
+ // log it as an access
+ $logaction = log_it("accessed personnel record editor (in peters hhh tester folder)");
+
+ $USER->logresult = $logaction;
+
+ // Default case is current user data to be embedded in editor page
+ echo json_encode($USER);
+ exit();
+ } else {
+ echo json_encode( array("result"=>"not logged in") );
+ exit();
+ }
+}
+
+//
+// ELSE it was "included"...
+
+?>
diff --git a/ed_act.php b/ed_act.php
new file mode 100644
index 0000000..bfa060b
--- /dev/null
+++ b/ed_act.php
@@ -0,0 +1,78 @@
+
+
+
+
+ Activities & Events > Edit Activity";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+
+ $WHICH = 0;
+ if (isset($_REQUEST['w'])) { $WHICH = $_REQUEST['w']; }
+ else {
+ $MY_TITLE = "Create Activity";
+ }
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/flex.php b/flex.php
new file mode 100644
index 0000000..f666763
--- /dev/null
+++ b/flex.php
@@ -0,0 +1,81 @@
+
+
+
+
+ Staff > Activities";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+ if (isset($_GET['s'])) { $FOCUS = "'" . $_GET['s'] . "'"; }
+ else { $FOCUS = "'all'"; }
+
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+
+
+
+
+
+
+ choose academic year
+ dates / hours of flex days
+ add a conf, workshop, meeting
+ add, edit, display project
+ add, edit, display courses
+ show required hours
+ show total planned / actual hours
+ show timeline / deadlines / stage
+ ask achievements
+ icons for approved, clarification
+ show overall status
+
+
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/graf/X_simple_2.png b/graf/X_simple_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..b99d372ace62402fa76ecad7c9db25d9c9990cc9
GIT binary patch
literal 637
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVD!!mi71Ki^|4CM&(%vz$xlkv
ztH>$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?*?YcV$s`sd8Z$aFC*&lZ1TN&=GPTE
z6V5!etMcQCsATlNc;VG#kweWYzZGX5jeX*0ICHa7#F1hK_8q;SC6{$Q2>B$Gpcf;l
z^y6T8(f>pFH(#2@9DTyQ=U63wa_WQAEbEdu^CxCM^IXMP>Kx>qbvi?R(nXseyZGf)
zG80s^eIDCznL9tw3Hu!I8GQsqY?l^zn2~N9pXU`sJV5=iUnH
UUmZCo8I)=~UHx3vIVCg!0F}AnVgLXD
literal 0
HcmV?d00001
diff --git a/graf/bird_logo.png b/graf/bird_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..902850ee7684f55c8c8215d6978bb6d5410613f0
GIT binary patch
literal 21803
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
E0Ow4`W&i*H
literal 0
HcmV?d00001
diff --git a/graf/play_video.png b/graf/play_video.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8fe72de12e8658e92c239567c323749f071c7a2
GIT binary patch
literal 607
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVD!!mi71Ki^|4CM&(%vz$xlkv
ztH>$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?sRiUwD4?i>cB)k8HN|t-io+s;elv^NC1~rS
zUB}P-TkTSBsPS5qYrk{T+BWv@7I&{`)-KjB=zhFxr&@DYzQt+7hzES?mYi-cY8I}S
q{Bv60$KLhUls)fVznS@6h-F%-+M;wpQlkNsE<9cRT-G@yGywn;lGa}U
literal 0
HcmV?d00001
diff --git a/graf/profile_card.png b/graf/profile_card.png
new file mode 100644
index 0000000000000000000000000000000000000000..e8bd7dded63a79f3e59a3f161dbfb60306f37fa4
GIT binary patch
literal 544
zcmeAS@N?(olHy`uVBq!ia0vp^0zk~e!3HF=pW8MvFfe*&hD4M^`1)8S=jZArrsOB3
z>Q&?x0Oc7NZ0suv5|gu2OB9k)(=+pImEP~(ucVNfVyhHx>TBRz;GCL~=}}db8eHWU
zl3bOYY?-2DZ^va*VFffGH?<^Dp&~aYuh^=>Rtapb6_5=Q)>l#hD=EpgRdNJbs1V^B
zpx~Tel&WB=XQrEMXl$WiZmDNzYH49)qN8ABU}&aqV5x6tqHADiWngJ#V5k5EN_Jcd
zHbp6ERzWUqP|JWkTcwPWk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO_g)3fPY}N7#Vb!lH*
z(Edc-c;-xgc9$hHMUB6yf9PIvQaa;IG^d!d`0+JbN%N~0{xIz^T>9uvxLtNraqn!W
z4<`?49ON{Qxghp;c~^kY70ERlj!H?t*|6pw&mle0lD5UK_C@|UE%Dpy$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?DdP!QtG>KfW2>H%RHHS@l!XP
zjSn)1baCahZEQ5HYL?%3uj
zS%$}Nw{p!}>b{~i%)Nfqr(NIXXs=+K{!!|dTVQtT+S$v`RS3a-O5i1b*rUH%Z4G~rs%tR2TZ94(wh#V6iu{aq3H
t!`Z_5Te#i9-uvRyA2FZ#xA}x_R=ll4_Wg|&47Q-e`>w^Y;J%
literal 0
HcmV?d00001
diff --git a/graf/smile_happy_1.png b/graf/smile_happy_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..264cb2e2de03f63bf7bc0bb7ec1016fb533c5e5a
GIT binary patch
literal 674
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVD!!mi71Ki^|4CM&(%vz$xlkv
ztH>$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?N+EeXd`9QRHI-U)#;>{CjfEd0P%wyiGfL*M5e(
zMCCV)%X(9Ox2z744c#Yy{;$$4#r4{cS|#J}T(Lo)r~ILMI$k8^ia{eqmZ%utF&5tHf@>H4l06S8guYu(GVDV2mdK
II;Vst00`yzb^rhX
literal 0
HcmV?d00001
diff --git a/graf/smile_meh.png b/graf/smile_meh.png
new file mode 100644
index 0000000000000000000000000000000000000000..649bf6c59e396fdb2a72a81dec351a611c54f7f3
GIT binary patch
literal 657
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVD!!mi71Ki^|4CM&(%vz$xlkv
ztH>$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?D}Vc$hNyV4sc|EW0Y=RB=BqpQM!|MC^9j8%p&+^u`BYgqUFOVA6f;+t8%
z+hDzLo=~XH=ff4pbW5D>>2+QYn-lY?Jkq+Rd|T}Eh{m%O_o6Dec1BMws{DU-QdQ*q
zXp8g5;|_OTo%C&U+_c?OuiyA@TYX#WI>&O)udbhUcou0sid-$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?1n(Si(ovZppqRDk)mDr8BK_H^vJ!ls&)XNDv*ELT
z$|U#5*z6-W_m1{3{(sxv92WlLDthf$*V%d3SYpOZ|9!c53=DqB-~zH!Qhf6v+U@<#9TSIf>m((-%Av+nWIU;cOAPp#$HewFvlQtcg`
wjcXS)%4VL*S^qF7E9SWRnTIPkeY*XLKinwi`Qz93CV*0`r>mdKI;Vst09#xn^8f$<
literal 0
HcmV?d00001
diff --git a/graf/textlogo_120.gif b/graf/textlogo_120.gif
new file mode 100644
index 0000000000000000000000000000000000000000..c7aff864d36295cf8236bcc4ecf7c6cecd13b54d
GIT binary patch
literal 9725
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≷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
literal 0
HcmV?d00001
diff --git a/graf/time_1.png b/graf/time_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..55dba9fd524481b4f15fea7c285e45e01ac0726e
GIT binary patch
literal 658
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVD!!mi71Ki^|4CM&(%vz$xlkv
ztH>$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?Hg)pEQ0QjnvHq5naX
z;e^7ASDo4^}pJol_nwA^2Cd*+za)sEiw$wRII(b`Ca0ic%`0gBDW?4&nW*O@Z_nz
zOw5s=Jhm%Uy;r){KfJT7cdyU6H|8F-vmJNct$X2SQ8{J3;StXh20N|=s_9;~y>@GQ
r=GxSm+X9c|zYm&iXULzIK6gLkuhv+RTa#CJfRd7@tDnm{r-UW|^||jl
literal 0
HcmV?d00001
diff --git a/graf/time_2.png b/graf/time_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..d2ff5e6c455ae0c4eb715630a00cf3d18486f5da
GIT binary patch
literal 733
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4(FKVD!!mi71Ki^|4CM&(%vz$xlkv
ztH>$}=$7*jE%JCTFLXC?ut(XXe=|z2CiGNg*@ERw>-n*TA>HIW;5GqpB!1xXLdi
zxhgx^GDXSWj?1RP3TQxXYDuC(MQ%=Bu~mhw64+cTAR8pCucQE0Qj%?}lpi<;HsXMd|v6mX?lFzvFL5RwBI{CP=f74|4QDKnYWfKnBBZqPq(q@+9RdL$<5Kt%`MG4
zcJBBgzJ;~P#D()zxQL2kQ
zqB^^}P0y&`-}ChEPBq^Lsr8E{yRJAWyytMJ#C5}#vXTe3b?s$+aaWce&hq_dBkbC}
z;^^`ZZ`wUD<)SLCPgy^U99Om619{^pUp1&XE`9TA?jeRS=iOXuMGjkh{Sa#B_W$wjC#q>1JH2C0wAnm;XV@G)V|KFK
T;q;47L8;Qy)z4*}Q$iB}8T1`a
literal 0
HcmV?d00001
diff --git a/graf/video_2.png b/graf/video_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..6429e771616b0b94076871e78642b14c12fe68b8
GIT binary patch
literal 514
zcmeAS@N?(olHy`uVBq!ia0vp^0zk~e!3HF=pW8MvFfe*&hD4M^`1)8S=jZArrsOB3
z>Q&?x0Oc7NZ0suv5|gu2OB9k)(=+pImEP~(ucVNfVyhHx>TBRz;GCL~=}}db8eHWU
zl3bOYY?-2DZ^va*VFffGH?<^Dp&~aYuh^=>Rtapb6_5=Q)>l#hD=EpgRdNJbs1V^B
zpx~Tel&WB=XQrEMXl$WiZmDNzYH49)qN8ABU}&aqV5x6tqHADiWngJ#V5k5EN_Jcd
zHbp6ERzWUqP|JWkTcwPWk^(Dz{qpj1y>er{{GxPyLrY6beFGzXBO_g)3fz5B8t=M!N$?xF$=RkiSpPiQ)v%jw@)e%h`V0Bj
xo=$jO_x*$2kEgxPMfL0}6LK1iPbr_%FrSxR@9f(j=bqf$dvbDeaw7#Ho*wUe
zP!#3K59RKs`4bu&R=z{eiI}2Zn%pG&LpYSO_k$^VVI;C6*c7EIT(u}%M&FVn_eS#o
zOxe(Qmz+~0u>ukK2+KosF;c5hqJj1S7M%188F+^DCWOmT-T}*Nyn2IQZX&7>P2C^_
zu@~`k18ffHhq12!qAQrO_+sRb#ODAr)!iEm4hT!~gAIv-(f0cBeBPvD0t
z^1_B;GqTmF)x$7?Gfik8M2;F=BN&~+kJV`F$H8LghT(AH*-MCP;98`$Qx`9w)A2aS8XvNkRqe^GIui-2v+ya&I9_4pk3+
zRY6cd2O%-P(ZPxA7E)_a){dUXWN8Whr77F!8s1F}{YFAjUY-BLt?Q@jN9Zon_*{1M
z&VBh85@X!`R%bor2+HEDGMRhTkY2e`%FvJh8E2g|D3b0g)T&28jkN(+HX1GQCPaP57RtJRPwM`Zne6%5siYZi=Ka8;3c=yEljRAc
zH)PBeJFeZ%Z%i4kP#=25`ifU?`9l=_)NxFxSGf40fznf=e=?dco^YlPS_l1nz56SL
zp7D$hpM>4%hdj*QtpS9NlHef(QmSX?Pn
z$QQNu+O=c#mruaOl{qJRRx*Uq)^8{QaCoc0pmGu17
literal 0
HcmV?d00001
diff --git a/graf/zoom.png b/graf/zoom.png
new file mode 100644
index 0000000000000000000000000000000000000000..ddde386f68f3abc70d0e376fba31e056031001d4
GIT binary patch
literal 1764
zcmWlYc|6tm8pn?;Me@2#a;KYnrxa
z7N+)Obtgl6izJ!L4-5{GMZ(|S{1}DNwo5=ZQkRWS8dE4mv0K+&r74t6bXzM2GXMku
zp_o__Vs-uRPOykq&BPzYxSWcUR9HsCApw4wcvOKmy%4RUdlVu0I1vLH8#7-pw~X*Y
z*u^5h31^dWD-Vl8yywE^Aw1JCy#&r6JZM-DVo(6vSX|G>+6LTdNO^*N6$9QB
z7FKYVf$Vymh{o6~K8~Zd5AXW0BF5w*+DFhchQ0}`Z-6_AWf7VN!JkDJpKwdT+diU`
zj{rJ6pCO|T7yiQCe2mOsVxD-&!mmjvZAVZpVH1nUk;yiBvjz*
zDz2o%@e#_pU>ApG9@>X-Isp$#$cM0g2=C{(nt?AOusTuOj};MmM$s{X*Bv;Mgxm(i
zFmWm#qqCS@M%yr6a&Rsg&uih7h{6{5XQQqk^`DT+#?v?CD1!SLv1RDw6GAbnKajwQ
z^tf(YO^p1lk0J8&BCI}F=u|z0?c-N1s>2OOS0&}pq
zf{Jd?8{nP_pA2NZC+-!H8SIaE*+_CD7|o=h1ZRN!FT9?ig-2XUCAURnDJ)}fzlfBc
zaDGf$g@`JJUlyL$pmm7Y*nlN}Cy#Wnte?dhe+osR_V18rxRy&AUb5l1sj-8T`D}8e
z|Ebg4>#wPY3b*bXu`}D3k)_uZ?wNhH&{JCLM7Fg2gDvm7?2V