Changeset - a23c8e3ebe9e
[Not reviewed]
default
0 3 2
Nathan Brink (binki) - 15 years ago 2010-10-09 23:15:41
ohnobinki@ohnopublishing.net
Include support for cleaner URLs with example .htaccess and inc/config.inc files. Now, each time a new schedule is created, the user is redirected to that schedule's canonical URL in the same manner as pastebins do. Fixes bug 32 and bug 33.
5 files changed with 85 insertions and 6 deletions:
0 comments (0 inline, 0 general)
.htaccess.example
Show inline comments
 
new file 100644
 
# The following would be used to enable friendly pastebin-style
 
# URLs. To enable support for these URLs in slate_permutate, set
 
# $clean_urls = TRUE in inc/config.inc.
 

	
 
RewriteEngine on
 

	
 
# If you are serving this out of your home directory, there's a good chance you'll have to uncomment and edit one of the lines below:
 

	
 
# For http://csx.calvin.edu/slate_permutate:
 
# RewriteBase /slate_permutate
 

	
 
# For http://ohnopub.net/~ohnobinki/slate_permutate:
 
# RewriteBase /~ohnobinki/slate_permutate
 

	
 
RewriteCond %{QUERY_STRING} ^(.*)?$
 
RewriteRule ^([0-9]+)$ process.php?s=$1&%1 [L]
inc/class.page.php
Show inline comments
 
<?php
 

	
 
/**
 
 * Not sure if there's a better place for this... it'd be a pita to
 
 * make a new include file like doconfig.inc but maybe that'll make
 
 * sense soon.
 
 */
 
$clean_urls = FALSE;
 
$config_inc = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc';
 
if (file_exists($config_inc))
 
  require_once($config_inc);
 

	
 
/* Class for general page generation */
 
class page
 
{
 
  private $base_title = 'SlatePermutate';
 
  private $doctype = 'html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"';
 
  private $htmlargs = 'xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"';
 
  private $bodyargs = '';
 
  public $lastJobTable = '';
 
  private $pageGenTime = 0;
 

	
 
  /* whether or not to output valid XHTML */
 
  private $xhtml = FALSE;
 

	
 
  // Scripts and styles
 
  private $headCode = array();
 

	
 
  /* the inclusion of ga.js is augmented in __construct(). */
 
  private $trackingcode = '
 
			  <script type="text/javascript">
 
				var nathangPageTracker = _gat._getTracker("UA-17441156-1");
 
				nathangPageTracker._trackPageview();
 
				
 
				var ethanzPageTracker = _gat._getTracker("UA-2800455-1");
 
				ethanzPageTracker._trackPageview();
 
			</script>'; // Google analytics ga.js tracking code
 

	
 
  private $pagetitle = ''; // Title of page
 
  private $scripts = array(); // Scripts to include on page
 

	
 
  /* the current school. See get_school(). */
 
  private $school;
 

	
 
  public function __construct($ntitle, $nscripts = array(), $immediate = TRUE)
 
  {
 
    require_once('school.inc');
 

	
 
    // Scripts and styles available to include
 
    $this->headCode['jQuery'] = '<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript" />';
 
    $this->headCode['jQueryUI'] = '<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7/jquery-ui.min.js" type="text/javascript" /><link rel="stylesheet" href="styles/jqueryui.css" type="text/css" media="screen" charset="utf-8" />';
 
    $this->headCode['jValidate'] = '<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.pack.js"></script>';
 
    $this->headCode['schedInput'] = '<script type="text/javascript" src="scripts/scheduleInput.js"></script>';
 
    $this->headCode['outputPrintStyle'] = '<link rel="stylesheet" href="styles/print.css" type="text/css" media="screen" charset="utf-8" />';
 
    $this->headCode['outputStyle'] = '<link rel="stylesheet" href="styles/output.css" type="text/css" media="screen" charset="utf-8" />'; 
 
    $this->headCode['gliderHeadcode'] = '<link rel="stylesheet" href="styles/glider.css" type="text/css" media="screen" charset="utf-8" />'; 
 
   $this->headCode['uiTabsKeyboard'] = '<script type="text/javascript" src="scripts/uiTabsKeyboard.js"></script>'; 
 
   $this->pagetitle = $ntitle;
 
   $this->scripts = $nscripts;
 

	
 
   /* compliant browsers which care, such as gecko, explicitly request xhtml: */
 
   if(!empty($_SERVER['HTTP_ACCEPT'])
 
      && strpos($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml') !== FALSE
 
      || !strlen($_SERVER['HTTP_ACCEPT']) /* then the browser doesn't care :-) */)
 
     {
 
       $this->xhtml = TRUE;
 
       header('Content-type: application/xhtml+xml');
 
     }
 

	
 
   $ga_www = 'http://www.';
 
   if ($_SERVER['SERVER_PORT'] != 80)
 
     $ga_www = 'https://ssl.';
 
   $this->trackingcode = '<script type="text/javascript" src="' . $ga_www . 'google-analytics.com/ga.js" />' . "\n"
 
     . $this->trackingcode;
 

	
 
   page::session_start();
 
   self::session_start();
 
    if($immediate
 
       && $ntitle != "NOHEAD")
 
      $this->head();
 

	
 
    /* everything that needs sessions started to work: */
 

	
 
    $this->school = school_load_guess();
 
 }
 

	
 
  /**
 
   * \brief
 
   *   Adds some headcode to this page.
 
   *
 
   * \param $key
 
   *   The key to register this headcode under.
 
   * \param $code
 
   *   The actual code, such as a <script/>.
 
   * \param $enable
 
   *   Whether or not to enable this code while adding it.
 
   */
 
  public function headcode_add($key, $code, $enable = FALSE)
 
  {
 
    $this->headCode[$key] = $code;
 
    if ($enable)
 
      $this->scripts[] = $key;
 
  }
 

	
 
// Public functions/vars
 

	
 
  public function head(){
 
    $this->pageGenTime = round(microtime(), 3);
 

	
 
    if ($this->xhtml)
 
       echo '<?xml version="1.0" encoding="utf-8" ?>' . "\n";
 

	
 
    echo '<!DOCTYPE ' . $this->doctype . '>
 
	  <html ' . $this->htmlargs . '>
 
	  <head>
 
	    <title>' . $this->pagetitle . ' :: ' . $this->base_title . '</title>
 
           <link rel="stylesheet" href="styles/general.css" type="text/css" media="screen" charset="utf-8" />';
 

	
 
    // Write out all passed scripts
 
    foreach ($this->scripts as $i){
 
    	echo $this->headCode["$i"];
 
    }
 

	
 
    echo '</head>
 
	  <body '.$this->bodyargs.' ><div id="page">';
 
@@ -116,103 +126,109 @@ class page
 
  }
 

	
 
  private function top(){
 
    echo '<div id="header">
 

	
 
	    <div id="title">
 
              <h1><a href="index.php"><img src="images/slatepermutate.png" alt="SlatePermutate" class="noborder" /></a><br /></h1>
 
              <p><span id="subtitle">'.$this->pagetitle.'</span>
 
  	      <span id="menu">Profile: '.$this->school['name'].' <a href="input.php?selectschool=1">(change)</a></span>
 

	
 
              </p>
 

	
 

	
 

	
 
            </div>
 

	
 
	  </div>
 
          <div id="content">';
 
  }
 

	
 

	
 

	
 
  public function foot(){
 
    echo '</div> <!-- id="content" -->';
 
    $this->pageGenTime = round(microtime(), 3);
 
    echo '  <div id="footer">
 
          <h5>&copy; '. date('Y').' <a href="http://protofusion.org/~nathang/">Nathan Gelderloos</a><br />
 
            <a href="http://ethanzonca.com">Ethan Zonca</a>
 
          </h5>
 
        </div> <!-- id="footer" -->
 
      </div>';
 
    echo $this->trackingcode;
 
    echo '</body></html>';
 
  }
 

	
 
  public function secondsToCompound($seconds) {
 
      $ret = "";
 
      $hours = intval(intval($seconds) / 3600);
 
      $ret .= "$hours:";
 
      $minutes = bcmod((intval($seconds) / 60),60);
 
      $ret .= "$minutes:";
 
      $seconds = bcmod(intval($seconds),60);
 
      $ret .= "$seconds";
 
      return $ret;
 
  }
 

	
 
  public function showSavedScheds($session)
 
  {
 
    global $clean_urls;
 

	
 
    echo '<p>';
 
    if (isset($session['saved']) && count($session['saved']) > 0)
 
      {
 
	$process_php_s = 'process.php?s=';
 
	if ($clean_urls)
 
	  $process_php_s = '';
 

	
 
	echo '<div id="savedBox" ><h3>Saved Schedules:</h3>';
 
	foreach($session['saved'] as $key => $name)
 
	  {
 
	    echo '<a href="process.php?s=' . $key . '" title="View schedule #' . $key . '">#' . $key . "</a>:\n "
 
	    echo '<a href="' . $process_php_s . $key . '" title="View schedule #' . $key . '">#' . $key . "</a>:\n "
 
	      . htmlentities($name)
 
	      . ' <a href="input.php?s=' . $key . '">edit</a>'
 
	      . ' <a href="process.php?del=' . $key . '">delete</a>'
 
	      . "<br /><br />\n";
 
	  }
 
	echo '</div>';
 
      }
 
    echo '</p>';
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Display a list of schools the user might be from.
 
   * \param $linkto
 
   *   The to which a &school= or ?school= query string should be
 
   *   appended.
 
   */
 
  public function showSchools($linkto)
 
  {
 
    echo "<p>\n";
 
    echo "  <div id=\"schoolBox\">\n";
 
    echo school_list_html($this->school['id'], $linkto);
 
    echo "  </div> <!-- id=\"schoolBox\" -->\n";
 
    echo "</p>\n";
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Display school-specific instructions for using slate_permutate.
 
   */
 
  public function showSchoolInstructions()
 
  {
 
    echo "<div id=\"schoolInstructionsBox\">\n";
 
    echo school_instructions_html($this->school);
 
    echo "</div> <!-- id=\"schoolInstructionsBox\" -->\n";
 
  }
 

	
 
  /**
 
   * \brief
 
   *   Print out a vocative form of a student's identity. For example,
 
   *   Dearborn Christin Schoolers are called ``Knights'' as are
 
   *   Calvin College students.
 
   *
 
   * The third argument is used to determine whether or not this
 
   * address _needs_ to be printed out. For example, in some sentences
 
   * when addressing generic students, it makes no sense to say the
 
   * standard ``Welcome, student'' or ``Dear generic person, how do
 
   * you do today?''. If the third argument is false, we'll refrain
inc/config.inc.example
Show inline comments
 
new file 100644
 
<?php
 
/*
 
 * Copyright 2010 Nathan Phillip Brink <ohnobinki@ohnopublishing.net>
 
 *
 
 * This file is a part of slate_permutate.
 
 *
 
 * slate_permutate is free software: you can redistribute it and/or modify
 
 * it under the terms of the GNU Affero General Public License as published by
 
 * the Free Software Foundation, either version 3 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * slate_permutate is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU Affero General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU Affero General Public License
 
 * along with slate_permutate.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/**
 
 * \brief
 
 *   Use clean URLs for saved schedules. Default: FALSE.
 
 *
 
 * Before setting this to TRUE, make sure that you have read and
 
 * understood ../.htaccess.example and copied it to ../.htaccess .
 
 */
 
/* $clean_urls = FALSE; */
input.php
Show inline comments
 
@@ -3,97 +3,97 @@
 
include_once 'class.schedule.php';
 
include_once 'class.class.php';
 
include_once 'class.section.php';
 
include_once 'inc/class.page.php';
 
require_once('inc/schedule_store.inc');
 

	
 
$scripts = array('jQuery', 'jQueryUI', 'jValidate','schedInput');
 
$inputPage = new page('Scheduler', $scripts, FALSE);
 

	
 
$schedule_store = FALSE;
 
$sch = FALSE;
 
if (isset($_REQUEST['s']))
 
  {
 
    $schedule_store = schedule_store_init();
 
    $schedule_id = (int)$_REQUEST['s'];
 
    $sch = schedule_store_retrieve($schedule_store, $schedule_id);
 
  }
 

	
 
if ($sch)
 
{
 
  $nclasses = $sch->nclasses_get();
 
  $my_hc = '<script type="text/javascript">
 
var classNum = ' . $nclasses . ';
 
/* holds number of sections for each class */
 
var sectionsOfClass = new Array();
 
';
 
  for ($class_key = 0; $class_key < $nclasses; $class_key ++)
 
    $my_hc .= 'sectionsOfClass[' . $class_key . '] = ' . $sch->class_get($class_key)->getnsections() . ";\n";
 
  $my_hc .= '// </script>';
 
  $inputPage->headcode_add('scheduleInput', $my_hc, TRUE);
 
}
 
else
 
  $inputPage->headcode_add('schduleInput', '<script type="text/javascript">
 
var classNum = 0;
 
/* holds number of sections for each class */
 
var sectionsOfClass = Array();
 
// </script>', TRUE);
 

	
 
$inputPage->head();
 

	
 
/*
 
 * Force a student to choose a school or declare he's a generic
 
 * student before displaying the input form. To do this, we need
 
 * another variable in $_SESSION: $_SESSION['school_chosen'].
 
 */
 
$school = $inputPage->get_school();
 
if ($school && (!empty($_REQUEST['school']) || $school['id'] != 'default'))
 
  $_SESSION['school_chosen'] = TRUE;
 
if ($_REQUEST['selectschool'] == 1
 
if (!empty($_REQUEST['selectschool'])
 
    || $school['id'] == 'default' && !isset($_SESSION['school_chosen']))
 
  {
 
?>
 
<h2>School Selection</h2>
 
<p>
 
  Choose the school you attend from the list below. <b>If you cannot
 
  find your school</b>, you may proceed using
 
  the <a href="input.php?school=default">generic
 
  settings</a>.
 
</p>
 
<?php
 
    $inputPage->showSchools('input.php');
 
    $inputPage->foot();
 
    exit;
 
  }
 

	
 
$inputPage->showSavedScheds($_SESSION);
 
?>
 
<p>
 
  Welcome to SlatePermutate<?php $inputPage->addressStudent(', ', '',
 
  FALSE); ?>! To get started, enter in some of your
 
  classes, and add available sections for each class.
 
</p>
 
<form method="post" action="process.php" id="scheduleForm">
 
<br />
 
<label>Schedule Name</label><br />
 
<input id="scheduleName" style="margin-bottom: 1em;" class="defText required" type="text" size="25" title="(e.g., Spring <?php echo Date('Y'); ?>)" name="postData[name]"
 
<?php if ($sch) echo 'value="' . str_replace('"', '&quot;', $sch->getName()) . '"'; /*"*/ ?>
 
/>
 

	
 
<table id="container">
 
  <tr><td>
 
    <table id="jsrows">
 
	<!-- Header -->
 
	<tr>
 
		<td>Class</td>
 
		<td class="center" id="letterNumber">Section</td>
 
		<td class="center">Start Time</td>
 
		<td class="center">End Time</td>
 
		<td class="center">M</td>
 
		<td class="center">Tu</td>
 
		<td class="center">W</td>
 
		<td class="center">Th</td>
 
		<td class="center">F</td>
 
		<td class="center"></td>
 
		<td class="center"></td>
 
	</tr>
 
	<?php if ($sch) echo $sch->input_form_render(); ?>
process.php
Show inline comments
 
@@ -17,125 +17,144 @@ function arrayToDays($array, $mode = 'nu
 
		case 'long':
 
			$days = array('Monday','Tuesday','Wednesday','Thursday','Friday');
 
			break;
 
		case 'num':
 
			$days = array('1','2','3','4','5');
 
			break;
 
		default:
 
			$outString = 'Invalid mode passed to arrayToDays()!';
 
			return $outString;
 
	}
 
	if(count($array) > 1){
 
		for($i=0; $i<=4; $i++)	{
 
			if(isset($array[$i]) && $array[$i] == $key){
 
				$outString .= $days[$i];
 
				if($pretty)
 
					$outString .= ', ';
 
			}
 
		}
 
		if($pretty){
 
			$outString = substr($outString,0,strlen($outString) - 2); // Remove last comma and space
 
			$outString = substr($outString,0, strrpos( $outString, ' ')) . ' and' . substr($outString, strrpos( $outString, ' '), strlen($outString));
 
		}
 
	}
 
	else {
 
		for($i=0; $i<=4; $i++)
 
			if(isset($array[$i]))
 
				$outString = $days[$i];
 
	}
 
	return $outString;
 
}
 

	
 
function prettyTime($time){
 
	return substr($time,0,strlen($time)-2) . ":" . substr($time,strlen($time)-2, strlen($time));
 
}
 

	
 
/*
 
 * The below code relies on sessions being started already.
 
 */
 
page::session_start();
 

	
 
$DEBUG = FALSE;
 
if (isset($_GET['debug']))
 
  $DEBUG = $_GET['debug'];
 

	
 
$schedule_store = schedule_store_init();
 

	
 
if(!$DEBUG)
 
  {
 
    if(isset($_GET['s']))
 
    $s = FALSE;
 
    if (isset($_GET['s']))
 
      $s = $_GET['s'];
 

	
 
    if($s !== FALSE)
 
      {
 
	$savedSched = schedule_store_retrieve($schedule_store, $_GET['s']);
 
	$savedSched = schedule_store_retrieve($schedule_store, $s);
 
	if ($savedSched)
 
	  $savedSched->writeoutTables();
 
	else
 
	  Page::show_404('Unable to find a saved schedule with an ID of ' . $_GET['s'] . '.');
 
	  page::show_404('Unable to find a saved schedule with an ID of ' . $s . '.');
 
      }
 
    elseif(isset($_GET['del']))
 
      {
 
	/* Allow the user to delete schedules that he has stored in his session */
 
	if ($_SESSION['saved'][(int)$_GET['del']])
 
	  {
 
	    /* user owns this schedule ID */
 
	    schedule_store_delete($schedule_store, (int)$_GET['del']);
 
	    unset($_SESSION['saved'][(int)$_GET['del']]);
 
	  }
 

	
 
	header('Location: input.php');
 
	exit;
 
      }
 
    elseif (!isset($_POST['postData']))
 
      {
 
	header('Location: input.php');
 
	exit;
 
      }
 
    else
 
      {
 
	/*
 
	 * we probably have input from the user and should interpret
 
	 * it as a schedule to permutate. Then we should redirect the
 
	 * user to the canonical URL for that schedule.
 
	 */
 
		$allClasses = new Schedule($_POST['postData']['name']);
 
	
 
		foreach($_POST['postData'] as $class)
 
		{
 
		  /*
 
		   * Only add classes if the user added at least one
 
		   * section to the class. We know that $class['name']
 
		   * is not a section, so count() needs to be > 1 and
 
		   * we need to skip over 'name' in our loop.
 
		   */
 
			if(is_array($class) && count($class) > 1)
 
			{
 
				$allClasses->addClass($class['name']);
 
		
 
				foreach($class as $section)
 
				  /* Skip the section name, which isn't a section */
 
					if(is_array($section))
 
					{
 
				             $allClasses->addSection($class['name'], $section['letter'], $section['start'], $section['end'], arrayToDays($section['days']));
 
					}
 
			}
 
		}
 
		$allClasses->findPossibilities();
 
		if (!isset($_SESSION['saved']))
 
		  $_SESSION['saved'] = array();
 
		$schedule_id = schedule_store_store($schedule_store, $allClasses);
 
		if ($schedule_id != NULL)
 
		  $_SESSION['saved'][$schedule_id] = $allClasses->getName();
 

	
 
		$process_php_s = '';
 
		if (!$clean_urls)
 
		  $process_php_s = 'process.php?s=';
 
		header('Location: ' . $process_php_s . $schedule_id);
 
		exit;
 
		/*
 
		 * writeoutTables() needs to know $schedule_id, so it
 
		 * has to be called after we save the schedule. See
 
		 * schedule_store_store().
 
		 */
 
		$allClasses->writeoutTables();
 
      }
 
  }
 
else
 
  {
 
	echo '<pre>DEBUG OUTPUT: <br /><br />';
 
	foreach($_POST['postData'] as $class) {
 
		echo 'Class: ' . $class['name'] . '<br />';
 
		foreach($class as $section)
 
			if(is_array($section))
 
			{
 
				echo '---- Section that starts at ' . prettyTime($section['start']) . ' and ends at ' . prettyTime($section['end']) . '. This class meets on ';
 
				echo arrayToDays($section['days'],'long',true) . '.<br />';
 
			}
 
		echo '<br />';
 
	}
 
	echo '</pre>';
 

	
 

	
 
}
0 comments (0 inline, 0 general)