Index: gobbler/install.php
===================================================================
--- gobbler/install.php	(revision 392)
+++ gobbler/install.php	(working copy)
@@ -150,6 +150,26 @@
 		track VARCHAR(255) REFERENCES Track(name),
 		PRIMARY KEY(username, tag, artist, album, track))");
 
+	$mdb2->query("CREATE TABLE Events(
+		eventID INT UNSIGNED,
+		event VARCHAR(255),
+		location VARCHAR(255),
+		date DATE,
+		time TIME,
+		description TEXT,
+		PRIMARY KEY(eventID, event),
+		FULLTEXT(event, location, description))");
+		
+	$mdb2->query("CREATE TABLE Event_Artist(
+		eventID INT UNSIGNED REFERENCES Events(eventID),
+		artist VARCHAR(255) REFERENCES Artist(name),
+		PRIMARY KEY(eventID, artist))");
+		
+	$mdb2->query("CREATE TABLE Event_Users(
+		eventID INT UNSIGNED REFERENCES Events(eventID),
+		username VARCHAR(255) REFERENCES Users(username),
+		PRIMARY KEY(eventID, username))");
+
 	// Test user configuration
 	$res = $mdb2->query("INSERT INTO Users
 		(username, password, created)
Index: web/themes/librefm/librefm.css
===================================================================
--- web/themes/librefm/librefm.css	(revision 392)
+++ web/themes/librefm/librefm.css	(working copy)
@@ -14,7 +14,7 @@
 
 #login a{ color: yellow !important; }
 
-#hd li{ display: inline; font-size: 21px; text-transform: lowercase; font-weight: bold; margin-right: 20px;}
+#hd li{ display: inline; font-size: 18px; text-transform: lowercase; font-weight: bold; margin-right: 12px;}
 
 #banner { height: 345px; position: relative;}
 
Index: web/themes/librefm/templates/events.tpl
===================================================================
--- web/themes/librefm/templates/events.tpl	(revision 0)
+++ web/themes/librefm/templates/events.tpl	(revision 0)
@@ -0,0 +1,95 @@
+{include file='header.tpl'}
+{if ($add)}
+	<h2>Add a new event</h2>
+	<form action='event.php' method='post'>
+		<fieldset>
+			<label for='event'>Event name:<span>&nbsp;</span></label>
+			<input id='event' name='event' type='text' value='' maxlength='255' /><br />
+
+			<label for='location'>Location:<span>&nbsp;</span></label>
+			<input id='location' name='location' type='text' value=''/><br />
+			
+			Date:<span>&nbsp;</span>
+			<select name="month">
+				<option> - Month - </option>
+				<option value="01">January</option>
+				<option value="02">Febuary</option>
+				<option value="03">March</option>
+				<option value="04">April</option>
+				<option value="05">May</option>
+				<option value="06">June</option>
+				<option value="07">July</option>
+				<option value="08">August</option>
+				<option value="09">September</option>
+				<option value="10">October</option>
+				<option value="11">November</option>
+				<option value="12">December</option>
+			</select>
+
+			<select name="day">
+				<option> - Day - </option>
+				<option value="1">1</option>
+				<option value="2">2</option>
+				<option value="3">3</option>
+				<option value="4">4</option>
+				<option value="5">5</option>
+				<option value="6">6</option>
+				<option value="7">7</option>
+				<option value="8">8</option>
+				<option value="9">9</option>
+				<option value="10">10</option>
+				<option value="11">11</option>
+				<option value="12">12</option>
+				<option value="13">13</option>
+				<option value="14">14</option>
+				<option value="15">15</option>
+				<option value="16">16</option>
+				<option value="17">17</option>
+				<option value="18">18</option>
+				<option value="19">19</option>
+				<option value="20">20</option>
+				<option value="21">21</option>
+				<option value="22">22</option>
+				<option value="23">23</option>
+				<option value="24">24</option>
+				<option value="25">25</option>
+				<option value="26">26</option>
+				<option value="27">27</option>
+				<option value="28">28</option>
+				<option value="29">29</option>
+				<option value="30">30</option>
+				<option value="31">31</option>
+			</select>
+
+			<select name="year">
+				<option> - Year - </option>
+				<option value="2009">2009</option>
+				<option value="2010">2010</option>
+			</select><br />
+			
+			<label for='artist'>Artist(s):<span>&nbsp;</span></label>
+			<input id='artist' name='artist' type='text' value=''/><br />
+			
+			Description:<span>&nbsp;</span><br />
+			<textarea id='description' name='description' rows=3 columns=10></textarea><br />
+
+			<input type='submit' name='login' value='Add event' />
+		</fieldset>
+	</form>
+{else}
+<h2>Upcoming events</h2>
+
+<div id="events">
+{if ($logged_in)}
+  <span style="float:right"><a href="{$base_url}/event.php?add">Add Event</a></span>
+{/if}  
+  {section name=i loop=$events}
+  <h3>{$events[i].event}</h3>
+  <p>{$events[i].date}</p>
+  <p>{$events[i].description}</p>
+  {/section}
+  <span style="float:right"><a href="{$base_url}/event.php?p={$p+1}">Next &gt&gt</a></span>
+</div>
+{/if}
+<div class="cleaner">&nbsp;</div>
+{include file='footer.tpl'}
Index: web/themes/librefm/templates/menu.tpl
===================================================================
--- web/themes/librefm/templates/menu.tpl	(revision 392)
+++ web/themes/librefm/templates/menu.tpl	(working copy)
@@ -13,4 +13,5 @@
 {/if}
         <li>Explore:</li>
         <li><a href="{$base_url}/explore.php?mode=artists">Artists</a></li>
+        <li><a href="{$base_url}/explore.php?mode=events">Events</a></li>
   </ul>
Index: web/themes/librefm/templates/explore-events.tpl
===================================================================
--- web/themes/librefm/templates/explore-events.tpl	(revision 0)
+++ web/themes/librefm/templates/explore-events.tpl	(revision 0)
@@ -0,0 +1,16 @@
+{include file='header.tpl'}
+
+<h2>Explore upcoming events</h2>
+
+<div id="events">
+{if ($logged_in)}
+  <span style="float:right"><a href="{$base_url}/event.php?add">Add Event</a></span>
+{/if}  
+  {section name=i loop=$events}
+  <h3>{$events[i].event}</h3>
+  <p>{$events[i].date}</p>
+  <p>{$events[i].description}</p>
+  {/section}
+</div>
+<div class="cleaner">&nbsp;</div>
+{include file='footer.tpl'}
Index: web/explore.php
===================================================================
--- web/explore.php	(revision 392)
+++ web/explore.php	(working copy)
@@ -24,11 +24,22 @@
 require_once("templating.php");
 require_once("data/Server.php");
 
-$aTopArtists = Server::getTopArtists(20);
-if (!PEAR::isError ($aTopArtists)) {
-    $smarty->assign("topartists", $aTopArtists);
+if ($_GET['mode'] == 'events') {
+	$aComingEvents = Server::getComingEvents(5);
+	if (!PEAR::isError ($aComingEvents)) {
+   	 $smarty->assign("events", $aComingEvents);
+	}
+	$smarty->display("explore-events.tpl");
 }
-$smarty->assign("explore", true);
-$smarty->display("explore-artists.tpl");
+else {
+	$aTopArtists = Server::getTopArtists(20);
+	if (!PEAR::isError ($aTopArtists)) {
+		  $smarty->assign("topartists", $aTopArtists);
+	}
+	$smarty->display("explore-artists.tpl");
+}
 
+//$smarty->assign("explore", true);
+
+
 ?>
Index: web/event.php
===================================================================
--- web/event.php	(revision 0)
+++ web/event.php	(revision 0)
@@ -0,0 +1,78 @@
+<?php
+
+/* Libre.fm -- a free network service for sharing your music listening habits
+
+   Copyright (C) 2009 Libre.fm Project
+
+   This program 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.
+
+   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+require_once("database.php");
+require_once("templating.php");
+//require_once("data/Event.php");
+require_once("data/Server.php");
+
+if (isset($_POST['event'])) {
+	$errors = "";
+	$event = $_POST['event'];
+	$location = $_POST['location'];
+	$day = $_POST['day'];
+	$month = $_POST['month'];
+	$year = $_POST['year'];
+	$artist = $_POST['artist'];
+	$description = $_POST['description'];
+	
+	//Basic validation
+	if(empty($location)) {
+		$errors .= "You must enter a location.<br />";
+	}
+	if(empty($day) || empty($month) || empty($year)) {
+		$errors .= "You must enter a date.<br />";
+	}
+	
+	$date = date($year . '-' . $month . '-' . $day);
+	
+	if(empty($errors)) {
+		$mdb2->query("INSERT INTO Events (event, location, date, time, description) Values("
+			. $mdb2->quote($event, "text") . ", "
+			. $mdb2->quote($location, "text") . ", "
+			. $mdb2->quote($date, "date") . ", 0,"
+//			. $mdb2->quote($time,  . ", "
+			. $mdb2->quote($description, "text") . ")");
+					
+	}
+	
+}
+
+if (isset($_GET['add'])) {
+	$smarty->assign("add", true);
+}
+
+else {
+	if (isset($_GET['p'])) {
+		$p = $_GET['p'];
+	}
+	else $p = 0;
+	$aComingEvents = Server::getComingEvents(5, $p);
+	if (!PEAR::isError ($aComingEvents)) {
+		$smarty->assign("p",$p);
+   	$smarty->assign("events", $aComingEvents);
+	}
+}
+
+$smarty->display("events.tpl");
+
+?>
\ No newline at end of file
Index: web/data/Server.php
===================================================================
--- web/data/Server.php	(revision 392)
+++ web/data/Server.php	(working copy)
@@ -122,7 +122,34 @@
 
 		return $result;
 	}
+	
+	/**
+   * Retrieves a list of upcoming events
+   *
+   * @param int $number The number of artists to return
+   * @return An array of artists or a PEAR_Error in case of failure
+   */
+   static function getComingEvents($number=5, $p=0) {
+       global $mdb2;
 
+       $res = $mdb2->query("SELECT eventID, event, location, date, time, description FROM Events 
+       	ORDER BY date DESC LIMIT " . $mdb2->quote($p*5, "integer") . "," . $mdb2->quote($number, "integer"));
+
+       if(PEAR::isError($res)) {
+           return $res;
+       }
+
+       $data = $res->fetchAll(MDB2_FETCHMODE_ASSOC);
+       foreach($data as $i) {
+           $row = sanitize($i);
+//           $res = $mdb2->query("SELECT artist FROM Event_Artist WHERE eventID=" . $mdb2->quote($row["eventID"]) . ")");
+//           $row["artisturl"] = Server::getArtistURL($row["artist"]);
+           $row["eventurl"] = Server::getEventURL($row["eventID"]);
+           $result[] = $row;
+       }
+       return $result;
+   }
+
 	/**
 	 * The get*URL functions are implemented here rather than in their respective
 	 * objects so that we can produce URLs without needing to build whole objects.
@@ -165,5 +192,14 @@
 			return $base_url . "/track.php?artist=" . urlencode(stripslashes($artist)) .   "&album=" . urlencode(stripslashes($album)) . "&track=" . urlencode(stripslashes($track));
 		}
 	}
+	
+	static function getEventURL($eventID) {
+		global $friendly_urls, $base_url;
+		if($friendly_urls) {
+			return $base_url . "/event/" . stripslashes($eventID);
+		} else {
+			return $base_url . "/event.php?id=" . stripslashes($eventID);
+		}
+	}
 
 }
