Commit 101d86ee authored by Leonidas Poulopoulos's avatar Leonidas Poulopoulos
Browse files

Aligned branch internationalization with latest changes in master

parents be9ee8b3 cc0c4fcf
===========
0.8.7 RELEASE
Minor enhancements
Enhancements:
- Merged all mail txt files into one
- Added all routes in form cleaning (initially, EXPIRED, ADMININACTIVE and ERROR were excluded)
===========
0.8.6 RELEASE
Minor UI enhancements/Bug fix
Fixes:
- Fixed issue where rules in ERROR state would cause check_sync to check them
Enhancements:
- Added small dots to ongoing response field to indicate activity
===========
0.8.5 RELEASE
Feature enhancement release/Minor UI fixes/Cleanup
Fixes:
- Changed javascript order to prevent unformated content in datatables
- Un-needed files cleanup
- Error template is now based on base.html template
Enhancements:
- Administrator privileges apply on UI as well
- Enhanced application security
===========
0.8.4 RELEASE
Vulnerability prevention/bug fixes release
Fixes:
- Fixed a bug where the shib auth backend erased non-shibboleth users info
- Added an authsource variable to prevent authentication backend overlapping
- Added exception handling for non-Shibboleth users that do not belong to a peer
=========== ===========
0.8.3 RELEASE 0.8.3 RELEASE
Feature enhancement release Feature enhancement release
......
...@@ -73,7 +73,19 @@ In settings.py set the following according to your configuration: ...@@ -73,7 +73,19 @@ In settings.py set the following according to your configuration:
* PRIMARY_WHOIS * PRIMARY_WHOIS
* ALTERNATE_WHOIS * ALTERNATE_WHOIS
4.2 Installation 4.2 Branding
4.2.1 Logos
Inside the static folder you will find two empty png files: logo.dist.png (172x80) and shib_login.dist.png (98x80).
Edit those two with your favourite image processing software and save them as logo.png and shib_login.png under the same folder. Image sizes are optimized to operate without any
other code changes. In case you want to incorporate images of different sizes you have to fine tune css and/or html as well.
4.2.2 Footer
Under the templates folder (templates), you can alter the footer.html file to include your own footer messages, badges, etc.
4.3 Installation
* Run: * Run:
./manage.py syncdb ./manage.py syncdb
......
...@@ -10,6 +10,9 @@ class shibauthBackend: ...@@ -10,6 +10,9 @@ class shibauthBackend:
firstname = kwargs.get('firstname') firstname = kwargs.get('firstname')
lastname = kwargs.get('lastname') lastname = kwargs.get('lastname')
mail = kwargs.get('mail') mail = kwargs.get('mail')
authsource = kwargs.get('authsource')
if authsource != 'shibboleth':
return None
try: try:
user = self._auth_user(username, firstname, lastname, mail) user = self._auth_user(username, firstname, lastname, mail)
except: except:
...@@ -22,10 +25,6 @@ class shibauthBackend: ...@@ -22,10 +25,6 @@ class shibauthBackend:
try: try:
user = User.objects.get(username__exact=username) user = User.objects.get(username__exact=username)
user.email = mail
user.first_name = firstname
user.last_name = lastname
user.save()
# The user did not exist. Create one with no privileges # The user did not exist. Create one with no privileges
except: except:
user = User.objects.create_user(username, mail, None) user = User.objects.create_user(username, mail, None)
......
...@@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _ ...@@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy
from django.template.defaultfilters import filesizeformat from django.template.defaultfilters import filesizeformat
from flowspy.flowspec.models import * from flowspy.flowspec.models import *
from flowspy.peers.models import *
from ipaddr import * from ipaddr import *
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -25,7 +26,14 @@ class RouteForm(forms.ModelForm): ...@@ -25,7 +26,14 @@ class RouteForm(forms.ModelForm):
class Meta: class Meta:
model = Route model = Route
def clean_applier(self):
applier = self.cleaned_data['applier']
if applier:
return self.cleaned_data["applier"]
else:
raise forms.ValidationError('This field is required.')
def clean_source(self): def clean_source(self):
user = User.objects.get(pk=self.data['applier']) user = User.objects.get(pk=self.data['applier'])
peer = user.get_profile().peer peer = user.get_profile().peer
...@@ -106,8 +114,15 @@ class RouteForm(forms.ModelForm): ...@@ -106,8 +114,15 @@ class RouteForm(forms.ModelForm):
destinationports = self.cleaned_data.get('destinationport', None) destinationports = self.cleaned_data.get('destinationport', None)
protocols = self.cleaned_data.get('protocol', None) protocols = self.cleaned_data.get('protocol', None)
user = self.cleaned_data.get('applier', None) user = self.cleaned_data.get('applier', None)
try:
issuperuser = self.data['issuperuser']
su = User.objects.get(username=issuperuser)
except:
issuperuser = None
peer = user.get_profile().peer peer = user.get_profile().peer
networks = peer.networks.all() networks = peer.networks.all()
if issuperuser:
networks = PeerRange.objects.filter(peer__in=Peer.objects.all()).distinct()
mynetwork = False mynetwork = False
route_pk_list = [] route_pk_list = []
if destination: if destination:
...@@ -116,7 +131,7 @@ class RouteForm(forms.ModelForm): ...@@ -116,7 +131,7 @@ class RouteForm(forms.ModelForm):
if IPNetwork(destination) in net: if IPNetwork(destination) in net:
mynetwork = True mynetwork = True
if not mynetwork: if not mynetwork:
raise forms.ValidationError(_('Destination address/network should belong to your administrative address space. Check My Profile to review your networks')) raise forms.ValidationError(_('Destination address/network should belong to your administrative address space. Check My Profile to review your networks'))
if (sourceports and ports): if (sourceports and ports):
raise forms.ValidationError(_('Cannot create rule for source ports and ports at the same time. Select either ports or source ports')) raise forms.ValidationError(_('Cannot create rule for source ports and ports at the same time. Select either ports or source ports'))
if (destinationports and ports): if (destinationports and ports):
...@@ -129,7 +144,7 @@ class RouteForm(forms.ModelForm): ...@@ -129,7 +144,7 @@ class RouteForm(forms.ModelForm):
raise forms.ValidationError(_('Fill at least a Rule Match Condition')) raise forms.ValidationError(_('Fill at least a Rule Match Condition'))
if not user.is_superuser and then[0].action not in settings.UI_USER_THEN_ACTIONS: if not user.is_superuser and then[0].action not in settings.UI_USER_THEN_ACTIONS:
raise forms.ValidationError(_('This action "%s" is not permitted') %(then[0].action)) raise forms.ValidationError(_('This action "%s" is not permitted') %(then[0].action))
existing_routes = Route.objects.exclude(status='EXPIRED').exclude(status='ERROR').exclude(status='ADMININACTIVE') existing_routes = Route.objects.all()
existing_routes = existing_routes.filter(applier__userprofile__peer=peer) existing_routes = existing_routes.filter(applier__userprofile__peer=peer)
if source: if source:
source = IPNetwork(source).compressed source = IPNetwork(source).compressed
......
...@@ -123,8 +123,9 @@ def check_sync(route_name=None, selected_routes = []): ...@@ -123,8 +123,9 @@ def check_sync(route_name=None, selected_routes = []):
routes = routes.filter(name=route_name) routes = routes.filter(name=route_name)
for route in routes: for route in routes:
if route.has_expired() and (route.status != 'EXPIRED' and route.status != 'ADMININACTIVE' and route.status != 'INACTIVE'): if route.has_expired() and (route.status != 'EXPIRED' and route.status != 'ADMININACTIVE' and route.status != 'INACTIVE'):
logger.info('Expiring route %s' %route.name) if route.status != 'ERROR':
subtask(delete).delay(route, reason="EXPIRED") logger.info('Expiring %s route %s' %(route.status, route.name))
subtask(delete).delay(route, reason="EXPIRED")
# elif route.has_expired() and (route.status == 'ADMININACTIVE' or route.status == 'INACTIVE'): # elif route.has_expired() and (route.status == 'ADMININACTIVE' or route.status == 'INACTIVE'):
# route.status = 'EXPIRED' # route.status = 'EXPIRED'
# route.response = 'Rule Expired' # route.response = 'Rule Expired'
...@@ -149,8 +150,8 @@ def notify_expired(): ...@@ -149,8 +150,8 @@ def notify_expired():
admin_url = "https://%s%s" % \ admin_url = "https://%s%s" % \
(fqdn, (fqdn,
"/fod/edit/%s"%route.name) "/fod/edit/%s"%route.name)
mail_body = render_to_string("rule_expiration.txt", mail_body = render_to_string("rule_action.txt",
{"route": route, 'expiration_days':expiration_days, 'url':admin_url}) {"route": route, 'expiration_days':expiration_days, 'action':'expires', 'url':admin_url})
days_num = ' days' days_num = ' days'
expiration_days_text = "%s %s" %('in',expiration_days) expiration_days_text = "%s %s" %('in',expiration_days)
if expiration_days == 0: if expiration_days == 0:
......
...@@ -64,12 +64,18 @@ def welcome(request): ...@@ -64,12 +64,18 @@ def welcome(request):
@never_cache @never_cache
def group_routes(request): def group_routes(request):
group_routes = [] group_routes = []
peer = request.user.get_profile().peer try:
peer = request.user.get_profile().peer
except UserProfile.DoesNotExist:
error = "User <strong>%s</strong> does not belong to any peer or organization. It is not possible to create new firewall rules.<br>Please contact Helpdesk to resolve this issue" % request.user.username
return render_to_response('error.html', {'error': error})
if peer: if peer:
peer_members = UserProfile.objects.filter(peer=peer) peer_members = UserProfile.objects.filter(peer=peer)
users = [prof.user for prof in peer_members] users = [prof.user for prof in peer_members]
group_routes = Route.objects.filter(applier__in=users) group_routes = Route.objects.filter(applier__in=users)
return render_to_response('user_routes.html', {'routes': group_routes}, if request.user.is_superuser:
group_routes = Route.objects.all()
return render_to_response('user_routes.html', {'routes': group_routes},
context_instance=RequestContext(request)) context_instance=RequestContext(request))
...@@ -83,7 +89,7 @@ def add_route(request): ...@@ -83,7 +89,7 @@ def add_route(request):
_("Insufficient rights on administrative networks. Cannot add rule. Contact your administrator")) _("Insufficient rights on administrative networks. Cannot add rule. Contact your administrator"))
return HttpResponseRedirect(reverse("group-routes")) return HttpResponseRedirect(reverse("group-routes"))
if request.method == "GET": if request.method == "GET":
form = RouteForm() form = RouteForm(initial={'applier': applier})
if not request.user.is_superuser: if not request.user.is_superuser:
form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True) form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False) form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False)
...@@ -91,19 +97,32 @@ def add_route(request): ...@@ -91,19 +97,32 @@ def add_route(request):
context_instance=RequestContext(request)) context_instance=RequestContext(request))
else: else:
form = RouteForm(request.POST) request_data = request.POST.copy()
if request.user.is_superuser:
request_data['issuperuser'] = request.user.username
else:
request_data['applier'] = applier
try:
del requset_data['issuperuser']
except:
pass
form = RouteForm(request_data)
if form.is_valid(): if form.is_valid():
route=form.save(commit=False) route=form.save(commit=False)
route.applier = request.user if not request.user.is_superuser:
route.applier = request.user
route.status = "PENDING" route.status = "PENDING"
route.response = "Applying"
route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed
route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed
route.save() route.save()
form.save_m2m() form.save_m2m()
route.commit_add() route.commit_add()
requesters_address = request.META['HTTP_X_FORWARDED_FOR'] requesters_address = request.META['HTTP_X_FORWARDED_FOR']
mail_body = render_to_string("rule_add_mail.txt", fqdn = Site.objects.get_current().domain
{"route": route, "address": requesters_address}) admin_url = "https://%s%s" % (fqdn, "/fod/edit/%s"%route.name)
mail_body = render_to_string("rule_action.txt",
{"route": route, "address": requesters_address, "action": "creation", "url": admin_url})
user_mail = "%s" %route.applier.email user_mail = "%s" %route.applier.email
user_mail = user_mail.split(';') user_mail = user_mail.split(';')
send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s creation request submitted by %s" %(route.name, route.applier.username), send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s creation request submitted by %s" %(route.name, route.applier.username),
...@@ -113,6 +132,9 @@ def add_route(request): ...@@ -113,6 +132,9 @@ def add_route(request):
logger.info(mail_body, extra=d) logger.info(mail_body, extra=d)
return HttpResponseRedirect(reverse("group-routes")) return HttpResponseRedirect(reverse("group-routes"))
else: else:
if not request.user.is_superuser:
form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False)
return render_to_response('apply.html', {'form': form, 'applier':applier}, return render_to_response('apply.html', {'form': form, 'applier':applier},
context_instance=RequestContext(request)) context_instance=RequestContext(request))
...@@ -123,7 +145,7 @@ def edit_route(request, route_slug): ...@@ -123,7 +145,7 @@ def edit_route(request, route_slug):
applier_peer = request.user.get_profile().peer applier_peer = request.user.get_profile().peer
route_edit = get_object_or_404(Route, name=route_slug) route_edit = get_object_or_404(Route, name=route_slug)
route_edit_applier_peer = route_edit.applier.get_profile().peer route_edit_applier_peer = route_edit.applier.get_profile().peer
if applier_peer != route_edit_applier_peer: if applier_peer != route_edit_applier_peer and (not request.user.is_superuser):
messages.add_message(request, messages.WARNING, messages.add_message(request, messages.WARNING,
_("Insufficient rights to edit rule %s") %(route_slug)) _("Insufficient rights to edit rule %s") %(route_slug))
return HttpResponseRedirect(reverse("group-routes")) return HttpResponseRedirect(reverse("group-routes"))
...@@ -141,34 +163,64 @@ def edit_route(request, route_slug): ...@@ -141,34 +163,64 @@ def edit_route(request, route_slug):
return HttpResponseRedirect(reverse("group-routes")) return HttpResponseRedirect(reverse("group-routes"))
route_original = deepcopy(route_edit) route_original = deepcopy(route_edit)
if request.POST: if request.POST:
form = RouteForm(request.POST, instance = route_edit) request_data = request.POST.copy()
if request.user.is_superuser:
request_data['issuperuser'] = request.user.username
else:
request_data['applier'] = applier
try:
del request_data['issuperuser']
except:
pass
form = RouteForm(request_data, instance = route_edit)
critical_changed_values = ['source', 'destination', 'sourceport', 'destinationport', 'port', 'protocol', 'then']
if form.is_valid(): if form.is_valid():
changed_data = form.changed_data
route=form.save(commit=False) route=form.save(commit=False)
route.name = route_original.name route.name = route_original.name
route.applier = request.user route.status = route_original.status
route.status = "PENDING" route.response = route_original.response
route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed if not request.user.is_superuser:
route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed route.applier = request.user
if bool(set(changed_data) & set(critical_changed_values)) or (not route_original.status == 'ACTIVE'):
route.status = "PENDING"
route.response = "Applying"
route.source = IPNetwork("%s/%s" %(IPNetwork(route.source).network.compressed, IPNetwork(route.source).prefixlen)).compressed
route.destination = IPNetwork("%s/%s" %(IPNetwork(route.destination).network.compressed, IPNetwork(route.destination).prefixlen)).compressed
route.save() route.save()
form.save_m2m() if bool(set(changed_data) & set(critical_changed_values)) or (not route_original.status == 'ACTIVE'):
route.commit_edit() form.save_m2m()
requesters_address = request.META['HTTP_X_FORWARDED_FOR'] route.commit_edit()
mail_body = render_to_string("rule_edit_mail.txt", requesters_address = request.META['HTTP_X_FORWARDED_FOR']
{"route": route, "address": requesters_address}) fqdn = Site.objects.get_current().domain
user_mail = "%s" %route.applier.email admin_url = "https://%s%s" % (fqdn, "/fod/edit/%s"%route.name)
user_mail = user_mail.split(';') mail_body = render_to_string("rule_action.txt",
send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s edit request submitted by %s" %(route.name, route.applier.username), {"route": route, "address": requesters_address, "action": "edit", "url": admin_url})
user_mail = "%s" %route.applier.email
user_mail = user_mail.split(';')
send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s edit request submitted by %s" %(route.name, route.applier.username),
mail_body, settings.SERVER_EMAIL, user_mail, mail_body, settings.SERVER_EMAIL, user_mail,
get_peer_techc_mails(route.applier)) get_peer_techc_mails(route.applier))
d = { 'clientip' : requesters_address, 'user' : route.applier.username } d = { 'clientip' : requesters_address, 'user' : route.applier.username }
logger.info(mail_body, extra=d) logger.info(mail_body, extra=d)
return HttpResponseRedirect(reverse("group-routes")) return HttpResponseRedirect(reverse("group-routes"))
else: else:
if not request.user.is_superuser:
form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
form.fields['protocol'] = forms.ModelMultipleChoiceField(queryset=MatchProtocol.objects.filter(protocol__in=settings.UI_USER_PROTOCOLS).order_by('protocol'), required=False)
return render_to_response('apply.html', {'form': form, 'edit':True, 'applier': applier}, return render_to_response('apply.html', {'form': form, 'edit':True, 'applier': applier},
context_instance=RequestContext(request)) context_instance=RequestContext(request))
else: else:
if (not route_original.status == 'ACTIVE'):
route_edit.expires = datetime.date.today() + datetime.timedelta(days = settings.EXPIRATION_DAYS_OFFSET)
dictionary = model_to_dict(route_edit, fields=[], exclude=[]) dictionary = model_to_dict(route_edit, fields=[], exclude=[])
#form = RouteForm(instance=route_edit) if request.user.is_superuser:
dictionary['issuperuser'] = request.user.username
else:
try:
del dictionary['issuperuser']
except:
pass
form = RouteForm(dictionary) form = RouteForm(dictionary)
if not request.user.is_superuser: if not request.user.is_superuser:
form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True) form.fields['then'] = forms.ModelMultipleChoiceField(queryset=ThenAction.objects.filter(action__in=settings.UI_USER_THEN_ACTIONS).order_by('action'), required=True)
...@@ -183,22 +235,26 @@ def delete_route(request, route_slug): ...@@ -183,22 +235,26 @@ def delete_route(request, route_slug):
route = get_object_or_404(Route, name=route_slug) route = get_object_or_404(Route, name=route_slug)
applier_peer = route.applier.get_profile().peer applier_peer = route.applier.get_profile().peer
requester_peer = request.user.get_profile().peer requester_peer = request.user.get_profile().peer
if applier_peer == requester_peer: if applier_peer == requester_peer or request.user.is_superuser:
route.status = "PENDING" route.status = "PENDING"
route.expires = datetime.date.today() route.expires = datetime.date.today()
route.applier = request.user if not request.user.is_superuser:
route.applier = request.user
route.response = "Suspending"
route.save() route.save()
route.commit_delete() route.commit_delete()
requesters_address = request.META['HTTP_X_FORWARDED_FOR'] requesters_address = request.META['HTTP_X_FORWARDED_FOR']
mail_body = render_to_string("rule_delete_mail.txt", fqdn = Site.objects.get_current().domain
{"route": route, "address": requesters_address}) admin_url = "https://%s%s" % (fqdn, "/fod/edit/%s"%route.name)
mail_body = render_to_string("rule_action.txt",
{"route": route, "address": requesters_address, "action": "removal", "url": admin_url})
user_mail = "%s" %route.applier.email user_mail = "%s" %route.applier.email
user_mail = user_mail.split(';') user_mail = user_mail.split(';')
send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s removal request submitted by %s" %(route.name, route.applier.username), send_new_mail(settings.EMAIL_SUBJECT_PREFIX + "Rule %s removal request submitted by %s" %(route.name, route.applier.username),
mail_body, settings.SERVER_EMAIL, user_mail, mail_body, settings.SERVER_EMAIL, user_mail,
get_peer_techc_mails(route.applier)) get_peer_techc_mails(route.applier))
d = { 'clientip' : requesters_address, 'user' : route.applier.username } d = { 'clientip' : requesters_address, 'user' : route.applier.username }
logger.info(mail_body, extra=d) logger.info(mail_body, extra=d)
html = "<html><body>Done</body></html>" html = "<html><body>Done</body></html>"
return HttpResponse(html) return HttpResponse(html)
else: else:
...@@ -208,9 +264,15 @@ def delete_route(request, route_slug): ...@@ -208,9 +264,15 @@ def delete_route(request, route_slug):
@never_cache @never_cache
def user_profile(request): def user_profile(request):
user = request.user user = request.user
peer = request.user.get_profile().peer try:
peer = request.user.get_profile().peer
return render_to_response('profile.html', {'user': user, 'peer':peer}, peers = Peer.objects.filter(pk=peer.pk)
if user.is_superuser:
peers = Peer.objects.all()
except UserProfile.DoesNotExist:
error = "User <strong>%s</strong> does not belong to any peer or organization. It is not possible to create new firewall rules.<br>Please contact Helpdesk to resolve this issue" % user.username
return render_to_response('error.html', {'error': error})
return render_to_response('profile.html', {'user': user, 'peers':peers},
context_instance=RequestContext(request)) context_instance=RequestContext(request))
@never_cache @never_cache
...@@ -251,10 +313,14 @@ def user_login(request): ...@@ -251,10 +313,14 @@ def user_login(request):
context_instance=RequestContext(request)) context_instance=RequestContext(request))
try: try:
user = User.objects.get(username__exact=username) user = User.objects.get(username__exact=username)
user.email = mail
user.first_name = firstname
user.last_name = lastname
user.save()
user_exists = True user_exists = True
except: except:
user_exists = False user_exists = False
user = authenticate(username=username, firstname=firstname, lastname=lastname, mail=mail) user = authenticate(username=username, firstname=firstname, lastname=lastname, mail=mail, authsource='shibboleth')
if user is not None: if user is not None:
try: try:
peer = Peer.objects.get(domain_name=organization) peer = Peer.objects.get(domain_name=organization)
......
This diff is collapsed.
...@@ -45,7 +45,7 @@ a:hover { ...@@ -45,7 +45,7 @@ a:hover {
} }
#main { #main {
background: url("/static/background_grnet.png") repeat-x scroll 0 0 #FFFFFF; background: url("/static/background.png") repeat-x scroll 0 0 #FFFFFF;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
......
This diff is collapsed.
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Application submitted" %}{% endblock %}
{% block content %}
<div align="center">
{% if pending %}
<h2>{% trans "Pending applications" %}</h2>
<table>
<tr><th>{% trans "Hostname" %}</th><th>{% trans "User" %}</th><th>{% trans "Memory" %}</th><th>{% trans "vCPUs" %}</th><th>{% trans "Network" %}</th><th>{% trans "Filed" %}</th></tr>
{% for app in pending %}
<tr><td><a href="{% url application-review app.pk %}">{{ app.hostname }}</a></td><td>{{ app.applicant }}</td><td>{{ app.memory }}</td><td>{{ app.vcpus }}</td><td>{{ app.network|default_if_none:"&mdash;" }}</td><td>{{ app.filed|date }}</td></tr>
{% endfor %}
</table>
{% endif %}
<h2>{% trans "Completed applications" %}</h2>
<table>
<tr><th>{% trans "Hostname" %}</th><th>{% trans "User" %}</th><th>{% trans "Memory" %}</th><th>{% trans "vCPUs" %}</th><th>{% trans "Network" %}</th><th>{% trans "Filed" %}</th></tr>
{% for app in completed %}
<tr><td><a href="{% url application-review app.pk %}">{{ app.hostname }}</a></td><td>{{ app.applicant }}</td><td>{{ app.memory }}</td><td>{{ app.vcpus }}</td><td>{{ app.network|default_if_none:"&mdash;" }}</td><td>{{ app.filed|date }}</td></tr>
{% endfor %}
</table>
</div>
{% endblock %}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment