source: subversion/applications/editors/django/osmeditor/simple/views.py @ 13472

Last change on this file since 13472 was 13472, checked in by hughb, 10 years ago
  • Object loaded is richer (sourced from /full URL); not rigorously tested, but: a) API is unreliable today, and b) object loading is about to be replaced by osmparser.py
  • some extra information for children output to screen
  • added temporary onscreen debug info
  • general UI tweaks
File size: 8.1 KB
Line 
1import xml.dom.minidom as m
2from django.conf import settings
3from django import forms
4from django.shortcuts import render_to_response
5from django.http import HttpResponse, HttpResponseRedirect
6try:
7    import httplib2
8except:
9    from third import httplib2
10
11try:
12    from xml.etree.cElementTree import Element, SubElement, tostring
13except:
14    from third.ElementTree import Element, SubElement, tostring
15
16import urllib
17
18def get_xml(type, id):
19    url = "%s/%s/%s/full" % (settings.OSM_API, type, id)
20    if type == "node":
21        url = url.replace('/full','') # required because the API 404s on node/x/full - wtf?
22    u = urllib.urlopen(url)
23    data = u.read()
24    doc = m.parseString(data)
25    return doc
26
27def get_osm_obj(type, id, doc=None):
28    obj = {}
29    if not doc:
30        doc = get_xml(type, id)
31    obj['xml'] = doc.toxml() #expose this to make debugging easier
32
33    obj['children'] = [] # we're giving everyone 0 or more children
34
35    if type == "node":
36        parent = doc.getElementsByTagName("node")[0]
37        referencer = parent
38        obj['lat'] = parent.getAttribute("lat")
39        obj['lon'] = parent.getAttribute("lon")
40
41    elif type == "way":
42        parent = doc.firstChild
43        referencer = doc.getElementsByTagName("way")[0]
44        for node in parent.getElementsByTagName("node"):
45            obj['children'].append( {'ref': node.getAttribute("id"),
46                                  'type':'node',
47                                  'tags': get_tags(node),
48                                  'tag_count': node.getElementsByTagName("tag").length
49                                 } )
50
51    elif type == "relation":
52        parent = doc.firstChild
53
54        # this pre-loop seems the only robust way to select and classify child XML elements - need XPath
55        memberElements = []
56        for element in parent.getElementsByTagName("*"):
57            if element.parentNode == parent:
58                if element.getAttribute("id") == id:
59                    referencer = element
60                else:
61                    memberElements.append(element)
62
63        for member in memberElements:
64            refs = [ref for ref in referencer.getElementsByTagName("member") if ref.getAttribute("ref") == member.getAttribute("id")]
65            if len(refs):
66                pointer = refs[0]
67                obj['children'].append( { 'ref': member.getAttribute("id"),
68                                       'type': member.nodeName, # could also use pointer.getAttribute("type") - maybe that's a safer bet?
69                                       'role': pointer.getAttribute("role"),
70                                       'tags': get_tags(member),
71                                       'tag_count': member.getElementsByTagName("tag").length
72                                    } )
73
74    obj['child_count'] = len(obj['children'])
75    obj['timestamp'] = referencer.getAttribute("timestamp")
76    obj['id'] = int(id)
77    obj['type'] = type
78    obj['tags'] = get_tags(referencer)
79    #hmm, not sure how the UI should manage the created_by tag
80    #obj['tags']['created_by'] = "%s (%s)" % (settings.APP_NAME,settings.APP_URI)
81    obj['user'] = { 'id': referencer.getAttribute("user") ,
82                    'uri': settings.OSM_USER % referencer.getAttribute("user") 
83                  }
84    obj['uri'] = { 'browse': "%s/%s/%s" % (settings.OSM_BROWSE, type.lower(), id),
85                   'xml_std': "%s/%s/%s" % (settings.OSM_API, type.lower(), id),
86                   'xml_full': "%s/%s/%s/full" % (settings.OSM_API, type.lower(), id) # echh, this url is just wrong
87                 }
88    obj['foo'] = referencer.nodeName
89    return obj
90
91def get_tags(parent):
92    tagset = {}
93    for tag in parent.getElementsByTagName("tag"):
94        tagset[tag.getAttribute("k")] = tag.getAttribute("v")
95    return tagset
96
97def edit_osm_obj(type, id, post, session={}):
98    xml = get_xml(type, id)
99    obj = get_osm_obj(type, id, xml)
100    if obj['timestamp'] != post['timestamp']:
101        raise Exception("Object changed since you started editing it.")
102    osm = Element('osm', {'version': '0.5'})
103    if type == "node":
104        parent = SubElement(osm, type, {'id':id, 
105                                        'lat':obj['lat'],
106                                        'lon':obj['lon']
107                                        })
108    elif type == "way":
109        parent = SubElement(osm, type, {'id':id })
110        for nd in xml.getElementsByTagName("nd"):
111            nd = SubElement(parent, "nd", {'ref': nd.getAttribute("ref")})
112   
113    elif type == "relation":
114        parent = SubElement(osm, type, {'id':id, })
115        for m in xml.getElementsByTagName("member"):
116            member = SubElement(parent, "member", {'type': m.getAttribute("type"),
117                                                   'id': m.getAttribute("id"),
118                                                   'role': m.getAttribute("role")
119                                                  }
120                               )
121    else:
122        raise Exception("%s not supported" % type)
123    changed = False
124    for key in filter(lambda x: x.startswith("delete_"), post.keys()):
125        k = key.replace("delete_key_", "")
126        if k in obj['tags']:
127            changed = True
128            del obj['tags'][k]
129        else:
130            raise Exception("Huh? %s is not in tags" % k)
131   
132    for key in filter(lambda x: x.startswith("key_"), post.keys()):
133        k = key.replace("key_", "")
134        if k in obj['tags'] and post[key] != obj['tags'][k]:
135            changed = True
136            obj['tags'][k] = post[key]
137   
138    for key in filter(lambda x: x.startswith("new_key_"), post.keys()):
139        new_id = key.replace("new_key_", "")
140        kname = "new_key_%s" % new_id
141        vname = "new_value_%s" % new_id
142        if kname in post and vname in post:
143            k = post[kname]
144            v = post[vname]
145            if k and v:
146                obj['tags'][k] = v
147                changed = True
148           
149    if not changed: return
150
151    for k, v in obj['tags'].items():
152        SubElement(parent, "tag", {'k': k, 'v': v})
153 
154    username = post.get('username', None) or session.get("username", None)
155    password = post.get('password', None) or session.get("password", None)
156    if not username or not password:
157        raise Exception("Need username and password")
158    xml = tostring(osm)
159    change_obj(type, id, xml, username, password)
160
161def change_obj(type, id, xml, username, password):   
162    url = "%s/%s/%s" % (settings.OSM_API, type, id)
163    http = httplib2.Http()   
164    http.add_credentials(username, password)
165    resp, content = http.request(url, "PUT", body=xml)   
166    if int(resp.status) != 200:
167        raise Exception("%s, %s \n%s" % (resp.status, url, content))
168
169def load(request, type="node", id=0):
170    if request.method == "POST":
171        edit_osm_obj(type, id, request.POST, request.session)
172        return HttpResponseRedirect("/%s/%s/" % (type, id))   
173    obj = get_osm_obj(type, id)
174   
175    return render_to_response("obj.html",{'obj':obj, 
176        'logged_in': ('username' in request.session)})
177
178def home(request):
179    return render_to_response("home.html", {'logged_in': 'username' in request.session})
180
181class UserForm(forms.Form):
182    email = forms.CharField(max_length=255)
183    password = forms.CharField(widget=forms.PasswordInput)
184
185def login(request):
186    if request.method == "POST":
187        form = UserForm(request.POST)
188        if form.is_valid():
189            username = form.cleaned_data['email']
190            password = form.cleaned_data['password']
191            http = httplib2.Http()   
192            http.add_credentials(username, password)
193            url = "%s/user/details" % (settings.OSM_API)
194            resp, content = http.request(url, "GET")
195            if int(resp.status) == 200:
196                request.session['username'] = username
197                request.session['password'] = password
198                return HttpResponseRedirect("/")   
199    else:
200        form = UserForm()
201    return render_to_response("login.html", {'form': form})   
202
203def api_proxy(request, url):
204    http = httplib2.Http()   
205    url = "%s/%s" % (settings.OSM_API, url)
206    resp, content = http.request(url, "GET")
207    return HttpResponse(content, content_type="application/osm+xml")
Note: See TracBrowser for help on using the repository browser.