source: subversion/sites/other/tilesAtHome_tahngo/requests/views.py @ 9092

Last change on this file since 9092 was 9092, checked in by spaetz, 12 years ago

run changed Tiles requester every 4 h

File size: 12.7 KB
Line 
1from django.utils.encoding import force_unicode
2from django.shortcuts import render_to_response
3from django.contrib.auth.models import User
4import django.views.generic.list_detail
5from django.http import HttpResponse, HttpResponseNotFound
6from tah.requests.models import Request,Upload
7from tah.requests.forms import CreateForm,UploadForm,ClientAuthForm
8from django.newforms import form_for_model,widgets
9from datetime import datetime, timedelta
10import urllib
11import xml.dom.minidom
12from django.contrib.auth import authenticate
13#from tah.user.auth import OSMBackend
14from tah.tah_intern.models import Layer
15from tah.tah_intern.Tile import Tile
16from django.views.decorators.cache import cache_control
17from tah.tah_intern.models import Settings
18
19
20def index(request):
21  return render_to_response('base_requests.html');
22
23#shortcut view to see all requests
24def show_first_page(request):
25  return show_requests(request,1)
26
27@cache_control(must_revalidate=True, max_age=30)
28def show_requests(request,page):
29  if page: pagination=30 
30  else: pagination=0
31  return django.views.generic.list_detail.object_list(request, queryset=Request.objects.filter(status=0).order_by('-request_time'),template_name='requests_show.html',allow_empty=True,paginate_by=pagination,page=page,template_object_name='new_reqs',extra_context={'active_reqs_list':Request.objects.filter(status=1).order_by('-clientping_time')[:30]});
32
33
34@cache_control(must_revalidate=True, max_age=30)
35def show_uploads_page(request):
36  return django.views.generic.list_detail.object_list(request, queryset=Request.objects.filter(status=2).order_by('-clientping_time')[:30],template_name='requests_show_uploads.html',allow_empty=True,template_object_name='reqs');
37
38def request_exists(request):
39    """ Gets handed a CreateForm bound to form data. Returns the 'Request' element if the request exists
40        already and 0 if not.
41        TODO: NOT IMPLEMEMENTED YET.
42    """
43    return 0
44
45
46def saveCreateRequestForm(request, form):
47    """ Returns (Request, reason), with Request being 'None' on failure and
48        the saved request object on success.
49        Reason is a string that describes the error in case of failure.
50    """
51    formdata = form.cleaned_data.copy()
52    # delete entries that are not needed as default value or won't work
53    del formdata['layers']
54    del formdata['status']
55    if not formdata['min_z'] in ['6','12']: formdata['min_z'] = 12
56    if not formdata['max_z']: formdata['max_z'] = {0:5,6:11,12:17}[formdata['min_z']]
57    if not formdata['priority'] or \
58      formdata['priority']>4 or formdata['priority']<1: 
59        formdata['priority'] = 3
60    formdata['clientping_time'] = force_unicode(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
61
62    # catch invalid x,y
63    if not Tile(None,formdata['min_z'],formdata['x'],formdata['y']).is_valid():
64      return (None, 'Invalid tile coordinates')
65    # Create a new request, or get the existing one
66    newRequest, created_new = Request.objects.get_or_create(status=0, min_z=formdata['min_z'], x=form.data['x'], y=form.data['y'],defaults=formdata)
67
68    newRequest.ipaddress = request.META['REMOTE_ADDR']
69    if not created_new:
70      #update existing request with new request data
71      newRequest.max_z = max(formdata['max_z'],newRequest.max_z)
72      newRequest.priority = min(formdata['priority'],newRequest.priority)
73
74    # finally save the updated request
75    newRequest.save()
76    if form.data.has_key('layers'):
77      # save the chosen layers
78      layers = Layer.objects.filter(pk__in=form['layers'].data)
79    else:
80      # no layers selected -> save default layers
81      layers = Layer.objects.filter(default=True)
82    for l in layers: newRequest.layers.add(l)
83    return (newRequest,'')
84
85def create(request):
86    html="XX|unknown error"
87    CreateFormClass = CreateForm
88    CreateFormClass.base_fields['ipaddress'].required = False
89    CreateFormClass.base_fields['ipaddress'].widget = widgets.HiddenInput()
90    CreateFormClass.base_fields['priority'].required = False
91    CreateFormClass.base_fields['status'].required = False 
92    CreateFormClass.base_fields['status'].widget = widgets.HiddenInput()
93    CreateFormClass.base_fields['min_z'].required = False 
94    CreateFormClass.base_fields['max_z'].required = False 
95    CreateFormClass.base_fields['max_z'].widget = widgets.HiddenInput()
96    CreateFormClass.base_fields['layers'].widget = widgets.CheckboxSelectMultiple( 
97         choices=CreateFormClass.base_fields['layers'].choices)
98    CreateFormClass.base_fields['layers'].required = False
99    CreateFormClass.base_fields['clientping_time'].required = False
100    CreateFormClass.base_fields['clientping_time'].widget = widgets.HiddenInput()
101    CreateFormClass.base_fields['client'].required = False
102    CreateFormClass.base_fields['client'].widget = widgets.HiddenInput()
103    form = CreateFormClass()
104
105    if request.method == 'POST':
106      form = CreateForm(request.POST)
107      if form.is_valid():
108        req, reason = saveCreateRequestForm(request, form)
109      else:
110        html="form is not valid. "+str(form.errors)
111    else:
112      #Create request using GET"
113      form = CreateForm(request.GET)
114      if form.is_valid():
115        req, reason = saveCreateRequestForm(request, form)
116      else:
117         # view the plain form webpage with default values filled in
118         return render_to_response('requests_create.html', \
119                {'createform': form, 'host':request.META['HTTP_HOST']})
120    if req: html = "Render '%s' (%s,%s,%s)" % \
121                    (req.layers_str,req.min_z,req.x,req.y)
122    else:   html = "Request failed (%s,%s,%s): %s" \
123                    % (form.cleaned_data['min_z'],form.cleaned_data['x'],form.cleaned_data['y'],reason)
124    return HttpResponse(html)
125
126
127def upload_request(request):
128    html='XX|Unknown error.'
129    UploadFormClass = UploadForm
130    UploadFormClass.base_fields['ipaddress'].required = False
131    UploadFormClass.base_fields['ipaddress'].widget = widgets.HiddenInput()
132    UploadFormClass.base_fields['priority'].required = False
133    UploadFormClass.base_fields['file'].required = False
134    UploadFormClass.base_fields['is_locked'].required = False
135    UploadFormClass.base_fields['is_locked'].widget = widgets.HiddenInput()
136    UploadFormClass.base_fields['user_id'].required = False
137    UploadFormClass.base_fields['user_id'].widget = widgets.HiddenInput()
138    form = UploadFormClass()
139
140    if request.method == 'POST':
141      authform = ClientAuthForm(request.POST)
142      if authform.is_valid():
143        name     = authform.cleaned_data['user']
144        passwd   = authform.cleaned_data['passwd']
145        user = authenticate(username=name, password=passwd)
146        if user is not None:
147          #"You provided a correct username and password!"
148          formdata = request.POST.copy()
149          formdata['user_id'] = user.id # set the user to the correct value
150          #t@h client send layername, rather than layer number,
151          #find the right one if that is the case
152          if formdata.has_key('layer'):
153            try: int(formdata['layer'])
154            except ValueError:
155              # look up the layer id
156              formdata['layer'] = Layer.objects.get(name=formdata['layer']).id
157          # due to a django verification bug, set a filename if a file was attached.
158          if 'file' in request.FILES: 
159            formdata['file']='dummy'
160          form = UploadFormClass(formdata)
161
162          if form.is_valid():
163            file = request.FILES['file']
164            try:
165              newUpload= form.save(commit=False)
166              #             #   filetype = file['content-type']   
167              newUpload.ipaddress = request.META['REMOTE_ADDR']
168              # low priority upload by default
169              if not newUpload.priority: newUpload.priority = 3
170              newUpload.is_locked = False
171              newUpload.save_file_file(file['filename'],file['content'])
172              newUpload.save()
173              html="OK|4|"
174            except:
175              #TODO: delete possibly uploaded file, in case of exception
176              import sys
177              html ="XX| Exception thrown."+str(user.id)+str(sys.exc_info()[1])
178          else:
179            html="XX|4|form is not valid. "+str(form.errors)
180        else:
181          # authentication failed here, or authform failed to validate.
182          html="XX|4|Invalid username. Your username and password were incorrect or the user has been disabled."
183    else:
184      # request.method==GET here. View the plain form webpage with default values filled in
185      authform = ClientAuthForm()
186      return render_to_response('requests_upload.html',{'uploadform': form, 'authform': authform, 'host':request.META['HTTP_HOST']})
187    return HttpResponse(html);
188
189def upload_gonogo(request):
190    # dummy, always return 1 for full speed ahead
191    load = 1 - Upload.objects.all().count()/600.0
192    return HttpResponse(str(load)+"\ndummytoken\n");
193
194def take(request):
195    html='XX|4|unknown error'
196    if request.method == 'POST':
197      form = ClientAuthForm(request.POST)
198      if form.is_valid():
199        name     = form.cleaned_data['user']
200        passwd   = form.cleaned_data['passwd']
201        user = authenticate(username=name, password=passwd)
202        if user is not None:
203            #"You provided a correct username and password!"
204            try:
205                req = Request.objects.filter(status=0).order_by('priority','request_time')[0]
206                req.status=1
207                req.client = user
208                req.clientping_time=datetime.now()
209                req.save()
210                html="OK|4|"+str(req)
211                #req.delete()
212            except IndexError:
213                html ="XX|4|No requests in queue"
214        else:
215            html="XX|4|Invalid username. Your username and password were incorrect or the user has been disabled."
216      else: #form was not valid
217        html = "XX|4|Form invalid. "+str(form.errors)
218      return HttpResponse(html);
219    else: #request.method != POST, show the web form
220      form = ClientAuthForm()
221      return render_to_response('requests_take.html',{'clientauthform': form})
222    return HttpResponse(html)
223
224def request_changedTiles(request):
225    html="Requested tiles:\n"
226    xml_dom = xml.dom.minidom.parse(urllib.urlopen('http://www.openstreetmap.org/api/0.5/changes?hours=4'))
227    tiles = xml_dom.getElementsByTagName("tile")
228    for tile in tiles:
229      (z,x,y) = tile.getAttribute('z'),tile.getAttribute('x'),tile.getAttribute('y')
230      CreateFormClass = CreateForm
231      CreateFormClass.base_fields['max_z'].required = False 
232      CreateFormClass.base_fields['layers'].required = False 
233      CreateFormClass.base_fields['status'].required = False 
234      form = CreateFormClass({'min_z': z, 'x': x, 'y': y, 'priority': 2})
235      if form.is_valid():
236        req, reason = saveCreateRequestForm(request, form)
237        if req:
238          html += "Render '%s' (%s,%s,%s)\n" % (req.layers_str,form.cleaned_data['min_z'],form.cleaned_data['x'],form.cleaned_data['y'])
239        else: html +="Renderrequest failed (%s,%s,%s): %s\n" % (form.cleaned_data['min_z'],form.cleaned_data['x'],form.cleaned_data['y'], reason)
240      else:
241        html+="form is not valid. %s\n" % form.errors
242    xml_dom.unlink()
243   
244    return HttpResponse(html,mimetype='text/plain')
245
246def expire_tiles(request):
247    """ Rerequest old active request that haven't been pinged by the client
248        for a while. Also delete old finished requests that we don't need
249        anymore.
250    """
251    rerequested = Request.objects.filter(status=1,clientping_time__lt=datetime.now()-timedelta(0,0,0,0,0,6))
252    for r in rerequested:
253      #next django version will be able to just update() this
254      r.status=0
255      r.save()
256
257    expired = Request.objects.filter(status=2, clientping_time__lt=datetime.now()-timedelta(2,0,0,0,0,0))
258    expired.delete()
259
260    html="Reset %d requests to unfinished status.\nExpired %d old finished requests." % (len(rerequested),len(expired))
261    return HttpResponse(html,mimetype='text/plain')
262
263def stats_munin_requests(request,status):
264    reply=''
265    states={'pending':0,'active':1,'done':2}
266    if states.has_key(status): state = states[status]
267    else: return HttpResponseNotFound('Unknown request state')
268    reqs = Request.objects.filter(status=state)
269    if state < 2:
270      #output low/medium/high requests for unfinished ones
271      for val, state in enumerate(['high','medium','low']):
272        c = reqs.filter(priority=val+1).count()
273        reply += "%s.value %d\n" % (state,c)
274    else:
275      #output requests finished per last hour and 48 moving avg
276      reply += "_req_processed_last_hour.value %d\n" %  reqs.filter(clientping_time__gt=datetime.now()-timedelta(0,0,0,0,0,1)).count()
277      reply += 'done.value %d' % (reqs.filter(clientping_time__gt=datetime.now()-timedelta(0,0,0,0,0,48)).count() // 48)
278    return HttpResponse(reply,mimetype='text/plain')
279
280def show_latest_client_version(request):
281    html = Settings().getSetting(name='latest_client_version')
282    return HttpResponse(html,mimetype='text/plain')
Note: See TracBrowser for help on using the repository browser.