From 97332b810372c802e30a551de9f45a42e75b2102 Mon Sep 17 00:00:00 2001
From: aaron <devnull@localhost>
Date: Mon, 8 Dec 2008 05:28:03 +0100
Subject: [PATCH] [svn r8081] Added cave and logbook search, collapsible footer
 navbar, useless statistics page. Also fixed broken css. Toying with forms but
 not committing those yet.

---
 troggle/expo/models_logbooks.py   |  9 ++---
 troggle/expo/search.py            | 39 ++++++++++++++++++++
 troggle/expo/views.py             |  1 +
 troggle/expo/views_caves.py       | 18 ++++++++++
 troggle/expo/views_logbooks.py    | 11 ++++++
 troggle/expo/views_other.py       | 13 +++++++
 troggle/media/css/main2.css       | 35 ++++++++++++++++--
 troggle/parsers/logbooks.py       |  2 +-
 troggle/settings.py               |  3 +-
 troggle/templates/base.html       | 60 +++++++++++++++++++++++++++++--
 troggle/templates/cave.html       |  2 +-
 troggle/templates/statistics.html |  8 +++++
 troggle/urls.py                   | 11 ++++--
 13 files changed, 194 insertions(+), 18 deletions(-)
 create mode 100644 troggle/expo/search.py
 create mode 100644 troggle/expo/views_other.py
 create mode 100644 troggle/templates/statistics.html

diff --git a/troggle/expo/models_logbooks.py b/troggle/expo/models_logbooks.py
index e9cf39143..89f212593 100644
--- a/troggle/expo/models_logbooks.py
+++ b/troggle/expo/models_logbooks.py
@@ -1,6 +1,6 @@
 from django.db import models
 from django.contrib import admin
-
+from django.forms import ModelForm
 
 class Expedition(models.Model):
     year        = models.CharField(max_length=20, unique=True)
@@ -79,9 +79,4 @@ class PersonTrip(models.Model):
     is_logbook_entry_author = models.BooleanField()
 
     def __unicode__(self):
-        return "%s %s (%s)" % (self.person_expedition, self.place, self.date)
-
-
-
-
-
+        return "%s %s (%s)" % (self.person_expedition, self.place, self.date)
\ No newline at end of file
diff --git a/troggle/expo/search.py b/troggle/expo/search.py
new file mode 100644
index 000000000..5ec2ce2f1
--- /dev/null
+++ b/troggle/expo/search.py
@@ -0,0 +1,39 @@
+import re
+
+from django.db.models import Q
+
+# search script from http://www.julienphalip.com/blog/2008/08/16/adding-search-django-site-snap/
+
+def normalize_query(query_string,
+                    findterms=re.compile(r'"([^"]+)"|(\S+)').findall,
+                    normspace=re.compile(r'\s{2,}').sub):
+    ''' Splits the query string in invidual keywords, getting rid of unecessary spaces
+        and grouping quoted words together.
+        Example:
+        
+        >>> normalize_query('  some random  words "with   quotes  " and   spaces')
+        ['some', 'random', 'words', 'with quotes', 'and', 'spaces']
+    
+    '''
+    return [normspace(' ', (t[0] or t[1]).strip()) for t in findterms(query_string)] 
+
+def get_query(query_string, search_fields):
+    ''' Returns a query, that is a combination of Q objects. That combination
+        aims to search keywords within a model by testing the given search fields.
+    
+    '''
+    query = None # Query to search for every search term        
+    terms = normalize_query(query_string)
+    for term in terms:
+        or_query = None # Query to search for a given term in each field
+        for field_name in search_fields:
+            q = Q(**{"%s__icontains" % field_name: term})
+            if or_query is None:
+                or_query = q
+            else:
+                or_query = or_query | q
+        if query is None:
+            query = or_query
+        else:
+            query = query & or_query
+    return query
\ No newline at end of file
diff --git a/troggle/expo/views.py b/troggle/expo/views.py
index eed58727e..718c720c4 100644
--- a/troggle/expo/views.py
+++ b/troggle/expo/views.py
@@ -1,3 +1,4 @@
 from views_caves import *
 from views_survex import *
 from views_logbooks import *
+from views_other import *
diff --git a/troggle/expo/views_caves.py b/troggle/expo/views_caves.py
index b2e185030..1f108f895 100644
--- a/troggle/expo/views_caves.py
+++ b/troggle/expo/views_caves.py
@@ -1,12 +1,15 @@
 from django.shortcuts import render_to_response
 from troggle.expo.models import Cave, CaveAndEntrance
 import troggle.settings as settings
+from troggle.expo.forms import CaveForm
+import search
 
 def caveindex(request):
     caves = Cave.objects.all()
     return render_to_response('caveindex.html', {'caves': caves, 'settings': settings})
 
 def cave(request, cave_id):
+    #hm, we're only choosing by the number within kataster, needs to be fixed. Caves in 1626 will presumably not work. - AC 7DEC08
     cave = Cave.objects.filter(kataster_number = cave_id)[0]
     return render_to_response('cave.html', {'cave': cave, 'settings': settings})
 
@@ -17,3 +20,18 @@ def ent(request, cave_id, ent_letter):
                                                 'entrance': cave_and_ent.entrance,
                                                 'letter': cave_and_ent.entrance_letter,
                                                 'settings': settings})
+
+def caveSearch(request):
+    query_string = ''
+    found_entries = None
+    if ('q' in request.GET) and request.GET['q'].strip():
+        query_string = request.GET['q']
+	entry_query = search.get_query(query_string, ['underground_description','official_name',])
+	found_entries = Cave.objects.filter(entry_query)
+
+    return render_to_response('cavesearch.html',
+                          { 'query_string': query_string, 'found_entries': found_entries, 'settings': settings})
+                          #context_instance=RequestContext(request))
+
+
+
diff --git a/troggle/expo/views_logbooks.py b/troggle/expo/views_logbooks.py
index 9d69099fe..b44c77022 100644
--- a/troggle/expo/views_logbooks.py
+++ b/troggle/expo/views_logbooks.py
@@ -1,6 +1,7 @@
 from django.shortcuts import render_to_response
 from troggle.expo.models import Expedition, Person, PersonExpedition, PersonTrip, LogbookEntry
 import troggle.settings as settings
+import search
 
 def personindex(request):
     persons = Person.objects.all()
@@ -14,4 +15,14 @@ def logbookentry(request, logbookentry_id):
     logbookentry = LogbookEntry.objects.filter(id = logbookentry_id)[0]
     return render_to_response('logbookentry.html', {'logbookentry': logbookentry, 'settings': settings})
 
+def logbookSearch(request, extra):
+    query_string = ''
+    found_entries = None
+    if ('q' in request.GET) and request.GET['q'].strip():
+        query_string = request.GET['q']
+	entry_query = search.get_query(query_string, ['text','title',])
+	found_entries = LogbookEntry.objects.filter(entry_query)
 
+    return render_to_response('logbooksearch.html',
+                          { 'query_string': query_string, 'found_entries': found_entries, 'settings': settings})
+                          #context_instance=RequestContext(request))
\ No newline at end of file
diff --git a/troggle/expo/views_other.py b/troggle/expo/views_other.py
new file mode 100644
index 000000000..808238e67
--- /dev/null
+++ b/troggle/expo/views_other.py
@@ -0,0 +1,13 @@
+from django.shortcuts import render_to_response
+from troggle.expo.models import Cave, Expedition, Person, LogbookEntry
+import troggle.settings as settings
+from django import forms
+from django.db.models import Q
+
+def stats(request):
+    statsDict={}
+    statsDict['expoCount'] = int(Expedition.objects.count())
+    statsDict['caveCount'] = int(Cave.objects.count())
+    statsDict['personCount'] = int(Person.objects.count())
+    statsDict['logbookEntryCount'] = int(LogbookEntry.objects.count())
+    return render_to_response('statistics.html', statsDict)
\ No newline at end of file
diff --git a/troggle/media/css/main2.css b/troggle/media/css/main2.css
index 8f1f3d258..523b1f7a3 100644
--- a/troggle/media/css/main2.css
+++ b/troggle/media/css/main2.css
@@ -5,11 +5,12 @@
 body, td, center, ul, p, input 	{ color: #000; font-family: sans-serif; }
 a:link, a:visited		{ text-decoration: none; }
 div.centre img			{ vertical-align: middle; }
-h1				{ text-align: center; font-size: 210%;
-				line-height: 100%; }
+
+h1				{ text-align: center; font-size: 210%;	line-height: 100%; }
 h2				{ color: #009900; }
 h3				{ color: #2c105e; }
 h4				{ color: #0d664c; }
+h4.navbar {line-height: 0px;}
 img.onright, div.onright	{ vertical-align: top; float: right;
 				margin-left: 10pt;  margin-bottom: 10pt;
 				margin-right: 8pt; }
@@ -22,6 +23,10 @@ table.imgtable			{ margin-left: auto; margin-right: auto; }
 table.imgtable td		{ vertical-align: middle; text-align: center;
 				padding: 10px; }
 
+table.normal		{ border: thin; border-top:solid ; border-left:dotted ; border-bottom:dotted; border-right:hidden ; border-width:1px;}
+table.normal td		{ border: thin; border-right:dotted ; border-width:1px; border-spacing:0px }
+table.normal th		{ border-left:thin ; border-right:thin ; text-align: left}
+
 /* "Traditional" table with borders.*/
 table.trad			{ margin: 0pt; border: 1px solid #000;
 				border-color: #c0c0c0 #8d8d8d #8d8d8d #c0c0c0; }
@@ -29,6 +34,30 @@ table.bigfatborder		{ border-width: 6px; }
 table.trad td, table.trad th	{ margin: 0pt; border: 1px solid #aaa;
 				border-color: #8d8d8d #c0c0c0 #c0c0c0 #8d8d8d; }
 
+/*Divs for layout*/
+html, body, div.contents {
+min-height: 100%;
+height: 100%;
+}
+html>body, html>body div.contents {
+height: auto;
+}
+body {
+}
+div.contents {
+position: absolute;
+top: 0;
+left: 0;
+}
+div.footer {
+position: fixed;
+bottom: 2px;
+right: 2px;
+}
+div.main {
+margin-bottom: 3em;
+}
+
 /* You are not expected to understand this. It is necessary. */
 table.centre			{ margin-left: auto; margin-right: auto; }
 table.centre td			{ text-align: left; }
@@ -40,4 +69,4 @@ table#cavepage th#name		{ text-align: center; width: 50%; }
 table#cavepage th#status	{ text-align: right; width: 25%; }
 
 .command                        { color: #FF0000; }
-.comment                        { color: #888888; font-style:italic;}
\ No newline at end of file
+.comment                        { color: #888888; font-style:italic;}
diff --git a/troggle/parsers/logbooks.py b/troggle/parsers/logbooks.py
index 900022ff2..d0d4f4c91 100644
--- a/troggle/parsers/logbooks.py
+++ b/troggle/parsers/logbooks.py
@@ -73,7 +73,7 @@ def LoadPersons():
     # this fills in those peopl for whom 2008 was their first expo
     for name in expomissing:
         firstname, lastname = name.split()
-        is_guest = name in ["Eeva Makiranta", "Kieth Curtis"]
+        is_guest = name in ["Eeva Makiranta", "Keith Curtis"]
         pObject = models.Person(first_name = firstname,
                                 last_name = lastname,
                                 is_vfho = False,
diff --git a/troggle/settings.py b/troggle/settings.py
index f6a9703ad..2dd7cc004 100644
--- a/troggle/settings.py
+++ b/troggle/settings.py
@@ -29,7 +29,8 @@ USE_I18N = True
 
 # Absolute path to the directory that holds media.
 # Example: "/home/media/media.lawrence.com/"
-MEDIA_ROOT = '/media-admin/'
+# MOVED TO LOCALSETTINGS
+MEDIA_ROOT = 'C:/Expo/expoweb/troggle/media/'
 
 # URL that handles the media served from MEDIA_ROOT. Make sure to use a
 # trailing slash if there is a path component (optional in other cases).
diff --git a/troggle/templates/base.html b/troggle/templates/base.html
index cb84590e9..6acd6acac 100644
--- a/troggle/templates/base.html
+++ b/troggle/templates/base.html
@@ -2,11 +2,67 @@
 <html lang="en">
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-    <link rel="stylesheet" type="text/css" href="{{ settings.MEDIA_URL }}/css/main2.css" />
+    <link rel="stylesheet" type="text/css" href="{{ settings.MEDIA_URL }}css/main2.css" />
     <title>{% block title %}{% endblock %}</title>
+
+<!-- script to toggle navbar -->
+
+<script language="javascript">
+<!--
+  function showFooter(){
+        document.getElementById('footerHidden').style.display = 'none';
+	document.getElementById('footerShowing').style.display = 'block';
+      }
+      
+  function hideFooter(){
+        document.getElementById('footerHidden').style.display = 'block';
+	document.getElementById('footerShowing').style.display = 'none';
+      }
+
+   function makeTransparent(){
+	document.getElementById('footerShowing').style.backgroundColor = 'transparent';
+      }
+-->
+</script>
+
 </head>
 <body>
+<div class="contents">
+<div class="main">
     {% block content %}{% endblock %}
-    {% block footer %}{% endblock %}
+</div>
+    {% block footer %}
+
+<div class="footer" id="footerHidden" style="display:none">
+	<h4><a href="javascript:;" onMouseDown="showFooter();">[Show Troggle Navigation / Search]</a></h4> 
+</div>
+
+<div class="footer" id="footerShowing" style="background-color:#CCC">
+	<h4 class="navbar"> Troggle navigation <a href="javascript:;" onMouseDown="hideFooter();">[Hide]</a> or <a href="javascript:;" onMouseDown="makeTransparent();">[Make transparent]</a></align></h4>
+    <table class="normal">	
+	<tr>
+		<td rowspan="2">
+			<a href="{{ settings.URL_ROOT }}cave">list caves</a> or 
+				<form name="input" action="{{ settings.URL_ROOT }}cavesearch" method="get">
+					<input type="text" name="q" value="search caves">
+					<input type="submit" value="Submit">
+				</form>
+		</td>
+		<td rowspan="2">
+			<a href="{{ settings.URL_ROOT }}logbookentry">list logbook entries</a> or
+				<form name="input" action="{{ settings.URL_ROOT }}logbooksearch" method="get">
+					<input type="text" name="q" value="search logbooks">
+					<input type="submit" value="Submit">
+				</form>
+		</td>
+		<td><a href="{{ settings.URL_ROOT }}person">list cavers</a></td>
+		<td><a href="{{ settings.URL_ROOT }}statistics"> statistics</a></td>
+	  <tr>
+      <td><a href="{{ settings.URL_ROOT }}photos">photos</a></td>
+      <td><a href="{{ settings.URL_ROOT }}admin"> admin</a></td>
+    </table>
+</div>
+    <p>{% endblock %}</p>
 </body>
+
 </html>
\ No newline at end of file
diff --git a/troggle/templates/cave.html b/troggle/templates/cave.html
index e8c597e2b..e76c3b87f 100644
--- a/troggle/templates/cave.html
+++ b/troggle/templates/cave.html
@@ -73,4 +73,4 @@
     <h2>Notes</h2>
     {{ cave.notes|wiki_to_html }}
 {% endif %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/troggle/templates/statistics.html b/troggle/templates/statistics.html
new file mode 100644
index 000000000..1fddd674d
--- /dev/null
+++ b/troggle/templates/statistics.html
@@ -0,0 +1,8 @@
+{% extends "base.html" %}
+{% load wiki_markup %}
+
+{% block title %}Database statistics{% endblock %}
+
+{% block content %}
+Over the course of {{ expoCount }} expeditions, {{ personCount }} people have contributed {{ caveCount }} caves and {{ logbookEntryCount }} logbook entries. 
+{% endblock %}
\ No newline at end of file
diff --git a/troggle/urls.py b/troggle/urls.py
index 4648a528a..0afaa3b10 100644
--- a/troggle/urls.py
+++ b/troggle/urls.py
@@ -1,6 +1,6 @@
 from django.conf.urls.defaults import *
 from expo.views import *
-
+import troggle.settings as settings
 from django.contrib import admin
 admin.autodiscover()
 
@@ -9,6 +9,8 @@ urlpatterns = patterns('',
     (r'^cave/$', caveindex),
     (r'^cave/(?P<cave_id>[^/]+)/$', cave),
     (r'^cave/(?P<cave_id>[^/]+)/(?P<ent_letter>[^/]?)$', ent),
+    (r'^cave/(?P<cave_id>[^/]+)/edit/$', edit_cave),
+    (r'^cavesearch/$', caveSearch),
     
     (r'^survex/(?P<survex_file>.*)\.index$', index),
     (r'^survex/(?P<survex_file>.*)\.svx$', svx),
@@ -20,11 +22,14 @@ urlpatterns = patterns('',
     (r'^person/(.*)$', person),
 
     (r'^logbookentry/(.*)$', logbookentry),
+    (r'^logbooksearch/(.*)$', logbookSearch),
+    
+    (r'^troggle/statistics/$', stats),
     
     (r'^admin/doc/', include('django.contrib.admindocs.urls')),
     (r'^admin/(.*)', admin.site.root),
 
-    (r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
-        {'document_root': 'c:/expodjango/troggle/media/'}),
+    (r'^troggle/site_media/(?P<path>.*)$', 'django.views.static.serve',
+        {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
 
 )