Associate races with events in a given timeframe.
authorCMDR furrycat <elite@furrycat.net>
Sun, 19 Jun 2016 07:43:08 +0000 (03:43 -0400)
committerCMDR furrycat <elite@furrycat.net>
Sun, 19 Jun 2016 07:45:27 +0000 (03:45 -0400)
entry.js
event.js [new file with mode: 0644]
lib/entry.php
lib/event.php [new file with mode: 0644]
lib/header.php
lib/race.php
propel/build/classes/buckyball/Event.php [new file with mode: 0644]
propel/build/classes/buckyball/Race.php
propel/schema.xml

index 48a7dc7..fe89209 100644 (file)
--- a/entry.js
+++ b/entry.js
@@ -589,6 +589,14 @@ function do_plot(table, canvas) {
   });
 }
 
+/* Check that entry is between the start and end times of the event. */
+function within_race_timeframe(time) {
+  if (! time) return false;
+  if (event_start_time != null && time < from_iso8601(event_start_time)) return false;
+  if (event_end_time != null && time < from_iso8601(event_end_time)) return false;
+  return true;
+}
+
 /* Check entry validity. */
 function validate(table, cloned) {
   var valid = true;
@@ -624,6 +632,10 @@ function validate(table, cloned) {
         input.setCustomValidity("");
         no_stations_visited = false;
         var time = from_iso8601(real_date(text));
+        if (! within_race_timeframe(time)) {
+          input.setCustomValidity('Outside race timeframe');
+          valid = false;
+        }
         if (i == first_row(table)) first_leg_time = time;
         else last_leg_time = time;
         if (time <= last_time) {
diff --git a/event.js b/event.js
new file mode 100644 (file)
index 0000000..24848e9
--- /dev/null
+++ b/event.js
@@ -0,0 +1,16 @@
+/* Document onload. */
+function loaded() {
+  var today = elite_date().replace(/..:..:..$/, '00:00:00');
+  for (var input of document.getElementsByTagName('input')) {
+    var m = input.name.match(/_time$/);
+    if (! m) continue;
+    input.autocomplete = 'off';
+    input.type = 'text';
+    input.pattern = '^(33[0-9][0-9]-(?:0[1-9]|1[0-2])-(?:[0-2][0-9]|3[01])) ((?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9])$';
+    input.placeholder = today;
+    input.maxLength = input.size = 19;
+    input.id = input.name;
+  }
+}
+
+document.onload = loaded();
index 881ffa4..5165597 100644 (file)
     $q = new CourseQuery;
     $q->joinWith("Course.Station");
     $q->joinWith("Course.Race");
+    $q->joinWith("Race.Event");
     $q->joinWith("Station.System");
     $q->findByRaceId($race_id);
     $course = $q->find();
     $race = $course[0]->getRace();
+    $event = $race->getEvent();
     $allotted_time = 0 + $race->getAllottedTime();
     $legs = array();
     $system_ids = array();
     echo "var distances = " . json_encode($distances) . ";\n";
     echo "var allotted_time = $allotted_time;\n";
     echo "var optional_waypoints = $waypoints;\n";
+    $event_start_time = $event->getStartTime();
+    if ($event_start_time) {
+      $event_start_time = real_time($event->getStartTime());
+      $event_end_time = real_time($event->getEndTime());
+      echo "var event_start_time = '$event_start_time';\n";
+      echo "var event_end_time = '$event_end_time';\n";
+    }
+    else {
+      echo "var event_start_time = null;\n";
+      echo "var event_end_time = null;\n";
+    }
     if ($entry) retrieve_entry($entry);
     if ($_POST['lap1station1']) {
       /*
diff --git a/lib/event.php b/lib/event.php
new file mode 100644 (file)
index 0000000..d8ba3f3
--- /dev/null
@@ -0,0 +1,82 @@
+<h2>Events</h2>
+<?php
+
+  function add_event($name, $start_time, $end_time) {
+    if (! $name) {
+      echo "<p>Missing event name!</p>\n";
+      return false;
+    }
+    if ($start_time || $end_time) {
+      $real_start_time = real_time($start_time);
+      if (is_null($real_start_time)) {
+        echo "<p>Invalid event start time!</p>\n";
+        return false;
+      }
+      $real_end_time = real_time($end_time);
+      if (is_null($real_end_time)) {
+        echo "<p>Invalid event end time!</p>\n";
+        return false;
+      }
+      if ($real_end_time < $real_start_time) {
+        echo "<p>Event end time is earlier than start time!</p>\n";
+        return false;
+      }
+    }
+    $event = new Event;
+    $event->setName($name);
+    if ($real_start_time) $event->setStartTime($real_start_time);
+    if ($real_end_time) $event->setEndTime($real_end_time);
+    try {
+      $event->save();
+      return true;
+    }
+    catch (Exception $e) {
+      echo "<p>Error adding event: " . $e->getMessage() . "</p>\n";
+    }
+    return false;
+  }
+
+  function show_event($event) {
+    echo "<h3>" . $event->getName() . "</h3>\n";
+
+    $rq = new RaceQuery;
+    $races = $rq->findByEventId($event->getId());
+    if (! count($races)) {
+      echo "<p>No races.</p>\n";
+      return;
+    }
+
+    foreach ($races as $race) {
+      echo "<p>" . $race->getTitleLink() . "</p>\n";
+    }
+  }
+
+  function module_event($action) {
+    if ($_POST['add_event']) {
+      if (add_event($_POST["name"], $_POST["start_time"], $_POST["end_time"])) unset($_POST);
+    }
+
+    $q = new EventQuery;
+    if ($action) $q->filterById($action);
+    $events = $q->find();
+    if (! count($events)) echo "<p>No events</p>\n";
+    echo "<div class=\"overflow\">\n";
+    foreach ($events as $event) {
+      if ($action) show_event($event);
+      else echo "<p>" . $event->getLink() . "</p>\n";
+    }
+    echo "</div>\n";
+
+    echo "<hr>\n";
+    form();
+    echo "<p>Add a new event: ";
+    input("name", $_POST['name']);
+    echo " from ";
+    input("start_time", $_POST['start_time']);
+    echo " to ";
+    input("end_time", $_POST['start_time']);
+    submit("add_event", "Add");
+    echo "</p>\n";
+    end_form();
+  }
+?>
index b31c7a7..3d0d0b2 100644 (file)
@@ -11,7 +11,7 @@
 <?php
   echo "<img src=\"$uri_root/images/logo.png\" alt=\"Buckyball Racing Club\" height=100 width=100>\n";
   $links = array();
-  foreach (array("competitor", "manufacturer", "hull", "ship", "system", "station", "race", "raikogram", "entry") as $what) {
+  foreach (array("competitor", "manufacturer", "hull", "ship", "system", "station", "event", "race", "raikogram", "entry") as $what) {
     $title = preg_replace('/y$/', 'ie', $what);
     $links[] =  "<span class=\"menu\"><a href=\"$uri_root/$what\">" . ucfirst($title) . "s</a></span>";
   }
index e8d5166..c17a3fe 100644 (file)
     return sqrt(($x * $x) + ($y * $y) + ($z * $z));
   }
 
-  function do_race($name, $allotted_time, $posted) {
+  function do_race($name, $event_id, $allotted_time, $posted) {
     $race = new Race;
     $race->setName($name);
+    $race->setEventId($event_id);
     if ($allotted_time) $race->setAllottedTime($allotted_time);
     $optional = $posted['optional'];
     if (is_int($optional) && $optional > 0) $race->setWaypoints($optional);
     return true;
   }
 
-  function add_race($name, $allotted_time) {
+  function add_race($name, $event_id, $allotted_time) {
     $sq = new StationQuery;
     $sq->joinWith('Station.System');
     $stations = $sq->orderBySystemId('desc')->orderByName()->find();
       $posted[$k] = $v;
     }
     if (count($posted)) {
-      if (do_race($name, $allotted_time, $posted)) return true;
+      if (! $event_id) {
+        echo "<p>Race not associated with an event.</p>\n";
+        return false;
+      }
+      if (do_race($name, $event_id, $allotted_time, $posted)) return true;
     }
 
     form();
   function module_race($action, $args) {
     global $race_colours;
 
-    if ($_POST['add_race']) {
-      if (add_race($_POST["name"], $_POST["allotted_time"])) unset($_POST);
+    if (array_key_exists("add_race", $_POST)) {
+      if (add_race($_POST["name"], $_POST["event_id"], $_POST["allotted_time"])) unset($_POST);
     }
 
     $methods = array(
         $white_fields[] = 'Raced';
         if ($allotted_time) $white_fields[] = 'Total';
         if ($race->getPrizes()) $orange_fields[] = 'Award';
-        entry_header($sort, $format, $type, $blue_fields, $white_fields, $orange_fields, $race->getName(), $race->getColours(true));
+        entry_header($sort, $format, $type, $blue_fields, $white_fields, $orange_fields, $race->getTitle(), $race->getColours(true));
         $n = $position = $rank = 1;
         $shown = 0;
         $ship_entries = array();
       echo "<p>Add stations before adding races.</p>\n";
       return;
     }
+    $eq = new EventQuery;
+    $events = $eq->orderByName()->find();
+    if (! count($events)) {
+      echo "<p>Add events before adding races.</p>\n";
+      return;
+    }
     form();
     echo "<p>Add a new race: ";
+    echo "<a href=\"$uri_root/event\">Event:</a> <select name=\"event_id\">";
+    option("event_id", 0, "");
+    foreach ($events as $event) {
+      $id = $event->getId();
+      $name = $event->getName();
+      option("event_id", $id, $name);
+    }
+    echo "</select>\n";
     input("name", $_POST["name"]);
     echo "allotted time (s): ";
     input("allotted_time", $_POST["allotted_time"]);
diff --git a/propel/build/classes/buckyball/Event.php b/propel/build/classes/buckyball/Event.php
new file mode 100644 (file)
index 0000000..0031c37
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+
+
+/**
+ * Skeleton subclass for representing a row from the 'event' table.
+ *
+ *
+ *
+ * You should add additional methods to this class to meet the
+ * application requirements.  This class will only be generated as
+ * long as it does not already exist in the output directory.
+ *
+ * @package    propel.generator.buckyball
+ */
+class Event extends BaseEvent
+{
+  private static $COLOURS = array('#808080', '#000000');
+
+  function Colours() {
+    return self::$COLOURS;
+  }
+
+  function getColours($strict = false) {
+    $colour1 = $this->getColour1();
+    $colour2 = $this->getColour2();
+    if ($strict && (! $colour1 || ! $colour2)) return null;
+    if (! $colour1) $colour1 = self::Colours()[0];
+    if (! $colour2) $colour2 = self::Colours()[1];
+    return array($colour1, $colour2);
+  }
+
+  function getFlag() {
+    $colours = $this->getColours(true);
+    if (! $colours) return '';
+    $style = "background-image: linear-gradient(-45deg, $colours[0] 0%, $colours[0] 50%, $colours[1] 50%, $colours[1] 100%);";
+    return "&nbsp;<span style=\"$style\">&nbsp;&nbsp;&nbsp;&nbsp;</span>";
+  }
+
+  function getLink() {
+    return parent::getLink() . $this->getFlag();
+  }
+}
index ac1da2c..7b03044 100644 (file)
@@ -24,12 +24,6 @@ class Race extends BaseRace
     'average_lap' => array('fastest average lap', 'ByAverageLap', 1 << 5)
   );
 
-  private static $COLOURS = array('#808080', '#000000');
-
-  function Colours() {
-    return self::$COLOURS;
-  }
-
   function Prizes() {
     return self::$PRIZES;
   }
@@ -91,23 +85,31 @@ class Race extends BaseRace
   }
 
   function getColours($strict = false) {
-    $colour1 = $this->getColour1();
-    $colour2 = $this->getColour2();
-    if ($strict && (! $colour1 || ! $colour2)) return null;
-    if (! $colour1) $colour1 = self::Colours()[0];
-    if (! $colour2) $colour2 = self::Colours()[1];
-    return array($colour1, $colour2);
+    return $this->getEvent()->getColours($strict);
   }
 
   function getFlag() {
-    $colours = $this->getColours(true);
-    if (! $colours) return '';
-    $style = "background-image: linear-gradient(-45deg, $colours[0] 0%, $colours[0] 50%, $colours[1] 50%, $colours[1] 100%);";
-    return "&nbsp;<span style=\"$style\">&nbsp;&nbsp;&nbsp;&nbsp;</span>";
+    return $this->getEvent()->getFlag();
+  }
+
+  function getName() {
+    $name = $this->getEvent()->getName();
+    $class = $this->getClassName();
+    if ($class) $name .= " $class";
+    return $name;
+  }
+
+  function getTitle() {
+    $class = $this->getClassName();
+    if ($class) return $class;
+    return $this->getEvent()->getName();
   }
 
   function getLink() {
     return parent::getLink() . $this->getFlag();
   }
 
+  function getTitleLink() {
+    return parent::getLink($this->getTitle()) . $this->getFlag();
+  }
 }
index 97fc9dd..b67d69b 100644 (file)
     </foreign-key>
   </table>
 
+  <!-- Event -->
+  <table name="event" phpName="Event" baseClass="BuckyballObject">
+    <vendor type="mysql">
+      <parameter name="Engine" value="InnoDB"/>
+      <parameter name="Charset" value="utf8"/>
+    </vendor>
+    <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
+    <column name="name" type="varchar" size="64" required="true"/>
+    <column name="start_time" type="timestamp" required="false"/>
+    <column name="end_time" type="timestamp" required="false"/>
+    <column name="colour1" type="char" size="7" required="false"/>
+    <column name="colour2" type="char" size="7" required="false"/>
+    <unique name="name">
+      <unique-column name="name"/>
+    </unique>
+  </table>
+
   <!-- Race -->
   <table name="race" phpName="Race" baseClass="BuckyballObject">
     <vendor type="mysql">
       <parameter name="Charset" value="utf8"/>
     </vendor>
     <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true"/>
-    <column name="name" type="varchar" size="64" required="true"/>
+    <column name="event_id" type="integer" required="true"/>
+    <column name="class_name" type="varchar" size="64" required="false"/>
     <column name="allotted_time" type="integer" required="false"/>
     <column name="waypoints" type="integer" required="false"/>
     <column name="prizes" type="integer" required="false"/>
-    <column name="colour1" type="char" size="7" required="false"/>
-    <column name="colour2" type="char" size="7" required="false"/>
     <unique name="name">
-      <unique-column name="name"/>
+      <unique-column name="event_id"/>
+      <unique-column name="class_name"/>
     </unique>
+    <foreign-key foreignTable="event" phpName="Event" refPhpName="Race">
+      <reference local="event_id" foreign="id"/>
+    </foreign-key>
   </table>
 
   <!-- Stations in race -->