views.py 23.1 KB
Newer Older
1
# -*- coding: utf-8 -*-
Dudás Ádám committed
2 3
from datetime import datetime
from django.conf import settings
Őry Máté committed
4
from datetime import timedelta as td
Dudás Ádám committed
5 6 7 8
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib import messages
from django.core.exceptions import PermissionDenied
9
from django.core import signing, urlresolvers
Dudás Ádám committed
10 11 12 13 14 15 16 17 18 19 20 21
from django.core.mail import mail_managers, send_mail
from django.db import transaction
from django.forms import ModelForm, Textarea
from django.http import Http404
from django.shortcuts import render, render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.decorators import method_decorator
from django.utils.translation import get_language as lang
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import *
from django.views.generic import *
22
from firewall.tasks import *
23
from cloud.settings import store_settings
Dudás Ádám committed
24
from one.models import *
Dányi Bence committed
25
from school.models import *
Dudás Ádám committed
26
import django.contrib.auth as auth
27
import json
28
import logging
tarokkk committed
29
import subprocess
30 31

logger = logging.getLogger(__name__)
Dudás Ádám committed
32 33 34 35 36

def _list_instances(request):
    instances = Instance.objects.exclude(state='DONE').filter(owner=request.user)
    for i in instances:
        i.update_state()
37
    instances = instances.exclude(state='DONE')
Dudás Ádám committed
38 39
    return instances

40 41 42
def info(request):
    return render_to_response("info.html", RequestContext(request, {}))

43
def index(request):
44 45 46 47
    if request.user.is_authenticated():
        return redirect(home)
    else:
        return redirect(info)
48 49


Dudás Ádám committed
50 51 52
@require_GET
@login_required
def home(request):
53
    instances = _list_instances(request)
54 55 56 57
    shares = [s for s in request.user.person_set.all()[0].get_shares()]
    for i, s in enumerate(shares):
        s.running_shared = s.instance_set.all().exclude(state="DONE").filter(owner=request.user).count()
        shares[i] = s
58 59 60 61 62
    try:
        details = UserCloudDetails.objects.get(user=request.user)
    except UserCloudDetails.DoesNotExist:
        details = UserCloudDetails(user=request.user)
        details.save()
x committed
63 64 65 66
    try:
        generated_public_key = details.ssh_key.id
    except:
        generated_public_key = -1
67
    return render_to_response("home.html", RequestContext(request, {
68
        'instances': instances,
69
        'shares': shares,
70 71
        'templates': Template.objects.filter(state='READY'),
        'mytemplates': Template.objects.filter(owner=request.user),
Dányi Bence committed
72
        'groups': request.user.person_set.all()[0].owned_groups.all(),
73
        'semesters': Semester.objects.all(),
74
        'userdetails': details,
x committed
75
        'keys': request.user.sshkey_set.exclude(id=generated_public_key).all(),
76
        'storeserv': store_settings['store_public'],
Dudás Ádám committed
77 78
        }))

79 80 81 82 83 84 85
@login_required
def ajax_template_delete(request):
    try:
        template_id = request.POST['id']
    except:
        return HttpResponse(unicode(_("Invalid template ID.")), status=404)
    template = get_object_or_404(Template, id=template_id)
86
    if template.running_instances() > 0:
87 88 89
        return HttpResponse(unicode(_("There are running instances of this template.")), status=404)
    elif template.share_set.exists():
        return HttpResponse(unicode(_("Template is still shared.")), status=404)
90 91
    elif template.owner != request.user:
        return HttpResponse(unicode(_("You don't have permission to delete this template.")), status=404)
92
    else:
93 94 95 96
        if template.safe_delete():
            return HttpResponse(unicode(_("Template successfully deleted.")))
        else:
            return HttpResponse(unicode(_("Unexpected error happened.")), status=404)
97

98 99
def ajax_template_name_unique(request):
    name = request.GET['name']
100 101 102 103 104
    s = "True"
    if Template.objects.filter(name=name).exists():
        s = "False"
    return HttpResponse(s)

105 106
@login_required
def vm_credentials(request, iid):
107 108
    try:
        vm = get_object_or_404(Instance, pk=iid, owner=request.user)
109 110 111
        proto = len(request.META["REMOTE_ADDR"].split('.')) == 1
        vm.hostname = vm.get_connect_host(use_ipv6=proto)
        vm.port = vm.get_port(use_ipv6=proto)
112
        return render_to_response('vm-credentials.html', RequestContext(request, { 'i' : vm }))
113
    except:
114
        return HttpResponse(_("Could not get Virtual Machine credentials."), status=404)
115
        messages.error(request, _('Failed to power off virtual machine.'))
116

117 118
class AjaxTemplateWizard(View):
    def get(self, request, *args, **kwargs):
119 120 121
        return render_to_response('new-template-flow-1.html', RequestContext(request, {
            'templates': [t for t in Template.objects.filter(public=True).all()] +
                         [t for t in Template.objects.filter(owner=request.user).all()],
122 123 124 125 126
            }))
    def post(self, request, *args, **kwargs):
        base = get_object_or_404(Template, id=request.POST['base'])
        if base.owner != request.user and not base.public and not request.user.is_superuser:
            raise PermissionDenied()
127 128 129 130
        try:
            maxshare = Template.objects.order_by('-pk')[0].pk + 1
        except:
            maxshare = 1
131 132 133
        return render_to_response('new-template-flow.html', RequestContext(request, {
            'sizes': InstanceType.objects.all(),
            'base': base,
134
            'maxshare': maxshare,
135 136 137
            }))
ajax_template_wizard = login_required(AjaxTemplateWizard.as_view())

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
class AjaxTemplateEditWizard(View):
    def get(self, request, id, *args, **kwargs):
        template = get_object_or_404(Template, id=id)
        if template.owner != request.user and not template.public and not request.user.is_superuser:
            raise PermissionDenied()
        return render_to_response('edit-template-flow.html', RequestContext(request, {
            'sizes': InstanceType.objects.all(),
            'template': template,
            }))
    def post(self, request, id, *args, **kwargs):
        template = get_object_or_404(Template, id=id)
        if template.owner != request.user and not template.public and not request.user.is_superuser:
            raise PermissionDenied()
        template.instance_type_id = request.POST['size']
        template.description = request.POST['description']
        template.name = request.POST['name']
        template.save()
        return redirect(home)

ajax_template_edit_wizard = login_required(AjaxTemplateEditWizard.as_view())

Őry Máté committed
159 160 161

class AjaxShareWizard(View):
    def get(self, request, id, gid=None, *args, **kwargs):
Őry Máté committed
162 163 164
        det = UserCloudDetails.objects.get(user=request.user)
        if det.get_weighted_share_count() >= det.share_quota:
            return HttpResponse(unicode(_('You do not have any free share quota.')))
Őry Máté committed
165 166 167 168 169 170 171 172 173
        types = TYPES_L
        types[0]['default'] = True
        for i, t in enumerate(types):
            t['deletex'] = datetime.now() + td(seconds=1) + t['delete'] if t['delete'] else None
            t['suspendx'] = datetime.now() + td(seconds=1) + t['suspend'] if t['suspend'] else None
            types[i] = t
        if gid:
            gid = get_object_or_404(Group, id=gid)

Őry Máté committed
174
        return render_to_response('new-share.html', RequestContext(request, {
Őry Máté committed
175 176 177 178 179 180
            'base': get_object_or_404(Template, id=id),
            'groups': request.user.person_set.all()[0].owned_groups.all(),
            'types': types,
            'group': gid,
            }))
    def post(self, request, id, gid=None, *args, **kwargs):
Őry Máté committed
181
        det = UserCloudDetails.objects.get(user=request.user)
Őry Máté committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
        base = get_object_or_404(Template, id=id)
        if base.owner != request.user and not base.public and not request.user.is_superuser:
            raise PermissionDenied()
        group = None
        if gid:
            group = get_object_or_404(Group, id=gid)
        else:
            group = get_object_or_404(Group, id=request.POST['group'])

        if not group.owners.filter(user=request.user).exists():
            raise PermissionDenied()
        stype = request.POST['type']
        if not stype in TYPES.keys():
            raise PermissionDenied()
        il = request.POST['instance_limit']
Őry Máté committed
197 198 199
        if det.get_weighted_share_count() + int(il)*base.instance_type.credit > det.share_quota:
            messages.error(request, _('You do not have enough free share quota.'))
            return redirect('/')
Őry Máté committed
200 201
        s = Share.objects.create(name=request.POST['name'], description=request.POST['description'],
                type=stype, instance_limit=il, per_user_limit=request.POST['per_user_limit'],
Őry Máté committed
202
                group=group, template=base, owner=request.user)
Őry Máté committed
203
        messages.success(request, _('Successfully shared %s.') % base)
Őry Máté committed
204
        return redirect(group)
Őry Máté committed
205 206
ajax_share_wizard = login_required(AjaxShareWizard.as_view())

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
class AjaxShareEditWizard(View):
    def get(self, request, id, *args, **kwargs):
        det = UserCloudDetails.objects.get(user=request.user)
        if det.get_weighted_share_count() >= det.share_quota:
            return HttpResponse(unicode(_('You do not have any free share quota.')))
        types = TYPES_L
        for i, t in enumerate(types):
            t['deletex'] = datetime.now() + td(seconds=1) + t['delete'] if t['delete'] else None
            t['suspendx'] = datetime.now() + td(seconds=1) + t['suspend'] if t['suspend'] else None
            types[i] = t
        share = get_object_or_404(Share, id=id)
        return render_to_response('edit-share.html', RequestContext(request, {
            'share': share,
            'types': types,
            }))
    def post(self, request, id, *args, **kwargs):
        det = UserCloudDetails.objects.get(user=request.user)
        share = get_object_or_404(Share, id=id)
        if share.owner != request.user and not request.user.is_superuser:
            raise PermissionDenied()
        stype = request.POST['type']
        if not stype in TYPES.keys():
            raise PermissionDenied()
        il = request.POST['instance_limit']
        if det.get_weighted_share_count() + int(il)*share.template.instance_type.credit > det.share_quota:
            messages.error(request, _('You do not have enough free share quota.'))
            return redirect('/')
        share.name=request.POST['name']
        share.description=request.POST['description']
        share.type=stype
        share.instance_limit=il
        share.per_user_limit=request.POST['per_user_limit']
        share.owner=request.user
        share.save()
        messages.success(request, _('Successfully edited share %s.') % share)
        return redirect(share.group)
ajax_share_edit_wizard = login_required(AjaxShareEditWizard.as_view())
Őry Máté committed
244 245


246
@require_POST
Dányi Bence committed
247
@login_required
248 249 250 251 252 253 254 255
def vm_saveas(request, vmid):
    inst = get_object_or_404(Instance, pk=vmid)
    if inst.owner != request.user and not request.user.is_superuser:
        raise PermissionDenied()
    inst.save_as()
    messages.success(request, _("Template is being saved..."))
    return redirect(inst)

256
def vm_new_ajax(request, template):
257
    return vm_new(request, template, redir=False)
Dányi Bence committed
258

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
def _redirect_or_201(path, redir):
    if redir:
        return redirect(path)
    else:
        response = HttpResponse("Created", status=201)
        response['Location'] = path
        return response

def _template_for_save(base, request):
    if base.owner != request.user and not base.public and not request.user.is_superuser:
        raise PermissionDenied()
    name = request.POST['name']
    t = Template.objects.create(name=name, disk=base.disk, instance_type_id=request.POST['size'], network=base.network, owner=request.user)
    t.access_type = base.access_type
    t.description = request.POST['description']
    t.system = base.system
    t.save()
    return t

def _check_quota(request, template, share):
    """
    Returns if the given request is permitted to run the new vm.
    """
    det = UserCloudDetails.objects.get(user=request.user)
    if det.get_weighted_instance_count() + template.instance_type.credit >= det.instance_quota:
        messages.error(request, _('You do not have any free quota. You can not launch this until you stop an other instance.'))
        return False
    if share:
        if share.get_running() + 1 > share.instance_limit:
            messages.error(request, _('The share does not have any free quota. You can not launch this until someone stops an instance.'))
            return False
        elif share.get_running_or_stopped(request.user) + 1 > share.per_user_limit:
            messages.error(request, _('You do not have any free quota for this share. You can not launch this until you stop an other instance.'))
            return False
        if not share.group.members.filter(user=request.user) and not share.group.owners.filter(user=request.user):
            messages.error(request, _('You are not a member of the share group.'))
            return False
    return True

Dudás Ádám committed
298 299
@require_POST
@login_required
300
def vm_new(request, template=None, share=None, redir=True):
301 302
    base = None
    extra = None
tarokkk committed
303 304 305 306 307
    if template:
        base = get_object_or_404(Template, pk=template)
    else:
        share = get_object_or_404(Share, pk=share)
        base = share.template
308

309
    go = True
310
    if "name" in request.POST:
311 312 313 314 315 316 317
        try:
            base = _template_for_save(base, request)
            extra = "<RECONTEXT>YES</RECONTEXT>"
        except:
            messages.error(request, _('Can not create template.'))
            go = False
    go = go and _check_quota(request, base, share)
318 319 320 321 322 323 324

    if not share and not base.public and base.owner != request.user:
        messages.error(request, _('You have no permission to try this instance without a share. Launch a new instance through a share.'))
        go = False
    type = share.type if share else 'LAB'
    TYPES[type]['suspend']
    time_of_suspend = TYPES[type]['suspend']+datetime.now()
tarokkk committed
325 326 327 328
    if TYPES[type]['delete']:
        time_of_delete = TYPES[type]['delete']+datetime.now()
    else:
        time_of_delete = None
329 330 331 332 333 334 335 336 337 338 339 340
    inst = None
    if go:
        try:
            inst = Instance.submit(base, request.user, extra=extra, share=share)
        except Exception as e:
            logger.error('Failed to create virtual machine.' + unicode(e))
            messages.error(request, _('Failed to create virtual machine.'))
            inst = None
        if inst:
            inst.time_of_suspend = time_of_suspend
            inst.time_of_delete = time_of_delete
            inst.save()
341 342
    elif extra and base:
        base.delete()
343
    return _redirect_or_201(inst.get_absolute_url() if inst else '/', redir)
Dudás Ádám committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359

class VmListView(ListView):
    context_object_name = 'instances'
    template_name = 'list.html'

    def get_queryset(self):
        self.profile = request.user
        return Instance.objects.filter(owner=self.profile)

vm_list = login_required(VmListView.as_view())

@require_safe
@login_required
def vm_show(request, iid):
    inst = get_object_or_404(Instance, id=iid, owner=request.user)
    inst.update_state()
360 361
    if inst.template.state == "SAVING":
        inst.check_if_is_save_as_done()
362 363 364 365
    try:
        ports = inst.firewall_host.list_ports()
    except:
        ports = None
366 367 368 369 370
    try:
        details = UserCloudDetails.objects.get(user=request.user)
    except UserCloudDetails.DoesNotExist:
        details = UserCloudDetails(user=request.user)
        details.save()
371 372 373
    proto = len(request.META["REMOTE_ADDR"].split('.')) == 1
    inst.hostname = inst.get_connect_host(use_ipv6=proto)
    inst.port = inst.get_port(use_ipv6=proto)
Dudás Ádám committed
374
    return render_to_response("show.html", RequestContext(request,{
375 376 377
        'uri': inst.get_connect_uri(),
        'state': inst.state,
        'name': inst.name,
tarokkk committed
378
        'id': int(iid),
Dudás Ádám committed
379 380
        'age': inst.get_age(),
        'instances': _list_instances(request),
Őry Máté committed
381
        'i': inst,
382
        'booting' : not inst.active_since,
383
        'ports': ports,
384
        'userdetails': details
Dudás Ádám committed
385 386
        }))

387 388 389 390 391
@require_safe
@login_required
def vm_ajax_instance_status(request, iid):
    inst = get_object_or_404(Instance, id=iid, owner=request.user)
    inst.update_state()
392 393 394 395 396 397
    return HttpResponse(json.dumps({
        'booting': not inst.active_since,
        'state': inst.state,
        'template': {
            'state': inst.template.state
        }}))
398

399 400 401 402 403 404 405
@login_required
def vm_ajax_rename(request, iid):
    inst = get_object_or_404(Instance, id=iid, owner=request.user)
    inst.name = request.POST['name']
    inst.save()
    return HttpResponse(json.dumps({'name': inst.name}))

406 407 408 409 410 411 412 413 414 415 416 417 418
def boot_token(request, token):
    try:
        id = signing.loads(token, salt='activate')
    except:
        return HttpResponse("Invalid token.")
    inst = get_object_or_404(Instance, id=id)
    if inst.active_since:
        return HttpResponse("Already booted?")
    else:
        inst.active_since = datetime.now()
        inst.save()
        return HttpResponse("KTHXBYE")

Őry Máté committed
419 420 421 422
class VmPortAddView(View):
    def post(self, request, iid, *args, **kwargs):
        try:
            public = int(request.POST['public'])
Dányi Bence committed
423

Őry Máté committed
424
            if public >= 22000 and public < 24000:
425
                raise ValidationError(_("Port number is in a restricted domain (22000 to 24000)."))
Őry Máté committed
426
            inst = get_object_or_404(Instance, id=iid, owner=request.user)
427 428 429 430 431
            if inst.template.network.nat:
                private = private=int(request.POST['private'])
            else:
                private = 0
            inst.firewall_host.add_port(proto=request.POST['proto'], public=public, private=private)
432
            messages.success(request, _(u"Port %d successfully added.") % public)
Őry Máté committed
433
        except:
434
            messages.error(request, _(u"Adding port failed."))
Őry Máté committed
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
#            raise
        return redirect('/vm/show/%d/' % int(iid))

    def get(self, request, iid, *args, **kwargs):
        return redirect('/')

vm_port_add = login_required(VmPortAddView.as_view())

@require_safe
@login_required
@require_GET
def vm_port_del(request, iid, proto, public):
    inst = get_object_or_404(Instance, id=iid, owner=request.user)
    try:
        inst.firewall_host.del_port(proto=proto, public=public)
450
        messages.success(request, _(u"Port %s successfully removed.") % public)
Őry Máté committed
451
    except:
452
        messages.error(request, _(u"Removing port failed."))
Őry Máté committed
453 454
    return redirect('/vm/show/%d/' % int(iid))

Dudás Ádám committed
455 456 457
class VmDeleteView(View):
    def post(self, request, iid, *args, **kwargs):
        try:
458 459 460 461
            inst = get_object_or_404(Instance, id=iid, owner=request.user)
            if inst.template.state != 'READY' and inst.template.owner == request.user:
                inst.template.delete()
            inst.delete()
Dudás Ádám committed
462 463 464
            messages.success(request, _('Virtual machine is successfully deleted.'))
        except:
            messages.error(request, _('Failed to delete virtual machine.'))
465 466 467 468
        if request.is_ajax():
            return HttpResponse("")
        else:
            return redirect('/')
Dudás Ádám committed
469 470 471

    def get(self, request, iid, *args, **kwargs):
        i = get_object_or_404(Instance, id=iid, owner=request.user)
472
        return render_to_response("confirm_delete.html", RequestContext(request, {
Dudás Ádám committed
473 474 475 476
            'i': i}))

vm_delete = login_required(VmDeleteView.as_view())

477
@login_required
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
#@require_POST
def vm_unshare(request, id, *args, **kwargs):
    s = get_object_or_404(Share, id=id)
    g = s.group
    if not g.owners.filter(user=request.user).exists():
        raise PermissionDenied()
    try:
        if s.get_running_or_stopped() > 0:
            messages.error(request, _('There are machines running of this share.'))
        else:
            s.delete()
            messages.success(request, _('Share is successfully removed.'))
    except:
        messages.error(request, _('Failed to remove share.'))
    return redirect(g)

@login_required
495 496 497 498 499 500 501 502 503 504 505 506 507
@require_POST
def vm_stop(request, iid, *args, **kwargs):
    try:
        get_object_or_404(Instance, id=iid, owner=request.user).stop()
        messages.success(request, _('Virtual machine is successfully stopped.'))
    except:
        messages.error(request, _('Failed to stop virtual machine.'))
    return redirect('/')

@login_required
@require_POST
def vm_resume(request, iid, *args, **kwargs):
    try:
Őry Máté committed
508 509
        obj = get_object_or_404(Instance, id=iid, owner=request.user)
        obj.resume()
510 511 512
        messages.success(request, _('Virtual machine is successfully resumed.'))
    except:
        messages.error(request, _('Failed to resume virtual machine.'))
Őry Máté committed
513
    obj.renew()
514 515 516 517
    return redirect('/')

@login_required
@require_POST
Őry Máté committed
518 519
def vm_renew(request, which, iid, *args, **kwargs):
    try:
520
        get_object_or_404(Instance, id=iid, owner=request.user).renew()
Őry Máté committed
521 522 523 524 525 526 527
        messages.success(request, _('Virtual machine is successfully renewed.'))
    except:
        messages.error(request, _('Failed to renew virtual machine.'))
    return redirect('/')

@login_required
@require_POST
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
def vm_power_off(request, iid, *args, **kwargs):
    try:
        get_object_or_404(Instance, id=iid, owner=request.user).poweroff()
        messages.success(request, _('Virtual machine is successfully powered off.'))
    except:
        messages.error(request, _('Failed to power off virtual machine.'))
    return redirect('/')

@login_required
@require_POST
def vm_restart(request, iid, *args, **kwargs):
    try:
        get_object_or_404(Instance, id=iid, owner=request.user).restart()
        messages.success(request, _('Virtual machine is successfully restarted.'))
    except:
        messages.error(request, _('Failed to restart virtual machine.'))
    return redirect('/')
Dudás Ádám committed
545

Dányi Bence committed
546 547 548 549 550 551 552
@login_required
@require_POST
def key_add(request):
    try:
        key=SshKey()
        key.key=request.POST['key']
        key.user=request.user
Dányi Bence committed
553
        key.full_clean()
Dányi Bence committed
554
        key.save()
x committed
555
        _update_keys(request.user)
Dányi Bence committed
556
    except ValidationError as e:
557 558 559
        for m in e.messages:
            messages.error(request, m)

x committed
560
    except:
561 562
        messages.error(request, _('Failed to add public key.'))
    else:
Őry Máté committed
563
        messages.success(request, _('Public key successfully added.'))
Dányi Bence committed
564 565 566 567 568 569
    return redirect('/')

@login_required
@require_POST
def key_ajax_delete(request):
    try:
570
        key=get_object_or_404(SshKey, id=request.POST['id'], user=request.user)
Dányi Bence committed
571
        key.delete()
x committed
572
        _update_keys(request.user)
Dányi Bence committed
573 574
    except:
        messages.error(request, _('Failed to delete public key'))
Dányi Bence committed
575 576 577 578 579 580 581 582 583
    return HttpResponse('OK')

@login_required
@require_POST
def key_ajax_reset(request):
    try:
        det=UserCloudDetails.objects.get(user=request.user)
        det.reset_smb()
        det.reset_keys()
x committed
584
        _update_keys(request.user)
Dányi Bence committed
585 586 587
    except:
        messages.error(request, _('Failed to reset keys'))
    return HttpResponse('OK')
Dányi Bence committed
588

x committed
589 590 591 592 593 594 595 596 597
def _update_keys(user):
    details = user.cloud_details
    password = details.smb_password
    key_list = []
    for key in user.sshkey_set.all():
        key_list.append(key.key)
    user = user.username
    StoreApi.updateauthorizationinfo(user, password, key_list)

tarokkk committed
598 599 600 601 602 603 604 605 606 607 608 609
def stat(request):
    values = subprocess.check_output(['/opt/webadmin/cloud/miscellaneous/stat/stat_wrap.sh'])
  #  values = '''
  #  {"CPU": {"USED_CPU": 2, "ALLOC_CPU": 0,
  #  "FREE_CPU": 98}, "MEM": {"FREE_MEM": 1685432, "ALLOC_MEM":0,
  #  "USED_MEM": 366284}}'''
    stat_dict = json.loads(values)
    return  HttpResponse(render_to_response("stat.html", RequestContext(
                request, {
                    'STAT' : stat_dict,
                }
            )))
x committed
610

Bach Dániel committed
611 612 613 614 615 616
def sites(request, site):
    if site in [ "legal", "policy", "help", "support" ]:
        return render_to_response("sites/%s.html" % site, RequestContext(request, {}))
    else:
        return redirect(home)

Dudás Ádám committed
617
# vim: et sw=4 ai fenc=utf8 smarttab :