Permalink
Browse files

moved over content from geocamShare/apps/geocamLens

  • Loading branch information...
1 parent 569fed0 commit 9521b8afde9f1812a288c3370f5524823bf78c84 @trey0 trey0 committed Mar 10, 2011
Showing with 4,600 additions and 58 deletions.
  1. +145 −0 geocamLens/SearchAbstract.py
  2. +18 −0 geocamLens/SearchSimple.py
  3. +105 −0 geocamLens/UploadClient.py
  4. +106 −0 geocamLens/ViewKml.py
  5. +245 −0 geocamLens/ViewLensAbstract.py
  6. +20 −0 geocamLens/ViewLensSimple.py
  7. +8 −14 geocamLens/__init__.py
  8. +6 −0 geocamLens/admin.py
  9. +225 −0 geocamLens/bin/simpleImport.py
  10. +4 −17 geocamLens/defaultSettings.py
  11. +40 −0 geocamLens/forms.py
  12. +34 −17 geocamLens/management/appCommands/prep.py
  13. +83 −0 geocamLens/media_src/icons/aerialhazard.svg
  14. +83 −0 geocamLens/media_src/icons/aerialignition.svg
  15. +103 −0 geocamLens/media_src/icons/base.svg
  16. +125 −0 geocamLens/media_src/icons/commandpost.svg
  17. +413 −0 geocamLens/media_src/icons/damaged.svg
  18. +90 −0 geocamLens/media_src/icons/downlink.svg
  19. +113 −0 geocamLens/media_src/icons/droppoint.svg
  20. +173 −0 geocamLens/media_src/icons/fireline.svg
  21. +181 −0 geocamLens/media_src/icons/fireorigin.svg
  22. +95 −0 geocamLens/media_src/icons/hazmat.svg
  23. +366 −0 geocamLens/media_src/icons/helispot.svg
  24. +211 −0 geocamLens/media_src/icons/hotspot.svg
  25. +253 −0 geocamLens/media_src/icons/relativelysafe.svg
  26. +103 −0 geocamLens/media_src/icons/repeater.svg
  27. +140 −0 geocamLens/media_src/icons/safetyzone.svg
  28. +138 −0 geocamLens/media_src/icons/spotfire.svg
  29. +103 −0 geocamLens/media_src/icons/stagingarea.svg
  30. +86 −0 geocamLens/media_src/icons/unsafe.svg
  31. +144 −0 geocamLens/media_src/icons/warning.svg
  32. +105 −0 geocamLens/media_src/icons/watersource.svg
  33. +420 −0 geocamLens/models.py
  34. BIN geocamLens/static/geocamLens/icons/map/camera.png
  35. BIN geocamLens/static/geocamLens/icons/map/cameraPoint.png
  36. 0 geocamLens/static/geocamLens/placeholder.txt
  37. +34 −0 geocamLens/templates/editImage.html
  38. +9 −0 geocamLens/templates/editImageWrapper.html
  39. 0 geocamLens/templates/geocamLens/placeholder.txt
  40. +13 −0 geocamLens/templates/upload.html
  41. 0 geocamLens/templatetags/__init__.py
  42. +22 −7 geocamLens/tests.py
  43. +38 −3 geocamLens/urls.py
@@ -0,0 +1,145 @@
+# __BEGIN_LICENSE__
+# Copyright (C) 2008-2010 United States Government as represented by
+# the Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+# __END_LICENSE__
+
+import re
+import sys
+
+from django.db.models import Q
+
+from geocamUtil import TimeUtil
+
+class BadQuery(Exception):
+ pass
+
+class SearchAbstract:
+ # override these settings in derived classes
+ getAllFeatures = None
+ fields = ()
+ fieldAliases = ()
+ timeField = 'timestamp'
+
+ def __init__(self):
+ self.flookup = dict([(name, name) for name in self.fields])
+ self.flookup.update(dict(self.fieldAliases))
+
+ def filterFieldBefore(self, query, clause, field, term, negated):
+ if negated:
+ raise BadQuery("Oops, can't use minus sign with BEFORE in clause '%s' of search '%s'" % (clause, query))
+ try:
+ # intervalStart=False to get end of specified interval
+ # (inclusive before)
+ utcDT = TimeUtil.stringToUtcDT(term, intervalStart=False)
+ except ValueError, msg:
+ raise BadQuery("Oops, %s in clause '%s' of search '%s'"
+ % (msg, clause, query))
+ return Q(**{self.timeField+'__lte': utcDT})
+
+ def filterFieldAfter(self, query, clause, field, term, negated):
+ if negated:
+ raise BadQuery("Oops, can't use minus sign with AFTER in clause '%s' of search '%s'" % (clause, query))
+ try:
+ # intervalStart=True to get start of specified interval
+ # (inclusive after)
+ utcDT = TimeUtil.stringToUtcDT(term, intervalStart=True)
+ except ValueError, msg:
+ raise BadQuery("Oops, %s in clause '%s' of search '%s'"
+ % (msg, clause, query))
+ return Q(**{self.timeField+'__gte': utcDT})
+
+ def filterFieldDefault(self, query, clause, field, term, negated):
+ if field == None:
+ fields = self.flookup.keys()
+ elif field not in self.flookup:
+ raise BadQuery("Oops, can't understand field name '%s' of search '%s'. Legal field names are: %s."
+ % (field, query, ', '.join(self.flookup.keys())))
+ else:
+ fields = [field]
+ if not re.search('^[\.\-\_a-zA-Z0-9]*$', term):
+ raise BadQuery("Oops, can't understand term '%s' in search '%s'. Terms must contain only letters, numbers, periods, hyphens, and underscores."
+ % (term, query))
+ if term == '':
+ raise BadQuery("Oops, empty search term in clause '%s' of search '%s'."
+ % (clause, query))
+ qfilter = Q()
+ for f in fields:
+ dbField = self.flookup[f]
+ qAdd = Q(**{dbField+'__icontains': term})
+ if negated:
+ qfilter = qfilter & ~qAdd
+ else:
+ qfilter = qfilter | qAdd
+ return qfilter
+
+ def filterField(self, query, clause, field, term, negated):
+ if field:
+ filterFuncName = 'filterField'+field.capitalize()
+ if hasattr(self, filterFuncName):
+ filterFunc = getattr(self, filterFuncName)
+ return filterFunc(query, clause, field, term, negated)
+ return self.filterFieldDefault(query, clause, field, term, negated)
+
+ def filterClause(self, query, clause):
+ if clause.startswith('-'):
+ negated = True
+ clause = clause[1:]
+ else:
+ negated = False
+ if ':' in clause:
+ field, term = clause.split(':', 1)
+ field = field.lower()
+ else:
+ field, term = None, clause
+ return self.filterField(query, clause, field, term, negated)
+
+ def queryTreeToString(self, queryTree):
+ return (' OR '
+ .join(['(%s)' % (' AND '
+ .join(['"%s"' % clause
+ for clause in term]))
+ for term in queryTree]))
+
+ def parseQuery(self, query):
+ if not re.search('^[\-\.\:\_a-zA-Z0-9 ]*$', query):
+ raise BadQuery("Oops, can't understand search '%s'. Searches must contain only letters, numbers, minus signs, colons, periods, underscores, and spaces."
+ % query)
+ queryClauses = query.split()
+ #print >>sys.stderr, 'queryClauses:', queryClauses
+
+ queryTree = [[]]
+ for clause in queryClauses:
+ if clause.lower() == 'or':
+ if queryTree[-1] == []:
+ raise BadQuery("Oops, 'or' must come between normal clauses in search '%s'" % query)
+ queryTree.append([])
+ elif clause.lower() == 'and':
+ if queryTree[-1] == []:
+ raise BadQuery("Oops, 'and' must come between normal clauses in search '%s'")
+ # ignore -- 'and' is default connective
+ else:
+ queryTree[-1].append(clause)
+ #print >>sys.stderr, 'queryTree:', queryTreeToString(queryTree)
+ return queryTree
+
+ def treeToFilter(self, query, queryTree):
+ queryFilter = Q()
+ for term in queryTree:
+ termFilter = Q()
+ for clause in term:
+ clauseFilter = self.filterClause(query, clause)
+ termFilter = termFilter & clauseFilter
+ queryFilter = queryFilter | termFilter
+ return queryFilter
+
+ def searchFeatures0(self, startSet, query):
+ queryTree = self.parseQuery(query)
+ queryFilter = self.treeToFilter(query, queryTree)
+ return startSet.filter(queryFilter)
+
+ def searchFeatures(self, startSet, query):
+ result = startSet
+ if query:
+ result = self.searchFeatures0(result, query)
+ return result.distinct().order_by('-'+self.timeField)
View
@@ -0,0 +1,18 @@
+# __BEGIN_LICENSE__
+# Copyright (C) 2008-2010 United States Government as represented by
+# the Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+# __END_LICENSE__
+
+from geocamCore.models import PointFeature
+
+from geocamLens.SearchAbstract import SearchAbstract
+
+class SearchSimple(SearchAbstract):
+ def getAllFeatures(self):
+ return PointFeature.objects.filter(processed=True)
+
+ fields = ('name', 'user', 'notes', 'tags', 'uuid')
+ timeField = 'timestamp' # FIX: handle features with non-zero time extent
+ # pairs (user-facing-field-name, django-field-name)
+ fieldAliases = (('user', 'author__username'),)
View
@@ -0,0 +1,105 @@
+# __BEGIN_LICENSE__
+# Copyright (C) 2008-2010 United States Government as represented by
+# the Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+# __END_LICENSE__
+
+import os
+import urllib2
+import tempfile
+import re
+import base64
+
+import PIL.Image
+
+from geocamUtil import MimeMultipartFormData
+
+class UploadClient:
+ def __init__(self, url, userName='root', password=''):
+ self.url = url
+ self.userName = userName
+ self.password = password
+
+ self.imageName = None
+ self.im = None
+
+ def addAuthentication(self, headers, url):
+ '''update headers and return transformed url to support share
+ basic authentication.'''
+ if self.password:
+ # ensure https so we don't send password unencrypted
+ assert url.startswith('http')
+ url = re.sub(r'^http:', 'https:', url)
+ # new-style url which does not include userName
+ url = '%s/upload-m/' % url
+ # add pre-emptive basic authentication
+ auth = base64.encodestring('%s:%s' % (self.userName, self.password))[:-1]
+ headers['Authorization'] = 'Basic %s' % auth
+ else:
+ # no password means use old-style upload
+ url = '%s/upload/%s/' % (url, self.userName)
+ return url
+
+ def uploadImage(self, imageName, attributes, downsampleFactor=1):
+ if downsampleFactor != 1:
+ im = PIL.Image.open(imageName)
+ w, h = im.size
+ thRes = (w//downsampleFactor, h//downsampleFactor)
+ im.thumbnail(thRes, PIL.Image.ANTIALIAS)
+ fd, tmpName = tempfile.mkstemp('uploadImageThumb.jpg')
+ os.close(fd)
+ im.save(tmpName)
+ del im
+ imageData = file(tmpName, 'r').read()
+ os.unlink(tmpName)
+ else:
+ imageData = file(imageName, 'r').read()
+
+ #cookieProcessor = urllib2.HTTPCookieProcessor()
+ opener = urllib2.build_opener() # (cookieProcessor)
+ headers = {'User-Agent': 'GeoCam Upload Tester'}
+
+ multipart = MimeMultipartFormData.MimeMultipartFormData()
+ for k, v in attributes.iteritems():
+ multipart[k] = v
+ multipart.addFile(name='photo',
+ filename=os.path.basename(imageName),
+ data=imageData,
+ contentType='image/jpeg')
+
+ h2 = headers.copy()
+ h2.update(multipart.getHeaders())
+ url = self.addAuthentication(h2, self.url)
+ req = urllib2.Request(url=url,
+ data=multipart.getPostData(),
+ headers=h2)
+ resp = opener.open(req)
+ return resp
+
+ def uploadTrack(self, url, trackName, attributes=None):
+ trackData = file(trackName, 'r').read()
+
+ if attributes == None:
+ attributes = dict(trackUploadProtocolVersion='1.0')
+
+ #cookieProcessor = urllib2.HTTPCookieProcessor()
+ opener = urllib2.build_opener() # (cookieProcessor)
+ headers = {'User-Agent': 'GeoCam Upload Tester'}
+ url = '%s/track' % self.url
+
+ multipart = MimeMultipartFormData.MimeMultipartFormData()
+ for k, v in attributes.iteritems():
+ multipart[k] = v
+ multipart.addFile(name='gpxFile',
+ filename=os.path.basename(trackName),
+ data=trackData,
+ contentType='text/xml')
+
+ h2 = headers.copy()
+ h2.update(multipart.getHeaders())
+ url = self.addAuthentication(h2, url)
+ req = urllib2.Request(url=url,
+ data=multipart.getPostData(),
+ headers=h2)
+ resp = opener.open(req)
+ return resp
View
@@ -0,0 +1,106 @@
+# __BEGIN_LICENSE__
+# Copyright (C) 2008-2010 United States Government as represented by
+# the Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+# __END_LICENSE__
+
+import urllib
+import datetime
+import sys
+
+from geocamUtil import KmlUtil
+from geocamCore.models import Feature
+
+from geocamLens.models import GoogleEarthSession
+from geocamLens import settings
+
+class BogusRequest:
+ def build_absolute_uri(self, text):
+ return text
+
+class ViewKml(object):
+ def kmlGetStartSessionKml(self, request, sessionId):
+ quotedId = urllib.quote_plus(sessionId)
+ absUrl = request.build_absolute_uri('%skml/%s/initial.kml' % (settings.SCRIPT_NAME, quotedId))
+ if settings.GEOCAM_LENS_KML_FLY_TO_VIEW:
+ flyToView = '<flyToView>1</flyToView>'
+ else:
+ flyToView = ''
+ return ("""
+<NetworkLink>
+ <name>%(GEOCAM_CORE_SITE_TITLE)s</name>
+ <Link>
+ <href>%(absUrl)s</href>
+ </Link>
+ %(flyToView)s
+</NetworkLink>
+""" % dict(GEOCAM_CORE_SITE_TITLE=settings.GEOCAM_CORE_SITE_TITLE,
+ absUrl=absUrl,
+ flyToView=flyToView))
+
+ def kmlStartSession(self, request):
+ searchQuery = request.REQUEST.get('q', None)
+ sessionId = GoogleEarthSession.getSessionId(searchQuery)
+ print >>sys.stderr, "ViewKml: started session %s" % sessionId
+ return KmlUtil.wrapKmlDjango(self.kmlGetStartSessionKml(request, sessionId))
+
+ def kmlGetAllFeaturesFolder(self, request, searchQuery, newUtime):
+ features = self.search.searchFeatures(Feature.objects.all(), searchQuery)
+ if 0:
+ # FIX: update models so this filtering statement can work
+ features = features.filter(mtime__lte=newUtime,
+ deleted=False)
+ featuresKml = '\n'.join([f.getKml(request) for f in features])
+ return ("""
+<Folder id="allFeatures">
+ <name>All features</name>
+ %s
+</Folder>
+""" % featuresKml)
+
+ def kmlGetInitialKml(self, request, sessionId):
+ newUtime = datetime.datetime.now()
+ session, created = GoogleEarthSession.objects.get_or_create(sessionId=sessionId,
+ defaults=dict(utime=newUtime))
+ session.utime = newUtime
+ session.save()
+
+ allFeaturesFolder = self.kmlGetAllFeaturesFolder(request,
+ session.getSearchQuery(),
+ newUtime)
+ quotedId = urllib.quote_plus(sessionId)
+ updateUrl = request.build_absolute_uri('%skml/%s/update.kml' % (settings.SCRIPT_NAME, quotedId))
+ return ("""
+<Document id="allFeatures">
+ <name>%(GEOCAM_CORE_SITE_TITLE)s</name>
+
+ <NetworkLink>
+ <name>Update</name>
+ <Link>
+ <href>%(updateUrl)s</href>
+ <refreshMode>onInterval</refreshMode>
+ <refreshInterval>30</refreshInterval>
+ </Link>
+ </NetworkLink>
+
+ %(allFeaturesFolder)s
+
+</Document>
+""" % dict(GEOCAM_CORE_SITE_TITLE=settings.GEOCAM_CORE_SITE_TITLE,
+ updateUrl=updateUrl,
+ allFeaturesFolder=allFeaturesFolder))
+
+ def kmlGetUpdateKml(self, request, sessionId):
+ # FIX: implement me -- can use old version of geocam for reference
+ return ''
+
+ def kmlGetSessionResponse(self, request, quotedId, method):
+ sessionId = urllib.unquote_plus(quotedId)
+ #print 'sessionId:', sessionId
+ #print 'method:', method
+ if method == 'initial':
+ return KmlUtil.wrapKmlDjango(self.kmlGetInitialKml(request, sessionId))
+ elif method == 'update':
+ return KmlUtil.wrapKmlDjango(self.kmlGetUpdateKml(request, sessionId))
+ else:
+ raise Exception('method must be "initial" or "update"')
Oops, something went wrong.

0 comments on commit 9521b8a

Please sign in to comment.