From: Joey Schulze Date: Thu, 12 Sep 2019 14:47:19 +0000 (+0200) Subject: Touren application X-Git-Url: https://git.infodrom.org/?p=infodrom.org%2Ftouren.infodrom.org;a=commitdiff_plain;h=9526336e7880e7ef8da25e94113fd8fdeecd31d0 Touren application --- diff --git a/class/tour.class.php b/class/tour.class.php new file mode 100644 index 0000000..4bdaf31 --- /dev/null +++ b/class/tour.class.php @@ -0,0 +1,333 @@ +_is_admin)) { + $sql = sprintf("SELECT admin FROM tour_member WHERE tour_id = %d AND member_id = %d", + $this->id, $_SESSION['userid']); + $this->_is_admin = $this->db->fetchValue($sql); + } + + return $this->_is_admin; + } + + public function isPlanned() + { + if (is_null($this->_is_planned)) { + $sql = sprintf("SELECT key = 'plan' FROM tour_status WHERE id = %d", $this->data->tour_status_id); + $this->_is_planned = $this->db->fetchValue($sql); + } + + return $this->_is_planned; + } + + public function getBaseData() + { + $sql = <<id} +EOS; + + return $this->db->fetchObject($sql); + } + + public function toggleDateStatus($tour_date_id, $sys_user_id) + { + $date = new Tour_Date($tour_date_id); + + $sql =<<db->fetchObject($sql); + + if ($row === false) { + $sql =<<db->fetchValue($sql); + + $sql = "SELECT id FROM tour_date_status ORDER BY priority OFFSET 1 LIMIT 1"; + $status_id = $this->db->fetchValue($sql); + + $this->db->insertInto('tour_date_member', ['tour_date_id' => $tour_date_id, + 'tour_member_id' => $member_id, + 'tour_date_status_id' => $status_id]); + $status = new Tour_Date_Status($status_id); + if ($sys_user_id == $_SESSION['userid']) + Tour_Log::add($this->id(), sprintf("Verfügbarkeit am %s: %s", + $date->germanDate(), $status->get('name'))); + else { + $user = new Sys_User($sys_user_id); + Tour_Log::add($this->id(), sprintf("Verfügbarkeit von %s am %s: %s", + $user->get('name'), + $date->germanDate(), $status->get('name'))); + } + } else { + $sql = sprintf("SELECT id FROM tour_date_status WHERE id > %d ORDER BY priority LIMIT 1", + $row->tour_date_status_id); + $status_id = $this->db->fetchValue($sql); + + if ($status_id === false) { + $sql = "SELECT id FROM tour_date_status ORDER BY priority LIMIT 1"; + $status_id = $this->db->fetchValue($sql); + } + + $this->db->update('tour_date_member', ['tour_date_status_id' => $status_id], 'id = ' . $row->id); + + $status = new Tour_Date_Status($status_id); + $status_name = $status->get('name'); + if (!strlen($status_name)) + $status_name = 'n/a'; + + if ($sys_user_id == $_SESSION['userid']) { + Tour_Log::addRewrite($this->id(), + sprintf("Verfügbarkeit am %s: ", $date->germanDate()), + $status_name); + } else { + $user = new Sys_User($sys_user_id); + Tour_Log::addRewrite($this->id(), + sprintf("Verfügbarkeit von %s am %s: ", $user->get('name'), $date->germanDate()), + $status_name); + } + } + } + + public function inviteMember($sys_user_id) + { + if (!$this->isAdmin()) + throw new Exception("Keine Berechtigung zum Einladen"); + + $user = new Sys_User($sys_user_id); + + if (!$user->id()) + throw new Exception("User $sys_user_id not found"); + + $this->db->insertInto('tour_member', + ['tour_id' => $this->id(), + 'member_id' => $sys_user_id]); + + $myself = new Sys_User($_SESSION['userid']); + $request = Application::get()->getRequest(); + $url = sprintf('%s://%s%s', $request->getScheme(), $request->getHttpHost(), Application::get()->getBaseURL()); + $body = Template::render('tour/invitemail', + ['inviter' => $myself->get('name'), + 'tour_name' => $this->get('name'), + 'tour_year' => $this->get('year'), + 'tour_duration' => $this->get('duration'), + 'name' => $user->get('name'), + 'email' => $user->get('email'), + 'url' => $url, + ]); + $mail = new Mail(); + $mail->env_from(MAIL_FROM); + $mail->set('From', mb_encode_mimeheader(utf8_decode(sprintf("%s <%s>", MAIL_FROM_NAME, MAIL_FROM)),'latin1')); + $mail->set('To', $user->get('email')); + $mail->set('Subject', mb_encode_mimeheader(utf8_decode(sprintf("Einladung zur Tour %s", $this->get('name'))),'latin1')); + + $mail->send($body); + } + + public function getDates() + { + $sql = <<id()} + ORDER BY start_date +EOS; + + $list = $this->db->fetchObjectList($sql); + + foreach ($list as &$row) { + $dt = new DateTime($row->start_date); + $row->year = $dt->format('Y'); + $row->start_short = $dt->format('d.m.'); + $dt->add(new DateInterval('P'.$this->get('duration').'D')); + $row->end_short = $dt->format('d.m.'); + } + + return $list; + } + + public function getMembers($admin=null) + { + if (!is_null($admin)) + $cond_admin = ' AND tour_member.admin = ' . ($admin ? 'true' : 'false'); + $sql = <<id}{$cond_admin} + ORDER BY name +EOS; + + $list = $this->db->fetchObjectList($sql); + + return $list; + } + + public function getAvailability($user_id) + { + $list = $this->getDates(); + + if (!count($list)) return []; + + $ids = []; + foreach ($list as &$row) + $ids[] = $row->id; + $ids = join(',', $ids); + + $sql = <<db->fetchObjectList($sql) as $item) { + foreach ($list as &$row) { + if ($row->id == $item->tour_date_id) { + $row->status_key = $item->status_key; + $row->status_text = $item->status_text; + break; + } + } + } + + return $list; + } + + public function getAvailabilityMatrix() + { + $list = $this->getDates(); + + $ids = []; + foreach ($list as &$row) + $ids[] = $row->id; + $ids = join(',', $ids); + + $sql = <<db->fetchObjectList($sql) as $item) { + foreach ($list as &$row) { + if ($row->id == $item->tour_date_id) { + if (!is_array($row->avail)) + $row->avail = []; + + if (!in_array($item->member_id, $userlist)) { + $nick = ''; + foreach (explode(' ', $item->name) as $word) + $nick .= substr($word,0,1); + + $user = new stdClass(); + $user->nick = $nick; + $user->name = $item->name; + $userlist[$item->member_id] = $user; + } + + $av = new stdClass(); + $av->member_id = $item->member_id; + $av->nick = $userlist[$item->member_id]->nick; + $av->status_key = $item->status_key; + $av->status_text = $item->status_text; + + $row->avail[$item->member_id] = $av; + break; + } + } + } + + return ['user' => $userlist, 'list' => $list]; + } + + public function getNotes($all=false) + { + if ($all !== true) + $condition = ' AND tour_note_seen.id IS NULL'; + $sql = <<id} AND deleted = false{$condition} + ORDER BY tour_note.sys_edit DESC +EOS; + + $list = $this->db->fetchObjectList($sql); + + if (count($list)) { + foreach ($list as &$row) { + $row->note_html = Wiki::renderHTML($row->note); + if ($all !== true) + $this->db->insertInto('tour_note_seen', ['tour_note_id' => $row->id]); + } + } + + return $list; + } +} \ No newline at end of file diff --git a/class/tour_date.class.php b/class/tour_date.class.php new file mode 100644 index 0000000..2daa964 --- /dev/null +++ b/class/tour_date.class.php @@ -0,0 +1,19 @@ +data->start_date); + + if ($withYear) + return sprintf('%d.%d.%04d', $parts[2], $parts[1], $parts[0]); + else + return sprintf('%d.%d.', $parts[2], $parts[1]); + } +} \ No newline at end of file diff --git a/class/tour_date_status.class.php b/class/tour_date_status.class.php new file mode 100644 index 0000000..4d2c4c7 --- /dev/null +++ b/class/tour_date_status.class.php @@ -0,0 +1,9 @@ +addLog($tour_id, $text); + } + + public static function addRewrite($tour_id, $base_text, $appendix) + { + $log = new Tour_Log(); + $log->addRewriteLog($tour_id, $base_text, $appendix); + } + + protected function __construct($id=false) + { + parent::__construct('tour_log', $id); + } + + protected function addLog($tour_id, $text) + { + return $this->db->insertInto($this->table, + ['tour_id' => $tour_id, + 'logdate' => 'now()', + 'logtext' => $text]); + } + + protected function addRewriteLog($tour_id, $base_text, $appendix) + { + $sql = sprintf("SELECT id FROM %s WHERE tour_id = %d AND sys_user_id = %d AND logtext LIKE %s AND sys_edit > (now() - INTERVAL '%d seconds')", + $this->table, + $tour_id, + $_SESSION['userid'], + $this->db->quote($base_text . '%'), + $this->seconds); + $id = $this->db->fetchValue($sql); + + if ($id) { + return $this->db->update($this->table, + ['logtext' => $base_text . $appendix], + 'id='.$id); + } else { + return $this->db->insertInto($this->table, + ['tour_id' => $tour_id, + 'logdate' => 'now()', + 'logtext' => $base_text . $appendix]); + } + } +} \ No newline at end of file diff --git a/class/tour_status.class.php b/class/tour_status.class.php new file mode 100644 index 0000000..d3f97dc --- /dev/null +++ b/class/tour_status.class.php @@ -0,0 +1,9 @@ + 'Home']; $list[] = ['url' => $this->app->getBaseURL() . 'index/settings', 'title' => 'Einstellungen']; + if ($this->app->isAdmin()) { + $list[] = ['url' => $this->app->getBaseURL() . 'tour/newmember', + 'title' => 'Neuer Biker']; + $list[] = ['url' => $this->app->getBaseURL() . 'tour/new', + 'title' => 'Neue Tour']; + } $list[] = ['url' => $this->app->getBaseURL() . 'account/logout', 'title' => 'Logout']; diff --git a/controller/tourcontroller.class.php b/controller/tourcontroller.class.php new file mode 100644 index 0000000..91ff5da --- /dev/null +++ b/controller/tourcontroller.class.php @@ -0,0 +1,763 @@ + 'Home', + 'url' => Application::url()]; + $list[] = ['title' => 'Status', + 'url' => Application::url('tour', 'index', $this->tour)]; + if ($this->tour && $this->tour->isAdmin() && $this->tour->isPlanned()) + $list[] = ['title' => 'Neu einladen', + 'url' => Application::url('tour', 'invite', $this->tour)]; + if ($this->tour && $this->tour->isAdmin() && $this->tour->isPlanned()) + $list[] = ['title' => 'Termine', + 'url' => Application::url('tour', 'dates', $this->tour)]; + if ($this->tour && $this->tour->isPlanned()) + $list[] = ['title' => 'Planung', + 'url' => Application::url('tour', 'plan', $this->tour)]; + if ($this->tour && $this->tour->isAdmin()) + $list[] = ['title' => 'Matrix', + 'url' => Application::url('tour', 'matrix', $this->tour)]; + $list[] = ['title' => 'Notizen', + 'url' => Application::url('tour', 'notes', $this->tour)]; + $list[] = ['title' => 'Zwischenziele', + 'url' => Application::url('tour', 'pov', $this->tour)]; + if ($this->tour && $this->tour->isAdmin()) { + $list[] = ['title' => 'Administration', + 'url' => Application::url('tour', 'admin', $this->tour)]; + $list[] = ['title' => 'Logbuch', + 'url' => Application::url('tour', 'log', $this->tour)]; + } + + return $list; + } + + public function indexAction($request, $response) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + $data = $this->tour->getBaseData(); + $data->information_html = Wiki::renderHTML($data->information); + + Application::get()->addJavascriptCode("load_dates();"); + + $vars = array_merge(get_object_vars($data), + ['admin' => $this->tour->isAdmin(), + 'notes' => $this->tour->getNotes(), + 'members' => $this->tour->getMembers()]); + + $response->setData(Template::render('tour/index', $vars)); + } + + public function adminAction($request, $response) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + if (!$this->tour->isAdmin()) + throw new Exception("Keine Berechtigung"); + + $form = new Form('tourplan'); + $form->add(new FormElement('text', ['name' => 'name', + 'title' => 'Name', + 'help' => 'z.B. Sauerland 2019', + 'value' => $this->tour->get('name')])); + $form->add(new FormElement('text', ['name' => 'urlkey', + 'title' => 'URL-Key', + 'help' => 'Keine Leer- oder Sonderzeichen, z.B. sl2019', + 'value' => $this->tour->get('key')])); + $form->add(new FormElement('number', ['name' => 'year', + 'title' => 'Jahr', + 'min' => date('Y'), + 'max' => 2050, + 'value' => $this->tour->get('year')])); + $form->add(new FormElement('number', ['name' => 'duration', + 'title' => 'Dauer in Tagen', + 'min' => 1, + 'value' => $this->tour->get('duration')])); + + $sql = "SELECT id AS value, name AS text FROM tour_status ORDER BY priority"; + $form->add(new FormElement('select', ['name' => 'tour_status_id', + 'title' => 'Tour-Status', + 'selected' => $this->tour->get('tour_status_id'), + 'options' => $this->db->fetchObjectList($sql)])); + $options = []; + foreach ($this->tour->getDates() as $row) + $options[] = new Storage(['value' => $row->id, 'text' => $row->start_datum]); + + $form->add(new FormElement('select', ['name' => 'tour_date_id', + 'title' => 'Datum', + 'empty' => '-- bitte wählen --', + 'selected' => $this->tour->get('tour_date_id'), + 'options' => $options])); + + $form->add(new FormElement('textarea', ['name' => 'information', + 'title' => 'Tourinformationen', + 'help' => 'MoinMoin-typische Syntax erlaubt', + 'rows' => 5, + 'value' => $this->tour->get('information')])); + + $options = []; + foreach ($this->tour->getMembers(false) as $row) + $options[] = new Storage(['value' => $row->id, 'text' => $row->name]); + + if (count($options)) { + $adminform = new Form('touradmin'); + $adminform->add(new FormElement('select', ['name' => 'tour_member_id', + 'title' => 'Weiterer Tourleiter', + 'empty' => '-- Bitte wählen --', + 'options' => $options])); + $adminformstr = $adminform->toString(); + } else { + $adminformstr = ''; + } + + $adminlist = $this->tour->getMembers(true); + + $response->setData(Template::render('tour/admin', ['form' => $form->toString(), + 'adminform' => $adminformstr, + 'adminlist' => $adminlist])); + } + + public function ajaxAdmin($request, $response, $data) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + if (!$this->tour->isAdmin()) + throw new Exception("Keine Berechtigung"); + + foreach (['name', 'urlkey', 'year', 'duration'] as $name) + if (!strlen($data[$name])) + throw new Exception('Nicht alle Pflichtfelder ausgefüllt'); + + if (!preg_match('/^[a-zA-Z0-9_\.-]+$/', $data['urlkey'])) + throw new Exception('Sonderzeichen nicht im URL-Key erlaubt'); + + $status_plan = new Tour_Status('plan', 'key'); + + $ok = $this->db->update('tour', ['key' => $data['urlkey'], + 'name' => $data['name'], + 'year' => intval($data['year']), + 'duration' => intval($data['duration']), + 'tour_status_id' => $data['tour_status_id'], + 'tour_date_id' => strlen($data['tour_date_id']) ? intval($data['tour_date_id']) : NULL, + 'information' => strlen($data['information']) ? $data['information'] : NULL, + ], 'id='.$this->tour->id()); + + if (!$ok) + throw new Exception('Tour-Daten konnten nicht aktualisiert werden'); + } + + public function ajaxTouradmin($request, $response, $data) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + if (!$this->tour->isAdmin()) + throw new Exception("Keine Berechtigung"); + + $this->db->update('tour_member', ['admin' => true], 'id='.$data['tour_member_id']); + + $sql = sprintf("SELECT name FROM sys_user JOIN tour_member ON member_id = sys_user.id WHERE tour_member.id = %d", + $data['tour_member_id']); + Tour_Log::add($this->tour->id(), sprintf("%s als Leiter hinzugefügt", $this->db->fetchValue($sql))); + } + + public function ajaxDeladmin($request, $response, $data) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + if (!$this->tour->isAdmin()) + throw new Exception("Keine Berechtigung"); + + $this->db->update('tour_member', ['admin' => false], 'id='.$data['id']); + + $sql = sprintf("SELECT name FROM sys_user JOIN tour_member ON member_id = sys_user.id WHERE tour_member.id = %d", + $data['id']); + Tour_Log::add($this->tour->id(), sprintf("%s als Leiter gelöscht", $this->db->fetchValue($sql))); + } + + protected function formatDates() + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + $ok = new Tour_Date_Status('ok', 'key'); + $maybe = new Tour_Date_Status('maybe', 'key'); + $not = new Tour_Date_Status('nope', 'key'); + $sql = <<id()}) AS sum_ok, + (SELECT count(*) FROM tour_date_member WHERE tour_date_id = tour_date.id AND tour_date_status_id = {$maybe->id()}) AS sum_maybe, + (SELECT count(*) FROM tour_date_member WHERE tour_date_id = tour_date.id AND tour_date_status_id = {$not->id()}) AS sum_not, + start_date + FROM tour_date + WHERE tour_id = {$this->tour->id()} + ORDER BY start_date +EOS; + + $list = $this->db->fetchObjectList($sql); + + foreach ($list as &$row) { + $dt = new DateTime($row->start_date); + $row->year = $dt->format('Y'); + $row->start_short = $dt->format('d.m.'); + $dt->add(new DateInterval('P'.$this->tour->get('duration').'D')); + $row->end_short = $dt->format('d.m.'); + + if ($row->sum_ok >= 4) + $row->maybe = true; + elseif ($row->sum_ok >= 3 && $row->sum_not == 0) + $row->maybe = true; + else + $row->maybe = false; + } + + return Template::render('tour/datelist', ['tour_date_id' => $this->tour->get('tour_date_id'), + 'list' => $list]); + } + + public function ajaxDates($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + $response->setData(['table' => $this->formatDates()]); + } + + public function datesAction($request, $response) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + $plan = new Tour_Status('plan', 'key'); + + $formstr = ''; + if ($this->tour->isAdmin() && $this->tour->get('tour_status_id') == $plan->id()) { + $form = new Form('newdate'); + $form->setTitle('Neuer Termin'); + $form->add(new FormElement('date', ['name' => 'start_date', + 'placeholder' => '2019-01-12', + 'value' => ''])); + $formstr = '
'.$form->toString(); + } + + Application::get()->addJavascriptCode("load_dates();"); + + $response->setData(Template::render('tour/dates', ['admin' => $this->tour->isAdmin(), + 'form' => $formstr])); + } + + public function planAction($request, $response) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + $plan = new Tour_Status('plan', 'key'); + if ($this->tour->get('tour_status_id') != $plan->id()) + return $response->setLocation(Application::url('tour', 'index', $this->tour)); + + $list = $this->tour->getAvailability($_SESSION['userid']); + + $sql = sprintf("SELECT comment FROM tour_member WHERE tour_id = %d AND member_id = %d", + $this->tour->id(), $_SESSION['userid']); + $comment = $this->db->fetchValue($sql); + + $form = new Form('tourmember'); + $form->setTitle('Allgemeiner Status'); + $form->add(new FormElement('text', ['name' => 'comment', + 'help' => 'z.B. kein fahrbereites Motorrad', + 'value' => $comment])); + $formstr = '
'.$form->toString(); + + $response->setData(Template::render('tour/plan', ['list' => $list, + 'form' => $formstr])); + } + + public function ajaxTourmember($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + $ok = $this->db->update('tour_member', ['comment' => strlen($data['comment']) ? $data['comment'] : NULL], + sprintf('tour_id = %d AND member_id = %d', $this->tour->id(), $_SESSION['userid'])); + + if (strlen($data['comment'])) + Tour_Log::add($this->tour->id(), sprintf("Neuer Status %s", $data['comment'])); + else + Tour_Log::add($this->tour->id(), "Status gelöscht"); + } + + public function inviteAction($request, $response) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + $user = new Sys_User(); + $userlist = $user->getUserList($this->tour->id()); + + $response->setData(Template::render('tour/invite', ['list' => $userlist])); + } + + public function ajaxTogglestatus($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + if (empty($data['user'])) + $uid = $_SESSION['userid']; + elseif ($this->tour->isAdmin()) + $uid = $data['user']; + else + $uid = $_SESSION['userid']; + + $this->tour->toggleDateStatus($data['id'], $uid); + + $sql =<<setData($this->db->fetchAssoc($sql)); + } + + public function ajaxInvite($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + if (!$this->tour->isAdmin()) + throw new Exception("Keine Berechtigung"); + + $this->tour->inviteMember($data['sys_user_id']); + + $user = new Sys_User($data['sys_user_id']); + Tour_Log::add($this->tour->id(), sprintf("%s eingeladen", $user->get('name'))); + } + + public function ajaxNewdate($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + if (!$this->tour->isAdmin()) + throw new Exception("Keine Berechtigung"); + + $start_date = false; + + if (preg_match('/^(\d+)-(\d+)-(\d+)$/', $data['start_date'], $match)) + $start_date = $data['start_date']; + elseif (preg_match('/^(\d+).(\d+).(\d+)$/', $data['start_date'], $match)) + $start_date = sprintf('%d-%d-%d', $match[3], $match[2], $match[1]); + else + throw new Exception('Kein Datum angegeben'); + + $ok = $this->db->insertInto('tour_date', ['tour_id' => $this->tour->id(), + 'start_date' => $start_date]); + + if (!$ok) + $response->setError('Fehler beim Speichern'); + } + + protected function formatPovList() + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + $sql = <<tour->id()} + ORDER BY seqnum, destination +EOS; + + $list = $this->db->fetchObjectList($sql); + + foreach ($list as &$row) { + $dt = new DateTime($row->start_date); + $row->year = $dt->format('Y'); + $row->start_short = $dt->format('d.m.'); + $dt->add(new DateInterval('P'.$this->tour->get('duration').'D')); + $row->end_short = $dt->format('d.m.'); + } + + return Template::render('tour/povlist', ['is_planned' => $this->tour->isPlanned(), + 'list' => $list]); + } + + public function ajaxPov($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + $response->setData(['table' => $this->formatPovList()]); + } + + public function povAction($request, $response) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + $plan = new Tour_Status('plan', 'key'); + if ($this->tour->get('tour_status_id') == $plan->id()) { + $form = new Form('newpov'); + $form->setTitle('Neues Zwischenziel'); + $form->add(new FormElement('text', ['name' => 'destination', + 'value' => ''])); + $formstr = '
'.$form->toString(); + } + + Application::get()->addJavascriptCode("load_pov();"); + + $response->setData(Template::render('tour/pov', ['form' => $formstr])); + } + + public function ajaxNewpov($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + $plan = new Tour_Status('plan', 'key'); + if ($this->tour->get('tour_status_id') != $plan->id()) + throw new Exception("Nicht mehr in der Planungsphase"); + + $sql = sprintf("SELECT max(seqnum) FROM tour_pov WHERE tour_id = %d", + $this->tour->id()); + $max = intval($this->db->fetchValue($sql)); + + $ok = $this->db->insertInto('tour_pov', ['tour_id' => $this->tour->id(), + 'seqnum' => $max + 1, + 'destination' => $data['destination']]); + + if (!$ok) + $response->setError('Fehler beim Speichern'); + + Tour_Log::add($this->tour->id(), sprintf("Zwischenziel %s hinzugefügt", $data['destination'])); + } + + public function ajaxPovmove($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + $sql = sprintf("SELECT seqnum FROM tour_pov WHERE tour_id = %d AND id = %d", + $this->tour->id(), $data['pov']); + $seqnum = $this->db->fetchvalue($sql); + + if ($seqnum === false) + return $response->setError('Zwischenziel nicht gefunden'); + + if ($data['direction'] == 'up') { + $sql = sprintf("SELECT id,seqnum FROM tour_pov WHERE tour_id = %d AND seqnum < %d ORDER BY seqnum DESC LIMIT 1", + $this->tour->id(), $seqnum); + } elseif ($data['direction'] == 'down') { + $sql = sprintf("SELECT id,seqnum FROM tour_pov WHERE tour_id = %d AND seqnum > %d ORDER BY seqnum ASC LIMIT 1", + $this->tour->id(), $seqnum); + } else { + return $response->setError("Unknown direction"); + } + $other = $this->db->fetchObject($sql); + + $this->db->execute(sprintf("UPDATE tour_pov SET seqnum = %d WHERE id = %d", $seqnum, $other->id)); + $this->db->execute(sprintf("UPDATE tour_pov SET seqnum = %d WHERE id = %d", $other->seqnum, $data['pov'])); + + return $ok; + } + + public function ajaxPovdel($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + $sql = sprintf("SELECT destination FROM tour_pov WHERE tour_id = %d AND id = %d", + $this->tour->id(), $data['pov']); + $destination = $this->db->fetchvalue($sql); + + if ($destination === false) + return $response->setError('Zwischenziel nicht gefunden'); + + $ok = $this->db->execute(sprintf("DELETE FROM tour_pov WHERE id = %d", $data['pov'])); + + if (!$ok) + throw new Exception("Zwischenziel konne nicht gelöscht werden"); + + Tour_Log::add($this->tour->id(), sprintf("Zwischenziel %s gelöscht", $destination)); + } + + public function matrixAction($request, $response) + { + if (empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + $info = $this->tour->getAvailabilityMatrix(); + + $response->setData(Template::render('tour/matrix', ['is_planned' => $this->tour->isPlanned(), + 'user' => $info['user'], + 'list' => $info['list']])); + } + + public function newmemberAction($request, $response) + { + if (!$this->app->isAdmin() && empty($this->tour)) + return $response->setLocation($this->app->getBaseURL()); + + $form = new Form('newbiker'); + $form->setTitle('Neuer Biker'); + $form->add(new FormElement('text', ['name' => 'name', + 'title' => 'Name', + 'value' => ''])); + $form->add(new FormElement('text', ['name' => 'email', + 'title' => 'E-Mail', + 'value' => ''])); + $form->add(new FormElement('text', ['name' => 'mobile', + 'title' => 'Mobiltelefon', + 'help' => 'Nur sichtbar für Tour-Mitglieder', + 'placeholder' => '0150-1234567', + 'value' => ''])); + + $formstr = '
'.$form->toString(); + + if (!empty($this->tour)) + Application::get()->addJavascriptCode("load_dates();"); + + $response->setData($formstr); + } + + public function ajaxNewbiker($request, $response, $data) + { + if (!strlen($data['name'])) + throw new Exception("Name muß ausgfüllt werden"); + + if (!strlen($data['email'])) + throw new Exception("E-Mail muß ausgfüllt werden"); + + $ok = $this->db->insertInto('sys_user', ['name' => $data['name'], + 'email' => strtolower($data['email']), + 'active' => true, + 'passwd' => '', + 'mobile' => strlen($data['mobile']) ? $data['mobile'] : NULL]); + + if ($ok && !empty($this->tour)) { + $id = $this->db->lastInsertId(); + + $ok = $this->db->insertInto('tour_member', ['tour_id' => $this->tour->id(), + 'member_id' => $id]); + if (!$ok) + throw new Exception('Teilnehmer konnte nicht gesetzt werden'); + + $user = new Sys_User($id); + Tour_Log::add($this->tour->id(), sprintf("%s hinzugefügt", $user->get('name'))); + } + + return $ok; + } + + public function newAction($request, $response) + { + if (!$this->app->isAdmin()) + throw new Exception("Nur Administratoren können Touren anlegen"); + + $user = new Sys_User(); + $userlist = $user->getUserList(); + + $options = []; + foreach ($userlist as $row) + $options[] = new Storage(['value' => $row->id, 'text' => $row->name]); + + $form = new Form('newtour'); + $form->setTitle('Neue Tour anlegen'); + $form->add(new FormElement('text', ['name' => 'name', + 'title' => 'Name', + 'help' => 'z.B. Sauerland 2019', + 'value' => ''])); + $form->add(new FormElement('text', ['name' => 'urlkey', + 'title' => 'URL-Key', + 'help' => 'Keine Leer- oder Sonderzeichen, z.B. sl2019', + 'value' => ''])); + $form->add(new FormElement('number', ['name' => 'year', + 'title' => 'Jahr', + 'min' => date('Y'), + 'max' => 2050, + 'value' => ''])); + $form->add(new FormElement('number', ['name' => 'duration', + 'title' => 'Dauer', + 'min' => 1, + 'value' => ''])); + $form->add(new FormElement('select', ['name' => 'leader', + 'title' => 'Tourleiter', + 'empty' => '-- Bitte wählen --', + 'options' => $options])); + + $response->setData(Template::render('page/formpage', ['form' => $form->toString()])); + } + + public function ajaxNewtour($request, $response, $data) + { + if (!$this->app->isAdmin()) + throw new Exception("Nur Administratoren können Touren anlegen"); + + foreach (['name', 'urlkey', 'year', 'duration', 'leader'] as $name) + if (!strlen($data[$name])) + throw new Exception('Alle Felder müssen ausgefüllt sein'); + + if (!preg_match('/^[a-zA-Z0-9_\.-]+$/', $data['urlkey'])) + throw new Exception('Sonderzeichen nicht im URL-Key erlaubt'); + + $status_plan = new Tour_Status('plan', 'key'); + + $ok = $this->db->insertInto('tour', ['key' => $data['urlkey'], + 'name' => $data['name'], + 'year' => intval($data['year']), + 'duration' => intval($data['duration']), + 'tour_status_id' => $status_plan->id(), + ]); + + if (!$ok) + throw new Exception('Neue Tour konnte nicht gespeichert werden'); + + $tour_id = $this->db->lastInsertId(); + + Tour_Log::add($tour_id, sprintf("Tour %s angelegt", $data['name'])); + + $ok = $this->db->insertInto('tour_member', ['tour_id' => $tour_id, + 'admin' => true, + 'member_id' => $data['leader']]); + if (!$ok) + throw new Exception('Tourleiter konnte nicht gesetzt werden'); + + $user = new Sys_User($data['leader']); + Tour_Log::add($tour_id, sprintf("%s als Leiter hinzugefügt", $user->get('name'))); + } + + public function notesAction($request, $response) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + $list = $this->tour->getNotes(true); + + $response->setData(Template::render('tour/notes', ['list' => $list])); + } + + public function ajaxNotedel($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + $sql = sprintf("SELECT id FROM tour_note WHERE id = %d AND tour_id = %d AND sys_user_id = %d", + $data['id'], $this->tour->id(), $_SESSION['userid']); + + if (!$this->db->fetchValue($sql)) + return $response->setError('Notiz nicht gefunden'); + + $this->db->update('tour_note', ['deleted' => true], 'id='.intval($data['id'])); + } + + public function logAction($request, $response) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + if (!$this->tour->isAdmin()) + throw new Exception("Keine Berechtigung"); + + $sql = <<tour->id()} + ORDER BY logdate DESC, tour_log.sys_edit DESC +EOS; + $list = $this->db->fetchObjectList($sql); + + $response->setData(Template::render('tour/log', ['list' => $list])); + } + + public function notenewAction($request, $response) + { + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + $form = new Form('newnote'); + $form->setTitle('Neue Notiz'); + $form->setAction(Application::url('tour', 'preview', $this->tour)); + $form->setSecondButton('Preview'); + $form->setDescription(Template::render('wikisyntax', [])); + $form->add(new FormElement('textarea', ['name' => 'note', + 'title' => 'Text', + 'help' => 'MoinMoin-typische Syntax erlaubt', + 'rows' => 5, + 'value' => ''])); + + $response->setData(Template::render('page/formpage', ['form' => $form->toString()])); + } + + public function previewAction($request, $response) + { + if (!$request->isPost()) + throw new Exception("Only POST requests allowed here"); + + if (empty($this->tour)) + throw new Exception("Keine Tour angegeben"); + + $data = $request->getPost(); + + $form = new Form('newnote'); + $form->setTitle('Neue Notiz'); + $form->setAction(Application::url('tour', 'preview', $this->tour)); + $form->setSecondButton('Preview'); + $form->setDescription(Template::render('wikisyntax', [])); + $form->add(new FormElement('textarea', ['name' => 'note', + 'title' => 'Text', + 'help' => 'MoinMoin-typische Syntax erlaubt', + 'rows' => 5, + 'value' => $data['note']])); + + $preview = Template::render('tour/notepreview', ['text' => Wiki::renderHTML($data['note'])]); + $response->setData(Template::render('page/formpage', ['form' => $form->toString() + .$preview])); + } + + public function ajaxNotenew($request, $response, $data) + { + if (empty($this->tour)) + throw new Exception('Keine Tour ausgewählt'); + + if (!strlen($data['note'])) + throw new Exception('Kein Text angegeben'); + + $data = ['tour_id' => $this->tour->id(), + 'note' => trim($data['note'])]; + + $this->db->insertInto('tour_note', $data); + } + +} diff --git a/core/sys_user.class.php b/core/sys_user.class.php index c03b23a..5611726 100644 --- a/core/sys_user.class.php +++ b/core/sys_user.class.php @@ -21,4 +21,20 @@ class Sys_User extends DatabaseTable 'pwkey' => NULL, 'pwkey_valid' => NULL]); } + + public function getUserlist($tour_id=false) + { + $tour_id = intval($tour_id); + $sql =<< 1 AND active = true + ORDER by sys_user.name +EOS; + + return $this->db->fetchObjectList($sql); + } } diff --git a/templates/page/list.phtml b/templates/page/list.phtml new file mode 100644 index 0000000..5a647fc --- /dev/null +++ b/templates/page/list.phtml @@ -0,0 +1,13 @@ +
+ +
+
+ +
+
+ +
\ No newline at end of file diff --git a/templates/tour/admin.phtml b/templates/tour/admin.phtml new file mode 100644 index 0000000..b37bc9f --- /dev/null +++ b/templates/tour/admin.phtml @@ -0,0 +1,26 @@ +
+ +

Tourplanung

+ + + +
+

Tourleitung

+ + + +
+ +
+
+ + +
+
+ +
+
+ +
+ +
diff --git a/templates/tour/datelist.phtml b/templates/tour/datelist.phtml new file mode 100644 index 0000000..9d1f861 --- /dev/null +++ b/templates/tour/datelist.phtml @@ -0,0 +1,20 @@ + + + + + + + + + + + + id ? ' class="bg-ok"' : ($row->maybe ? ' class="bg-maybe"' : '') ?>> + + + + + + + +
Datum#ok#evtl.#nein
start_short; ?> – end_short; ?>year; ?>sum_ok; ?>sum_maybe; ?>sum_not; ?>
diff --git a/templates/tour/dates.phtml b/templates/tour/dates.phtml new file mode 100644 index 0000000..011d048 --- /dev/null +++ b/templates/tour/dates.phtml @@ -0,0 +1,9 @@ +
+ +

Termine

+ +
+ + + +
diff --git a/templates/tour/index.phtml b/templates/tour/index.phtml new file mode 100644 index 0000000..db4ee00 --- /dev/null +++ b/templates/tour/index.phtml @@ -0,0 +1,73 @@ +
+ +
+
+ +
+
+ + +
+
+
+ + name; ?> +
+ note_html; ?> +
datum; ?>
+
+ +
+
+
+ + + +

Termine

+
+ + + + +
+
+
+ +
+
+
+ + + +

Eingeladen sind

+ + + + + + + + + + + + + + + + + + +
NameMobilBemerkung
name; ?> <email?>>mobile; ?> + single_room ? 'EZ ' : ''; ?> + comment; ?> +
+ + +

Termine

+
+ + +
\ No newline at end of file diff --git a/templates/tour/invite.phtml b/templates/tour/invite.phtml new file mode 100644 index 0000000..3e7b95d --- /dev/null +++ b/templates/tour/invite.phtml @@ -0,0 +1,28 @@ +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+

Legende

+
+
+
+ +
diff --git a/templates/tour/invitemail.phtml b/templates/tour/invitemail.phtml new file mode 100644 index 0000000..37a6b8e --- /dev/null +++ b/templates/tour/invitemail.phtml @@ -0,0 +1,17 @@ +Moin ! + + lädt Dich ein, an der Motorrad-Tour teilzunehmen. +Die Tour ist für geplant und soll Tag(e) dauern. + +Die Tour wird online unter folgender Adresse geplant: + + <> + +Bitte melde Dich dort mit Deiner Mail Adresse "" an. +Über die Funktion "Passwort vergessen" setzt Du ein neues Passwort. + +Bitte hinterlege dort, zu welchen Zeiten Du an der Tour teilnehmen +kannst, zu welchen Zeiten Du nur evtl. Zeit hast und zu welchen Zeiten +Du ganz sicher nicht teilnehmen kannst. Diese Einstellungen kannst Du +jederzeit bearbeiten. + diff --git a/templates/tour/log.phtml b/templates/tour/log.phtml new file mode 100644 index 0000000..486a9a4 --- /dev/null +++ b/templates/tour/log.phtml @@ -0,0 +1,22 @@ +
+ +

Logbuch

+ + + + + + + + + + + + + + + + +
DatumText
date; ?>
name; ?>
logtext; ?>
+ +
\ No newline at end of file diff --git a/templates/tour/matrix.phtml b/templates/tour/matrix.phtml new file mode 100644 index 0000000..aeae3b6 --- /dev/null +++ b/templates/tour/matrix.phtml @@ -0,0 +1,53 @@ +
+ +

Terminmatrix

+ + + + + + + + + + + + + + + $item) { + if (array_key_exists($uid, $row->avail)) { + ?> + + + + + + + + +
Datumnick; ?>
start_short; ?> – end_short; ?>  
+ + +
+

Legende

+ +nick; ?> ist name; ?>
+ +
+ + + +

Die Terminfindung ist abgeschlossen.

+ + +
\ No newline at end of file diff --git a/templates/tour/notepreview.phtml b/templates/tour/notepreview.phtml new file mode 100644 index 0000000..f890186 --- /dev/null +++ b/templates/tour/notepreview.phtml @@ -0,0 +1,5 @@ +
+
+ +
+
diff --git a/templates/tour/notes.phtml b/templates/tour/notes.phtml new file mode 100644 index 0000000..b65a23b --- /dev/null +++ b/templates/tour/notes.phtml @@ -0,0 +1,35 @@ +
+ +
+

Alle Notizen

+ +
+ + + + + +
+
+
+ +
+ name; ?> +
+ note_html; ?> +
datum; ?>
+
+
+ +
+
+
+ + +
\ No newline at end of file diff --git a/templates/tour/plan.phtml b/templates/tour/plan.phtml new file mode 100644 index 0000000..16e8bc4 --- /dev/null +++ b/templates/tour/plan.phtml @@ -0,0 +1,28 @@ +
+ +

Terminplanung

+ + + + + + + + + + + + + + + + +
DatumMein Status
start_short; ?> – end_short; ?>year; ?>status_text; ?>
+ +
+Der Status wird durch Druck auf die Spalte geändert +
+ + + +
\ No newline at end of file diff --git a/templates/tour/pov.phtml b/templates/tour/pov.phtml new file mode 100644 index 0000000..6e474c9 --- /dev/null +++ b/templates/tour/pov.phtml @@ -0,0 +1,9 @@ +
+ +

Gewünschte Zwischenziele

+ +
+ + + +
diff --git a/templates/tour/povlist.phtml b/templates/tour/povlist.phtml new file mode 100644 index 0000000..d8fd071 --- /dev/null +++ b/templates/tour/povlist.phtml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + +
ZwischenzielAktionen
destination; ?> + + + +
diff --git a/touren.css b/touren.css index 5c5fe33..19c387f 100644 --- a/touren.css +++ b/touren.css @@ -2,6 +2,9 @@ margin-bottom: 1ex; background-color: #007bff; } +.navbar-brand span { + overflow: hidden; +} div.header { background-color: #007bff; color: white; @@ -50,7 +53,7 @@ div.loginform, div.lostpwform { } @media (max-width: 360px) { .onlynarrow { - display: block; + display: inline; } .onlywide { display: none; @@ -61,7 +64,7 @@ div.loginform, div.lostpwform { display: none; } .onlywide { - display: block; + display: inline; } } div.loginform h3, div.lostpwform h3 { @@ -76,3 +79,50 @@ div.lostpw { div.error h3 { border-bottom: 2px solid #ccc; } +div.tourlist .row button.btn, +div.invite .row button.btn { + width: 100%; + margin-bottom: 1ex; +} +.tour table#plan td:nth-child(2) { + text-align: center; + cursor: pointer; +} +.bg-unknown { + background-color: #FFFFFF; +} +.bg-ok { + background-color: #00FF00 !important; +} +.bg-maybe { + background-color: #FFFF00; +} +.bg-nope { + background-color: #FF0000; + color: white; +} +#datelist .table tbody tr.bg-maybe:nth-of-type(2n+1) { + background-color: #EEEE00 !important; +} +form[name="newdate"] .form-group { + float: left +} +form[name="newdate"] input { + width: 12em; + margin-right: 0.5em; +} +#povlist table button.btn { + font-weight: bold; +} +div.tour table#matrix td#date-status { + border-left: 1px solid white; +} +div.tour div.legende { + border-top: 2px solid #ccc; +} +div#note_del { + z-index: 50; +} +div#note_del.alert-warning { + border: 1px solid orange; +} diff --git a/touren.js b/touren.js index 0229de1..29d7fac 100644 --- a/touren.js +++ b/touren.js @@ -55,6 +55,39 @@ function ajax_request(route, parms, callback) }); } +function load_dates() +{ + ajax_request('tour/'+tour_key+'/dates', '', function(data){ + $('#datelist').html(data.table); + }); +} + +function load_pov() +{ + ajax_request('tour/'+tour_key+'/pov', '', function(data){ + $('#povlist').html(data.table); + + $('#povlist table button.btn-warning').click(function(e){ + ajax_request('tour/'+tour_key+'/povmove', + {'pov': $(this).parents('tr:first').attr('data-id'), + 'direction': $(this).attr('data-dir')}, + function(data){ + load_pov(); + }); + }); + $('#povlist table button.btn-warning:first').attr('disabled', 'disabled'); + $('#povlist table button.btn-warning:last').attr('disabled', 'disabled'); + + $('#povlist table button.btn-danger').click (function(e){ + ajax_request('tour/'+tour_key+'/povdel', + {'pov': $(this).parents('tr:first').attr('data-id')}, + function(data){ + load_pov(); + }); + }); + }); +} + $(function(){ $('input').on('keydown', function(e){ if (e.which === 13) @@ -101,4 +134,167 @@ $(function(){ setTimeout(function(){window.location.href = tour_base_url + 'index/index';}, 4000); }); }); + + // Create new tour + $('#newtour_save').click(function(e){ + if (!$('form[name="newtour"] #name').val().length || + !$('form[name="newtour"] #urlkey').val().length || + !$('form[name="newtour"] #year').val().length || + !$('form[name="newtour"] #duration').val().length || + !$('form[name="newtour"] #leader').val().length) + return show_message('Alle Felder müssen ausgefüllt sein', 'error'); + + if ($('form[name="newtour"] #urlkey').val().indexOf(' ') != -1) + return show_message('Leerzeichen nicht erlaubt im URL-Key', 'error'); + + ajax_request('tour/newtour', $('form[name="newtour"]').serialize(), function(data){ + show_message('Tour gespeichert', 'info'); + setTimeout(function(){window.location.href = tour_base_url + 'index/index';}, 4000); + }); + }); + + // Toggle status for date + $('div.tour table#plan td#date-status').click(function(e){ + var cell = $(this); + ajax_request('tour/'+tour_key+'/togglestatus', + 'id='+cell.attr('data-id'), + function(data){ + cell.attr('class', 'bg-'+data.status_key); + cell.text(data.status_text); + }); + }); + + // Toggle status for date in matrix + $('div.tour table#matrix td#date-toggle').click(function(e){ + var cell = $(this); + ajax_request('tour/'+tour_key+'/togglestatus', + {id: cell.attr('data-date-id'), + user: cell.attr('data-user-id')}, + function(data){ + cell.attr('class', 'bg-'+data.status_key); + }); + }); + + // Set tour member status + $('#tourmember_save').click(function(e){ + ajax_request('tour/'+tour_key+'/tourmember', $('form[name="tourmember"]').serialize(), function(data){ + show_message('Status gespeichert', 'info'); + }); + }); + + // Add new date to tour + $('#newdate_save').click(function(e){ + if (!$('#start_date').val().length) return; + ajax_request('tour/'+tour_key+'/newdate', $('form[name="newdate"]').serialize(), function(data){ + load_dates(); + show_message('Termin gespeichert', 'info'); + }); + }); + + // Add new POV + $('#newpov_save').click(function(e){ + if (!$('form[name="newpov"] #destination').val().length) return; + ajax_request('tour/'+tour_key+'/newpov', $('form[name="newpov"]').serialize(), function(data){ + load_pov(); + show_message('Zwischenziel gespeichert', 'info'); + $('form[name="newpov"] #destination').val(''); + }); + }); + + // Add new member to tour + $('div.invite button.btn-primary').click(function(e){ + var button = $(this); + if (!button.attr('data-id').length) return; + ajax_request('tour/'+tour_key+'/invite', + 'sys_user_id='+button.attr('data-id'), + function(data){ + button.removeClass('btn-primary').addClass('btn-success').attr('disabled', 'disabled'); + }); + }); + // Create new biker and add new member to tour + $('div.invite button.btn-warning').click(function(e){ + window.location.href = tour_base_url + 'tour/' + tour_key + '/newmember'; + }); + $('#newbiker_save').click(function(e){ + if (!$('form[name="newbiker"] #name').val().length || + !$('form[name="newbiker"] #email').val().length) + return show_message('Name und E-Mail müssen ausgefüllt sein', 'error'); + + if (typeof tour_key == 'string') + var backend = 'tour/'+tour_key+'/newbiker'; + else + var backend = 'tour/newbiker'; + ajax_request(backend, $('form[name="newbiker"]').serialize(), function(data){ + show_message('Biker gespeichert', 'info'); + if (typeof tour_key == 'string') + setTimeout(function(){window.location.href = tour_base_url + 'tour/' + tour_key + '/invite';}, 4000); + }); + }); + + // Notizen + $('.container.notes #btn_new').click(function(e){ + window.location.href = tour_base_url + 'tour/'+tour_key+'/notenew'; + }); + $('.container.notes .alert-dark .alert-primary').click(function(e){ + $('div#note_del').center().show(); + $('div#note_del button').attr('data-id', $(this).attr('data-id')); + }); + $('div#note_del button#btn_del').click(function(e){ + var note_id = $(this).attr('data-id'); + + ajax_request('tour/'+tour_key+'/notedel', 'id='+note_id, function(data){ + $('div#note_del').hide(); + $('div.note[data-id="'+note_id+'"]').hide(); + show_message('Notiz gelöscht', 'info'); + }); + }); + $('div#note_del button#btn_close').click(function(e){ + $('div#note_del').hide(); + }); + $('#newnote_save').click(function(e){ + var dest_url = tour_base_url + 'tour/'+tour_key+'/notes'; + if (!$('form[name="newnote"] #note').val().length) { + window.location.href = dest_url; + return; + } + + ajax_request('tour/'+tour_key+'/notenew', $('form[name="newnote"]').serialize(), function(data){ + show_message('Notiz gespeichert', 'info'); + setTimeout(function(){window.location.href = dest_url;}, 2000); + }); + }); + $('#newnote_second').click(function(e){ + if (!$('form[name="newnote"] #note').val().length) + return; + + $('form[name="newnote"]').submit(); + }); + + // Administration + $('#tourplan_save').click(function(e){ + if (!$('form[name="tourplan"] #name').val().length || + !$('form[name="tourplan"] #urlkey').val().length || + !$('form[name="tourplan"] #year').val().length || + !$('form[name="tourplan"] #duration').val().length) + return show_message('Name, Key, Jahr und Dauer müssen ausgefüllt sein', 'error'); + + ajax_request('tour/'+tour_key+'/admin', $('form[name="tourplan"]').serialize(), function(data){ + show_message('Informationen gespeichert', 'info'); + }); + }); + $('#touradmin_save').click(function(e){ + if (!$('form[name="touradmin"] #tour_member_id').val().length) return; + + ajax_request('tour/'+tour_key+'/touradmin', $('form[name="touradmin"]').serialize(), function(data){ + show_message('Tourleiter gesetzt', 'info'); + $('form[name="touradmin"] #tour_member_id option[value="'+$('form[name="touradmin"] #tour_member_id').val()+'"]').remove(); + }); + }); + $('#touradmin .btn-danger').click(function(e){ + var button = $(this); + ajax_request('tour/'+tour_key+'/deladmin', 'id='+button.attr('data-id'), function(data){ + show_message('Tourleiter gelöscht', 'info'); + button.parents('div.form-row:first').hide(); + }); + }); });