Commit 0d188bd6 by Őry Máté

Merge branch 'release-13.03.1' into releases

parents e0757a88 a5e7ec7a
......@@ -34,6 +34,10 @@ nosetests.xml
.project
.pydevproject
# Compiled CSS/JS resources
*.css
*.min.js
# Other
*.swp
*~
......
SHELL := /bin/bash
jsfiles += one/static/script/cloud.min.js
jsfiles += one/static/script/util.min.js
jsfiles += one/static/script/store.min.js
cssfiles += one/static/style/style.css
default: migrate collectstatic mo restart
default: migrate generatestatic collectstatic mo restart
pulldef: pull default
pull:
......@@ -14,6 +18,8 @@ po:
migrate:
./manage.py migrate
generatestatic: $(jsfiles) $(cssfiles)
collectstatic:
./manage.py collectstatic --noinput
......@@ -22,4 +28,10 @@ mo:
for i in */; do cd $$i; ls locale &>/dev/null && ../manage.py compilemessages || true; cd ..; done
restart:
sudo /etc/init.d/apache2 reload
sudo /etc/init.d/apache2 reload || sudo restart django
%.min.js: %.js
uglifyjs $< > $@
%.css: %.less
lessc one/static/style/style.less > one/static/style/style.css
from cloud.settings import DEBUG
def process_debug(req):
return {'DEBUG': DEBUG}
......@@ -5,7 +5,7 @@ DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
('IK', 'cloud@iit.bme.hu'),
('IK', 'cloud@cloud.ik.bme.hu'),
)
MANAGERS = ADMINS
......@@ -73,6 +73,7 @@ STATICFILES_DIRS = (
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'/opt/webadmin/cloud/one/static',
'/opt/webadmin/cloud/cloud/static',
)
# List of finder classes that know how to find static files in
......@@ -109,6 +110,17 @@ ROOT_URLCONF = 'cloud.urls'
# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'cloud.wsgi.application'
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'cloud.context_processors.process_debug',
)
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
......@@ -186,6 +198,8 @@ CELERY_ROUTES = {
'firewall.tasks.reload_firewall_task': {'queue': 'firewall'},
'firewall.tasks.reload_dhcp_task': {'queue': 'dhcp'},
'firewall.tasks.reload_blacklist_task': {'queue': 'firewall'},
'firewall.tasks.Periodic': {'queue': 'local'},
'one.tasks.SendMailTask': {'queue': 'local'},
}
store_settings = {
......@@ -200,7 +214,6 @@ store_settings = {
"store_public": "store.ik.bme.hu",
}
firewall_settings = {
"default_vlangroup": "publikus",
"reload_sleep": "10",
......@@ -210,6 +223,9 @@ firewall_settings = {
"dns_ttl": "300",
}
EMAIL_HOST='152.66.243.92' # giccero ipv4
CLOUD_URL='https://cloud.ik.bme.hu/'
try:
from cloud.local_settings import *
except:
......
<!DOCTYPE html>
<html lang="hu">
<head>
<title>IK Cloud</title>
<link href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css" />
<link rel="icon" type="image/png" href="/static/favicon.png" />
<link href="/static/style/style.css" rel="stylesheet" type="text/css" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div id="header">
<h1><a href="/">IK Cloud</a></h1>
</div>
<div id="content">
<div id="http-error">
<h1>Karbantartás – Maintenance</h1>
<p lang="hu">
Az oldal ideiglenesen nem érhető el karbantartás miatt. Elnézést kérünk a kellemetlenségekért.
</p>
<p lang="en">
The site is temporarily down for maintenance. We apologize for any inconvinience.
</p>
</div>
<div class="clear"></div>
</div>
<footer>
<a href="/sites/legal/">Impresszum</a> |
<a href="/sites/policy/">Szabályzat</a> |
<a href="/sites/help/">Súgó</a> |
<a href="/sites/support/">Támogatás</a> |
cloud <em>(kukac)</em> ik.bme.hu
</footer>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-39125666-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block js %}
<script type="text/javascript" src="{% static "script/store.js" %}"></script>
<style>
.contentblock p{
margin: 15px;
text-align: justify;
}
.contentblock img{
margin: 0px auto;
display: block;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);
border-radius: 5px;
text-align: center;
vertical-align: middle;
}
.boxes a:link,
a:visited {
color: black;
}
.boxes strong {
font-size: .9em;
}
</style>
{% endblock %}
{% block content %}
<div class="boxes">
<div class="contentblock" id="state">
<h2>A projektről</h2>
<div>
<p>Az <strong>IK Cloud</strong> a BME IK és IIT együttműködésében, a VIK
támogatásával hosszabb ideje folyó munka során jött létre.
A kutatás célja <strong>a cloud oktatási-kutatási célú felhasználásának</strong>
vonzóvá tétele.
</p>
<p>
A nagy kapacitású virtuális infrastruktúra azonban új lehetőséget is nyújt.
<strong>Igény szerint</strong> indíthatóak virtuális gépek:
gördülékennyé válik a tantermi és otthoni <strong>hallgatói munka,</strong>
a kutatási <strong>projektek dinamikus IT támogatása.</strong>
</p>
<p><img src="{% static "info/cloud-migration.png" %}" /></p>
<p>A rendszerünk segítségével <strong>kiváltható</strong> a tanszéken
működő öregedő szerverpark jelentős része.</p>
</div>
</div>
</div>
<div class="boxes">
<div class="contentblock" id="state">
<h2>Virtuális labor</h2>
<div>
<p><img src="{% static "info/cloud-lab.png" %}" /></p>
<p>Lehetőség van <strong>tantárgyra szabott környezet</strong> biztosítására
a tantermi mérések vagy az otthoni feladatok elvégzéséhez, vagy az
önkiszolgáló felületen pillanatok alatt indítható <strong>projektek, önálló
labor, szakdolgozat, diplomaterv, vagy TDK-munka</strong> segítéséhez
virtuális gép.</p>
<p style="text-align:center;"><a
href="{% url one.views.home %}">Próbálja ki a rendszert
most!</a></p>
</div>
</div>
<div class="contentblock" id="state" lang="en">
<h2>About the project</h2>
<div>
<p>The project aims to harness the power of cloud computing in
education and research. Our self service portal helps migrating
old servers, and on-demand launching appliances prepared by the
teacher.</p>
</p>
</div>
</div>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>A súgó elkészültéig kérjük szíves türelmüket.</p>
<p>Addig is ajánljuk figyelmükbe a rendszer <a href="/info/">rövid ismertetőjét</a>, a használat módját részletező <a href="/sites/policy/">szabályzatot</a>, valamint a felület számos pontján megjelenő <img src="{% static "icons/information-frame.png" %}" alt="Súgó" /> ikonnal jelölt információdobozokat.</p>
<p>Amennyiben kérdése maradt, örömmel segítünk a <a href="/sites/support/">támogatás</a> oldalon leírt elérhetőségeinken.</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>Az IK Cloud a BME IK és IIT együttműködésében, a VIK támogatásával létrejött rendszer, amelyben az IIT oktatói és hallgatói szükség szerint vehetnek igénybe virtuális erőforrásokat.
</p>
<p>Az oldal üzemeltetője a BME Közigazgatási Informatikai Központ.</p>
<p>A rendszer fejlesztésében részt vettek:
Bach Dániel,
Dányi Bence,
Dudás Ádám,
Guba Sándor,
Őry Máté és
dr. Szeberényi Imre.</p>
<p>A rendszer HP hardveren, Ubuntu operációs rendszeren, KVM virtualizációval, Open vSwitch virtuális hálózaton, libvirt köztes réteggel, OpenNebula cloud menedzserrel, Django alapú webportállal működik.</p>
<p>Some icons by <a href="http://p.yusukekamiyamane.com/">Yusuke Kamiyamane</a>. Licensed under a <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 License</a>.</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>Az IK Cloud a BME IK és IIT együttműködésében, a VIK támogatásával létrejött rendszer, amelyben az IIT oktatói és hallgatói szükség szerint vehetnek igénybe <strong>virtuális erőforrásokat</strong>.</p>
<p>Az IIT géptermeiben telepített kliensszoftver segítségével az oktató által előkészített és kiajánlott <strong>virtuális környezetet a hallgató</strong> a számára megszabott <strong>kvóta keretein belül</strong> igény szerint indíthatja.</p>
<p>A HSZK géptermeiben a kliensszoftver jelenleg nincs telepítve, de a virtuális gépek indítása, a fájlok elérése webböngészővel is teljes értékű; míg a gépekhez való csatlakozás kézzel elvégezhető.</p>
<p>Lehetőség van a gépteremben elkezdett munka otthoni folytatására is a korábban elindított környezetben. A rendszer segítségével az otthoni feladatot végző hallgató is elkerülheti az összetett szoftverkörnyezet telepítésével járó kellemetlenségeket, figyelmét a szakmai munkára irányíthatja.</p>
<p>A rendszer segítséget nyújt önálló labor, szakdolgozat, diplomaterv vagy tdk-munka készítésénél is: a munkához szükséges virtuális gépeket az önkiszolgáló rendszeren keresztül azonnal használatba lehet venni.</p>
<p>Az elindított virtuális gépekre az adott operációs rendszeren szokásos módon lehet távolról csatlakozni: Windows esetén RDP (távoli asztal), Linux esetén SSH, vagy grafikusan NoMachine NX segítségével. A kapcsolódást a géptermekben telepített kliensszoftver még kényelmesebbé teszi.</p>
<p>Az elindított gépeken a <strong>felhasználói adattár</strong> automatikusan csatolásra kerül. Minden munkát itt érdemes végezni, mivel az a gép leállítása után is elérhető marad.</p>
<p>A felhasználók a rendszert jelen önkiszolgáló felületen keresztül érhetik el, amelybe az egyetemi címtárszolgáltatás (eduID) segítségével léphetnek be. A továbblépéssel elfogadják a következőekben összefoglalt <strong>felhasználási feltételeket</strong>.</p>
<ul>
<li>A rendszer <strong>nem használható</strong> semmilyen jogszabályba, vagy <a href="http://net.bme.hu/regula/">egyetemi</a> <strong>szabályzatba ütköző tevékenységre</strong>.</li>
<li><strong>Kizárólag tanulmányi</strong> vagy <strong>kutatási tevékenységhez</strong> használható erőforrás.</li>
<li>Bár a rendszer használata térítésmentes, a <strong>felesleges gépek leállítása</strong> a felhasználó kötelessége.</li>
<li>Minden gép indítása <strong>határidő kijelölésével</strong> történik. A határidő lejártával <strong>a gépet megállítjuk</strong>. Amennyiben a felhasználó a megállítást követően (a törlési határidő leteltéig) nem kéri meghosszabbítását, a gépet és <strong>minden rajta lévő adatot törlünk!</strong></li>
<li>A felhasználó felelőssége a futtatott rendszer biztonságos üzemeltetése, a hosszabb időn át futó gépek frissítése.</li>
<li>A rendszert üzemeltető BME IK lehetőségeihez mérten mindent megtesz a szolgáltatásbiztos üzemért, az egyetemi infrastruktúra sajátosságai miatt előforduló üzemszünetekre azonban számítani kell. A BME IK az üzemeltetés kapcsán a folyamatos üzem sérüléséért vagy adatvesztésért <strong>minden felelősséget kizár</strong>. Ezeknek megfelelően szükség esetén a biztonsági mentés és a magas rendelkezésre állású környezet kialakítása a felhasználóra hárul.</li>
</ul>
<p>A szabályok betartása közös érdekünk. Reméljük, hogy a rendszerünk használata megkönnyíti munkájukat, melyhez sok sikert kívánunk!</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="irasmu">
<p>A rendszer használatával kapcsolatos kérdéseket, általános észrevételeket a <tt>cloud <em>(kukac)</em>
ik.bme.hu</tt> e-mail címen várjuk.
Ugyancsak örömmel fogadjuk a rendszer használatával kapcsolatos beszámolókat.</p>
<p>A rendszerben talált hibákat (vagy azok gyanúját), valamint ötleteit, javaslatait kérjük,
<a href="https://giccero.cloud.ik.bme.hu/trac/cloud/newticket" rel="nofollow">
hibajegy felvételével</a> jelezze.
</p>
</div>
{% endblock %}
......@@ -5,107 +5,91 @@ admin.autodiscover()
import one.views
import firewall.views
#import store.views
# import store.views
js_info_dict = {
'packages': ('one', ),
}
urlpatterns = patterns('',
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'one.views.home', name='home'),
url(r'^login/$', 'school.views.login', name='login'),
url(r'^logout/$', 'school.views.logout', name='logout'),
url(r'^vm/new/(?P<template>\d+)/$', 'one.views.vm_new', name='vm_new'),
url(r'^ajax/vm/new/(?P<template>\d+)/$', 'one.views.vm_new_ajax',
name='vm_new_ajax'),
url(r'^vm/new/s(?P<share>\d+)/$', 'one.views.vm_new', name='vm_new'),
url(r'^vm/show/(?P<iid>\d+)/$', 'one.views.vm_show', name='vm_show'),
url(r'^vm/delete/(?P<iid>\d+)/$', 'one.views.vm_delete',
name='vm_delete'),
url(r'^vm/stop/(?P<iid>\d+)/$', 'one.views.vm_stop', name='vm_stop'),
url(r'^vm/unshare/(?P<id>\d+)/$', 'one.views.vm_unshare',
name='vm_unshare'),
url(r'^vm/resume/(?P<iid>\d+)/$', 'one.views.vm_resume',
name='vm_resume'),
url(r'^vm/power_off/(?P<iid>\d+)/$', 'one.views.vm_power_off',
name='vm_power_off'),
url(r'^vm/restart/(?P<iid>\d+)/$', 'one.views.vm_restart',
name='vm_restart'),
url(r'^admin/doc/', include('django.contrib.admindocs.urls'), ),
url(r'^admin/', include(admin.site.urls), ),
url(r'^login/$', 'school.views.login', name='login', ),
url(r'^logout/$', 'school.views.logout', name='logout', ),
url(r'^$', 'one.views.index', ),
url(r'^info/$', 'one.views.info', ),
url(r'^home/$', 'one.views.home', ),
url(r'^vm/new/(?P<template>\d+)/$', 'one.views.vm_new',
name='new_vm_from_template'),
url(r'^ajax/vm/new/(?P<template>\d+)/$', 'one.views.vm_new_ajax', ),
url(r'^vm/new/s(?P<share>\d+)/$', 'one.views.vm_new',
name='new_vm_form_share'),
url(r'^vm/show/(?P<iid>\d+)/$', 'one.views.vm_show', ),
url(r'^vm/delete/(?P<iid>\d+)/$', 'one.views.vm_delete', ),
url(r'^vm/stop/(?P<iid>\d+)/$', 'one.views.vm_stop', ),
url(r'^vm/unshare/(?P<id>\d+)/$', 'one.views.vm_unshare', ),
url(r'^vm/resume/(?P<iid>\d+)/$', 'one.views.vm_resume', ),
url(r'^vm/power_off/(?P<iid>\d+)/$', 'one.views.vm_power_off', ),
url(r'^vm/restart/(?P<iid>\d+)/$', 'one.views.vm_restart', ),
url(r'^vm/renew/(?P<which>(suspend|delete))/(?P<iid>\d+)/$',
'one.views.vm_renew', name='vm_renew'),
url(r'^vm/port_add/(?P<iid>\d+)/$', 'one.views.vm_port_add',
name='vm_port_add'),
'one.views.vm_renew', ),
url(r'^vm/port_add/(?P<iid>\d+)/$', 'one.views.vm_port_add', ),
url(r'^vm/port_del/(?P<iid>\d+)/(?P<proto>tcp|udp)/(?P<public>\d+)/$',
'one.views.vm_port_del', name='vm_port_del'),
url(r'^vm/saveas/(?P<vmid>\d+)$', 'one.views.vm_saveas',
name='vm_saveas'),
url(r'^vm/credentials/(?P<iid>\d+)$', 'one.views.vm_credentials',
name='vm_credentials'),
url(r'^reload/$', 'firewall.views.reload_firewall',
name='reload_firewall'),
url(r'^fwapi/$', 'firewall.views.firewall_api',
name='firewall_api'),
url(r'^store/$', 'store.views.index', name='store_index'),
url(r'^store/gui/$', 'store.views.gui', name='store_gui'),
url(r'^store/top/$', 'store.views.toplist', name='store_top'),
url(r'^ajax/store/top/$', 'store.views.ajax_toplist',
name='axat_store_top'),
url(r'^ajax/templateWizard$', 'one.views.ajax_template_wizard',
name='ajax_template_wizard'),
url(r'^ajax/share/(?P<id>\d+)/$', 'one.views.ajax_share_wizard',
name='ajax_share_wizard'),
'one.views.vm_port_del', ),
url(r'^ajax/shareEdit/(?P<id>\d+)/$', 'one.views.ajax_share_edit_wizard',
name='ajax_share_edit_wizard'),
url(r'^vm/saveas/(?P<vmid>\d+)$', 'one.views.vm_saveas', ),
url(r'^vm/credentials/(?P<iid>\d+)$', 'one.views.vm_credentials', ),
url(r'^ajax/templateWizard/$', 'one.views.ajax_template_wizard', ),
url(r'^ajax/templateEditWizard/(?P<id>\d+)/$', 'one.views.ajax_template_edit_wizard', ),
url(r'^ajax/share/(?P<id>\d+)/$', 'one.views.ajax_share_wizard', ),
url(r'^ajax/share/(?P<id>\d+)/(?P<gid>\d+)$',
'one.views.ajax_share_wizard', name='ajax_share_wizard'),
url(r'^ajax/template/delete/$', 'one.views.ajax_template_delete',
name='ajax_template_delete'),
url(r'^ajax/template_name_unique/(?P<name>.*)$',
'one.views.ajax_template_name_unique',
name='ajax_template_name_unique'),
url(r'^ajax/store/list$', 'store.views.ajax_listfolder',
name='store_ajax_listfolder'),
url(r'^ajax/store/download$', 'store.views.ajax_download',
name='store_ajax_download'),
url(r'^ajax/store/upload$', 'store.views.ajax_upload',
name='store_ajax_upload'),
url(r'^ajax/store/delete$', 'store.views.ajax_delete',
name='store_ajax_delete'),
url(r'^ajax/store/newFolder$', 'store.views.ajax_new_folder',
name='store_ajax_new_folder'),
url(r'^ajax/store/quota$', 'store.views.ajax_quota',
name='store_ajax_quota'),
url(r'^ajax/store/rename$', 'store.views.ajax_rename',
name='store_ajax_rename'),
'one.views.ajax_share_wizard', ),
url(r'^ajax/vm/status/(?P<iid>\d+)$',
'one.views.vm_ajax_instance_status',
name='vm_ajax_instance_status'),
'one.views.vm_ajax_instance_status', ),
url(r'^ajax/vm/rename/(?P<iid>\d+)/$',
'one.views.vm_ajax_rename',
name='vm_ajax_rename'),
url(r'^language/(?P<lang>[-A-Za-z]+)/$', 'school.views.language',
name='language'),
url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
url(r'^b/(?P<token>.*)/$', 'one.views.boot_token', name='boot_token'),
'one.views.vm_ajax_rename', ),
url(r'^key/add/$', 'one.views.key_add', ),
url(r'^ajax/key/delete/$', 'one.views.key_ajax_delete', ),
url(r'^ajax/key/reset/$', 'one.views.key_ajax_reset', ),
url(r'^ajax/template/delete/$', 'one.views.ajax_template_delete', ),
url(r'^ajax/template_name_unique/$',
'one.views.ajax_template_name_unique', ),
url(r'^reload/$', 'firewall.views.reload_firewall', ),
url(r'^fwapi/$', 'firewall.views.firewall_api', ),
url(r'^store/$', 'store.views.index', ),
url(r'^store/gui/$', 'store.views.gui', ),
url(r'^store/top/$', 'store.views.toplist', ),
url(r'^ajax/store/top/$', 'store.views.ajax_toplist', ),
url(r'^ajax/store/list$', 'store.views.ajax_listfolder', ),
url(r'^ajax/store/download$', 'store.views.ajax_download', ),
url(r'^ajax/store/upload$', 'store.views.ajax_upload', ),
url(r'^ajax/store/delete$', 'store.views.ajax_delete', ),
url(r'^ajax/store/newFolder$', 'store.views.ajax_new_folder', ),
url(r'^ajax/store/quota$', 'store.views.ajax_quota', ),
url(r'^ajax/store/rename$', 'store.views.ajax_rename', ),
url(r'^language/(?P<lang>[-A-Za-z]+)/$', 'school.views.language', ),
url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict, ),
url(r'^b/(?P<token>.*)/$', 'one.views.boot_token', ),
url(r'^group/show/(?P<gid>\d+)/$', 'school.views.group_show',
name='group_show'),
url(r'^group/new/$', 'school.views.group_new', name='group_new'),
url(r'^group/new/$', 'school.views.group_new', ),
url(r'^ajax/group/(?P<gid>\d+)/add/$',
'school.views.group_ajax_add_new_member',
name='group_ajax_add_new_member'),
'school.views.group_ajax_add_new_member', ),
url(r'^ajax/group/(?P<gid>\d+)/addOwner/$',
'school.views.group_ajax_add_new_owner',
name='group_ajax_add_new_owner'),
'school.views.group_ajax_add_new_owner', ),
url(r'^ajax/group/(?P<gid>\d+)/remove/$',
'school.views.group_ajax_remove_member',
name='group_ajax_remove_member'),
url(r'^ajax/group/delete/$', 'school.views.group_ajax_delete',
name='group_ajax_delete'),
url(r'^ajax/group/autocomplete/$', 'school.views.group_ajax_owner_autocomplete',
name='group_ajax_autocomplete'),
url(r'^key/add/$', 'one.views.key_add', name='key_add'),
url(r'^ajax/key/delete/$', 'one.views.key_ajax_delete',
name='key_ajax_delete'),
url(r'^ajax/key/reset/$', 'one.views.key_ajax_reset',
name='key_ajax_reset'),
'school.views.group_ajax_remove_member', ),
url(r'^ajax/group/delete/$', 'school.views.group_ajax_delete', ),
url(r'^ajax/group/autocomplete/$',
'school.views.group_ajax_owner_autocomplete', ),
url(r'^stat/$', 'one.views.stat'),
url(r'^sites/(?P<site>[a-zA-Z0-9]+)/$', 'one.views.sites'),
url(r'^accounts/(?P<site>profile)/$', 'one.views.sites'),
)
......@@ -13,7 +13,7 @@ class RecordInline(contrib.admin.TabularInline):
class HostAdmin(admin.ModelAdmin):
list_display = ('hostname', 'vlan', 'ipv4', 'ipv6', 'pub_ipv4', 'mac',
'shared_ip', 'owner', 'description', 'reverse', 'groups_l')
'shared_ip', 'owner', 'description', 'reverse', 'list_groups')
ordering = ('hostname', )
list_filter = ('owner', 'vlan', 'groups')
search_fields = ('hostname', 'description', 'ipv4', 'ipv6', 'mac')
......@@ -21,7 +21,7 @@ class HostAdmin(admin.ModelAdmin):
inlines = (RuleInline, RecordInline)
@staticmethod
def groups_l(instance):
def list_groups(instance):
"""Returns instance's groups' names as a comma-separated list."""
names = [group.name for group in instance.groups.all()]
return u', '.join(names)
......@@ -45,34 +45,36 @@ class RuleAdmin(admin.ModelAdmin):
def color_desc(self, instance):
"""Returns a colorful description of the instance."""
para = '</span>'
if instance.dport:
para = 'dport=%s %s' % (instance.dport, para)
if instance.sport:
para = 'sport=%s %s' % (instance.sport, para)
if instance.proto:
para = 'proto=%s %s' % (instance.proto, para)
para = u'<span style="color: #00FF00;">' + para
return (
u'<span style="color: #FF0000;">[%s]</span> ' % instance.r_type +
(u'%s<span style="color: #0000FF;"> ▸ </span>%s' %
((instance.foreign_network.name, instance.r_type)
if instance.direction == '1' else
(instance.r_type, instance.foreign_network.name))) +
' ' + para + ' ' + instance.description)
return (u'<span style="color: #FF0000;">[%(type)s]</span> '
u'%(src)s<span style="color: #0000FF;"> ▸ </span>%(dst)s '
u'%(para)s %(desc)s') % {
'type': instance.r_type,
'src': (instance.foreign_network.name
if instance.direction == '1' else instance.r_type),
'dst': (instance.r_type if instance.direction == '1'
else instance.foreign_network.name),
'para': (u'<span style="color: #00FF00;">' +
(('proto=%s ' % instance.proto)
if instance.proto else '') +
(('sport=%s ' % instance.sport)
if instance.sport else '') +
(('dport=%s ' % instance.dport)
if instance.dport else '') +
'</span>'),
'desc': instance.description}
color_desc.allow_tags = True
def vlan_l(self, instance):
@staticmethod
def vlan_l(instance):
"""Returns instance's VLANs' names as a comma-separated list."""
retval = []
for vlan in instance.foreign_network.vlans.all():
retval.append(vlan.name)
return u', '.join(retval)
names = [vlan.name for vlan in instance.foreign_network.vlans.all()]
return u', '.join(names)
def used_in(self, instance):
@staticmethod
def used_in(instance):
for field in [instance.vlan, instance.vlangroup, instance.host,
instance.hostgroup, instance.firewall]:
if field is not None:
if field:
return unicode(field) + ' ' + field._meta.object_name
......@@ -92,15 +94,15 @@ class DomainAdmin(admin.ModelAdmin):
class RecordAdmin(admin.ModelAdmin):
list_display = ('name_', 'type', 'address_', 'ttl', 'host', 'owner')
def address_(self, instance):
@staticmethod
def address_(instance):
a = instance.get_data()
if a:
return a['address']
return a['address'] if a else None
def name_(self, instance):
@staticmethod
def name_(instance):
a = instance.get_data()
if a:
return a['name']
return a['name'] if a else None
class BlacklistAdmin(admin.ModelAdmin):
list_display = ('ipv4', 'reason', 'created_at', 'modified_at')
......
......@@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError
from django.forms import fields
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.ipv6 import is_valid_ipv6_address
from south.modelsinspector import add_introspection_rules
import re
......@@ -35,26 +36,46 @@ class MACAddressField(models.Field):
add_introspection_rules([], ["firewall\.fields\.MACAddressField"])
def val_alfanum(value):
"""Check whether the parameter is a valid alphanumeric value."""
if alfanum_re.search(value) is None:
raise ValidationError(
_(u'%s - only letters, numbers, underscores and hyphens are '
'allowed!') % value)
"""Validate whether the parameter is a valid alphanumeric value."""
if not alfanum_re.match(value):
raise ValidationError(_(u'%s - only letters, numbers, underscores '
'and hyphens are allowed!') % value)
def is_valid_domain(value):
"""Check whether the parameter is a valid domain name."""
return domain_re.match(value) is not None
def val_domain(value):
"""Check wheter the parameter is a valid domin."""
if domain_re.search(value) is None:
raise ValidationError(_(u'%s - invalid domain') % value)
"""Validate whether the parameter is a valid domin name."""
if not is_valid_domain(value):
raise ValidationError(_(u'%s - invalid domain name') % value)
def is_valid_reverse_domain(value):
"""Check whether the parameter is a valid reverse domain name."""
return reverse_domain_re.match(value) is not None
def val_reverse_domain(value):
"""Check whether the parameter is a valid reverse domain."""
if not reverse_domain_re.search(value):
raise ValidationError(u'%s - reverse domain' % value)
"""Validate whether the parameter is a valid reverse domain name."""
if not is_valid_reverse_domain(value):
raise ValidationError(u'%s - invalid reverse domain name' % value)
def is_valid_ipv4_address(value):
"""Check whether the parameter is a valid IPv4 address."""
return ipv4_re.match(value) is not None
def val_ipv4(value):
"""Validate whether the parameter is a valid IPv4 address."""
if not is_valid_ipv4_address(value):
raise ValidationError(_(u'%s - not an IPv4 address') % value)
def val_ipv6(value):
"""Validate whether the parameter is a valid IPv6 address."""
if not is_valid_ipv6_address(value):
raise ValidationError(_(u'%s - not an IPv6 address') % value)
def ipv4_2_ipv6(ipv4):
"""Convert IPv4 address string to IPv6 address string."""
val_ipv4(ipv4)
m = ipv4_re.match(ipv4)
if m is None:
raise ValidationError(_(u'%s - not an IPv4 address') % ipv4)
return ("2001:738:2001:4031:%s:%s:%s:0" %
(m.group(1), m.group(2), m.group(3)))
......@@ -10,7 +10,7 @@ from datetime import datetime, timedelta
from django.db.models import Q
class firewall:
class Firewall:
IPV6=False
RULES = None
RULES_NAT = []
......@@ -36,14 +36,15 @@ class firewall:
def iptables(self, s):
"""Append rule."""
"""Append rule to filter table."""
self.RULES.append(s)
def iptablesnat(self, s):
"""Append rule to NAT table."""
self.RULES_NAT.append(s)
def host2vlan(self, host, rule):
if rule.foreign_network is None:
if not rule.foreign_network:
return
if self.IPV6 and host.ipv6:
......@@ -76,7 +77,7 @@ class firewall:
def fw2vlan(self, rule):
if rule.foreign_network is None:
if not rule.foreign_network:
return
dport_sport = self.dportsport(rule)
......@@ -92,7 +93,7 @@ class firewall:
'LOG_ACC' if rule.accept else 'LOG_DROP'))
def vlan2vlan(self, l_vlan, rule):
if rule.foreign_network is None:
if not rule.foreign_network:
return
dport_sport = self.dportsport(rule)
......
......@@ -19,44 +19,47 @@ def reload_dhcp_task(data):
def reload_blacklist_task(data):
pass
class Periodic(PeriodicTask):
run_every = timedelta(seconds=10)
def run(self, **kwargs):
if cache.get('dns_lock'):
cache.delete("dns_lock")
reload_dns_task.delay(dns())
print "dns ujratoltese kesz"
if cache.get('dhcp_lock'):
cache.delete("dhcp_lock")
reload_dhcp_task.delay(dhcp())
print "dhcp ujratoltese kesz"
if cache.get('firewall_lock'):
cache.delete("firewall_lock")
ipv4 = Firewall().get()
ipv6 = Firewall(True).get()
reload_firewall_task.delay(ipv4, ipv6)
print "firewall ujratoltese kesz"
if cache.get('blacklist_lock'):
cache.delete("blacklist_lock")
reload_blacklist_task.delay(list(ipset()))
print "blacklist ujratoltese kesz"
class ReloadTask(Task):
def run(self, type='Host'):
sleep=False
if type in ["Host", "Records", "Domain", "Vlan"]:
lock = lambda: cache.add("dns_lock", "true", 9)
if lock():
if not sleep:
sleep = True
time.sleep(10)
reload_dns_task.delay(dns())
cache.add("dns_lock", "true", 30)
if type == "Host":
lock = lambda: cache.add("dhcp_lock", "true", 9)
if lock():
if not sleep:
sleep = True
time.sleep(10)
reload_dhcp_task.delay(dhcp())
cache.add("dhcp_lock", "true", 30)
if type in ["Host", "Rule", "Firewall"]:
lock = lambda: cache.add("firewall_lock", "true", 9)
if lock():
if not sleep:
sleep = True
time.sleep(10)
ipv4 = firewall().get()
ipv6 = firewall(True).get()
reload_firewall_task.delay(ipv4, ipv6)
cache.add("firewall_lock", "true", 30)
if type == "Blacklist":
lock = lambda: cache.add("blacklist_lock", "true", 9)
if lock():
if not sleep:
sleep = True
time.sleep(10)
reload_blacklist_task.delay(list(ipset()))
cache.add("blacklist_lock", "true", 30)
print type
......@@ -16,21 +16,19 @@ class MockGroups:
def all(self):
return self.groups
class HostAdminNoGroupTestCase(TestCase):
def runTest(self):
class HostAdminTestCase(TestCase):
def test_no_groups(self):
instance = MockInstance([])
l = HostAdmin.groups_l(instance)
l = HostAdmin.list_groups(instance)
self.assertEqual(l, "")
class HostAdminSingleGroupTestCase(TestCase):
def runTest(self):
def test_sigle_group(self):
instance = MockInstance([MockGroup("alma")])
l = HostAdmin.groups_l(instance)
l = HostAdmin.list_groups(instance)
self.assertEqual(l, "alma")
class HostAdminMultipleGroupsTestCase(TestCase):
def runTest(self):
def test_multiple_groups(self):
instance = MockInstance([MockGroup("alma"),
MockGroup("korte"), MockGroup("szilva")])
l = HostAdmin.groups_l(instance)
l = HostAdmin.list_groups(instance)
self.assertEqual(l, "alma, korte, szilva")
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.shortcuts import render_to_response
from firewall.models import *
from firewall.fw import *
from django.views.decorators.csrf import csrf_exempt
......@@ -9,23 +8,27 @@ from django.db import IntegrityError
from tasks import *
from celery.task.control import inspect
from django.utils.translation import ugettext_lazy as _
from django.template.loader import render_to_string
from cloud.settings import CLOUD_URL as url
from django.utils import translation
import re
import base64
import json
import sys
import datetime
from django.utils.timezone import utc
from one.tasks import SendMailTask
def reload_firewall(request):
if request.user.is_authenticated():
if request.user.is_superuser:
html = ((_("Dear %s, you've signed in as administrator!") %
request.user.username) + "<br />" +
_("Reloading in 10 seconds..."))
html = (_("Dear %s, you've signed in as administrator!<br />"
"Reloading in 10 seconds...") % request.user.username)
ReloadTask.delay()
else:
html = (_("Dear %s, you've signed in!")
% request.user.username)
html = (_("Dear %s, you've signed in!") % request.user.username)
else:
html = _("Dear anonymous, you've not signed in yet!")
return HttpResponse(html)
......@@ -41,16 +44,29 @@ def firewall_api(request):
if command == "blacklist":
obj, created = Blacklist.objects.get_or_create(ipv4=data["ip"])
if created:
obj.reason=data["reason"]
obj.snort_message=data["snort_message"]
if created:
try:
obj.host = models.Host.objects.get(ipv4=data["ip"])
user = obj.host.owner
lang = user.person_set.all()[0].language
translation.activate(lang)
msg = render_to_string('mails/notification-ban-now.txt', { 'user': user, 'bl': obj, 'instance:': obj.host.instance_set.get(), 'url': url} )
SendMailTask.delay(to=obj.host.owner.email, subject='[IK Cloud] %s' % obj.host.instance_set.get().name, msg=msg, sender=u'cloud@ik.bme.hu')
except (Host.DoesNotExist, ValidationError, IntegrityError, AttributeError):
pass
print obj.modified_at + datetime.timedelta(minutes=5)
print datetime.datetime.utcnow().replace(tzinfo=utc)
if obj.type == 'tempwhite' and obj.modified_at + datetime.timedelta(minutes=1) < datetime.datetime.utcnow().replace(tzinfo=utc):
obj.type = 'tempban'
obj.save()
return HttpResponse(unicode(_("OK")));
return HttpResponse(unicode(_("OK")))
if not (data["vlan"] == "vm-net" or data["vlan"] == "war"):
raise Exception(_("Only vm-net and war can be used."))
data["hostname"] = re.sub(r' ','_', data["hostname"])
data["hostname"] = re.sub(r' ', '_', data["hostname"])
if command == "create":
data["owner"] = "opennebula"
......@@ -78,14 +94,13 @@ def firewall_api(request):
host = models.Host.objects.get(hostname=data["hostname"],
owner=owner)
host.del_rules()
host.delete()
else:
raise Exception(_("Unknown command."))
except (ValidationError, IntegrityError, AttributeError, Exception) as e:
return HttpResponse(_("Something went wrong!\n%s\n") % e);
return HttpResponse(_("Something went wrong!\n%s\n") % e)
except:
return HttpResponse(_("Something went wrong!\n"));
return HttpResponse(_("Something went wrong!\n"))
return HttpResponse(unicode(_("OK")));
return HttpResponse(unicode(_("OK")))
......@@ -10,4 +10,4 @@ sed -i 's/^<volume user=.*//' /etc/security/pam_mount.conf.xml
rm -rf ~cloud/{.bash_history,.ssh/id_rsa}
rm -rf ~root/{.bash_history}
rm -rf /etc/ssh/ssh_host_*
rm -rf /usr/NX/home/nx/.ssh/known_hosts
......@@ -3,6 +3,12 @@
echo "En vagyok a $0 !"
hostname "$HOSTNAME"
echo "$HOSTNAME" > /etc/hostname
if [ "$DISTRO" == "ubuntu" ]; then
echo "$HOSTNAME" > /etc/hostname
fi
if [ "$DISTRO" == "redhat" ]; then
echo -e -n "NETWORKING=yes\nHOSTNAME=$HOSTNAME\n" > /etc/sysconfig/network
fi
sed "s/\(127\.0\.1\.1\).*/\1\t$HOSTNAME/" -i /etc/hosts
......@@ -13,6 +13,7 @@ echo ok "$ipv4 $ipv6 $gw4 $gw6"
/etc/init.d/network-manager stop
ifdown eth0 || ifconfig eth0 0 down
if [ "$DISTRO" == "ubuntu" ]; then
cat > /etc/network/interfaces << EOF
auto lo
iface lo inet loopback
......@@ -30,4 +31,28 @@ EOF
ifup eth0
fi
if [ "$DISTRO" == "redhat" ]; then
cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF
DEVICE="eth0"
BOOTPROTO="none"
IPV6INIT="yes"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"
DNS1="152.66.243.60"
PEERDNS="yes"
IPADDR="$ipv4"
NETMASK="255.255.0.0"
GATEWAY=$gw4
IPV6ADDR="$ipv6/80"
IPV6_DEFAULTGW="$gw6"
EOF
ifup eth0
fi
......@@ -5,8 +5,14 @@ echo "En vagyok a $0 !"
mkdir -p "$HOME/.ssh"
echo "$SSHPRIV" > $HOME/.ssh/id_rsa
chmod 600 "$HOME/.ssh/id_rsa"
echo "$SSHPUB" >> "$HOME/.ssh/authorized_keys"
mkdir "$HOME/sshfs"
chown "$USER:$USER" -R "$HOME"
sed -i 's/^<volume user=.*//' /etc/security/pam_mount.conf.xml
sed -i "s/^\(<\/pam_mount>.*\)/<volume user=\"$USER\" fstype=\"fuse\" path=\"sshfs#${NEPTUN}@${SERVER}:home\" mountpoint=\"~\/sshfs\" options=\"nonempty,reconnect,StrictHostKeyChecking=no\" \/>\n\1/" /etc/security/pam_mount.conf.xml
sed -i 's/^sshfs.*//' /etc/fstab
cat >> /etc/fstab <<END
sshfs#${NEPTUN}@${SERVER}:home $HOME/sshfs fuse defaults,idmap=user,reconnect,_netdev,uid=1000,gid=1000,allow_other,StrictHostKeyChecking=no,IdentityFile=$HOME/.ssh/id_rsa 0 0
END
mount "$HOME/sshfs"
......@@ -2,6 +2,7 @@
echo "En vagyok a $0 !"
wget -q -O /dev/null "$BOOTURL"
( while ! wget -T 2 -t 1 -q --no-check-certificate -O /dev/null "$BOOTURL" ; do sleep 5; done ) &
disown $!
......@@ -4,6 +4,15 @@ export BASEDIR=$(dirname $0)
export USER="cloud"
export HOME=$(awk -F: -v u=$USER '$1==u{print $6}' /etc/passwd)
if [ -f /etc/lsb-release ]; then
export DISTRO=ubuntu
fi
if [ -f /etc/redhat-release ]; then
export DISTRO=redhat
fi
echo $DISTRO
mkdir -p "$BASEDIR/mnt"
cd "$BASEDIR"
......
......@@ -16,40 +16,5 @@
"email": "",
"date_joined": "2013-01-16T12:36:01Z"
}
},
{
"pk": 9,
"model": "one.template",
"fields": {
"name": "Ubuntu 12.04 desktop",
"created_at": "2013-01-31T10:11:08Z",
"access_type": "nx",
"instance_type": 3,
"owner": 1,
"disk": 1,
"network": 2
}
},
{
"pk": 10,
"model": "one.template",
"fields": {
"name": "Windows 7",
"created_at": "2013-01-31T10:11:21Z",
"access_type": "rdp",
"instance_type": 2,
"owner": 1,
"disk": 1,
"network": 2
}
},
{
"pk": 2,
"model": "one.network",
"fields": {
"name": "VM-NET",
"nat": true,
"public": false
}
}
]
......@@ -5,15 +5,15 @@ for i in cloudstore toplist django
do
sudo stop $i || true
done
set -x
cd /opt/webadmin/cloud
./manage.py syncdb --noinput
./manage.py migrate
./manage.py loaddata miscellaneous/dump.json
./manage.py loaddata miscellaneous/devenv/dev.json
./manage.py update
./manage.py loaddata miscellaneous/devenv/dev.json
set +x
sudo apt-get install rabbitmq-server gettext
sudo rabbitmqctl delete_user guest || true
sudo rabbitmqctl add_user nyuszi teszt || true
sudo rabbitmqctl add_vhost django || true
sudo rabbitmqctl set_permissions -p django nyuszi '.*' '.*' '.*' || true
sudo cp /opt/webadmin/cloud/miscellaneous/devenv/boot_url.py /opt/
#Set up store server
rm -rf /var/www/*
......@@ -44,6 +44,18 @@ do
sudo start $i
done
set -x
cd /opt/webadmin/cloud
./manage.py syncdb --noinput
./manage.py migrate
./manage.py loaddata miscellaneous/dump.json
./manage.py loaddata miscellaneous/devenv/dev.json
./manage.py update
./manage.py loaddata miscellaneous/devenv/dev.json
set +x
cd /opt/webadmin/cloud/miscellaneous/devenv
sudo cp vimrc.local /etc/vim/vimrc.local
......@@ -52,16 +64,11 @@ sudo cp vimrc.local /etc/vim/vimrc.local
cd /opt/webadmin/cloud
./manage.py changepassword test
git config --global alias.prettylog 'log --graph --all --decorate --date-order --pretty="%C(yellow)%h%Cred%d%Creset - %C(cyan)%an %Creset: %s %Cgreen(%cr)"'
git config --global alias.prettylog 'log --graph --all --decorate --date-order --pretty="%C(yellow)%h%Cred%d%Creset - %C(cyan)%an %Creset: %s %Cgreen(%ar)"'
git config --global alias.civ 'commit --interactive --verbose'
git config --global color.ui true
git config --global core.editor vim
true
sudo apt-get install rabbitmq-server
sudo rabbitmqctl delete_user guest
sudo rabbitmqctl add_user nyuszi teszt
sudo rabbitmqctl add_vhost django
sudo rabbitmqctl set_permissions -p django nyuszi '.*' '.*' '.*'
......@@ -7,4 +7,6 @@ set et
set sw=4
set ai
set smarttab
set textwidth=76
set colorcolumn=76
#!/bin/bash
/opt/webadmin/cloud/manage.py dumpdata -e admin -e one.userclouddetails -e school -e auth.permission -e contenttypes -e sessions -e djcelery --format=json --indent=2|grep -v '"password":'|sed -e 's/^.*"smb_password":.*$/"smb_password": "kamu",/' -e 's/BEGIN RSA PRIVATE.*END RSA/xxx/' >/opt/webadmin/cloud/miscellaneous/dump.json
/opt/webadmin/cloud/manage.py dumpdata -e admin -e auth.permission -e contenttypes -e sessions -e djcelery --format=json --indent=2|grep -v '"password":'|sed -e 's/^.*"smb_password":.*$/"smb_password": "kamu",/' -e 's/BEGIN RSA PRIVATE.*END RSA/xxx/' >/opt/webadmin/cloud/miscellaneous/dump.json
......@@ -6,11 +6,19 @@ import os
import sys
import gtk
import gobject
from multiprocessing import Manager, Process
import threading
import signal
import time
class RDP:
def __init__(self, uri):
gobject.threads_init()
self.scheme, self.username, self.password, self.host, self.port = uri.split(':',4)
self.manager = Manager()
self.global_vars = self.manager.Namespace()
self.global_vars.pid = 0
self.box = gtk.MessageDialog(parent=None, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CANCEL, message_format="Connecting to RDP...")
def dialog_box(self,text):
# Window = gtk.Window()
# Window.set_size_request(250, 100)
......@@ -19,12 +27,27 @@ class RDP:
# window.set_title("Message dialogs")
md = gtk.MessageDialog(parent=None, type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_CLOSE, message_format=text)
md.run()
print "After run"
md.destroy()
def connect(self):
#rdp:cloud:qYSv3eQJYY:152.66.243.62:23037
if self.scheme == "rdp":
self.connect_rdp()
#print self.global_vars.pid
p = threading.Thread(target=self.connect_rdp, args=[self.global_vars])
p.start()
while self.global_vars.pid == 0:
time.sleep(1)
#print "Rdesktop pid: "+str(self.global_vars.pid)
#print self.box
return_value = self.box.run()
#print "Box return value: "+str(return_value)
if return_value != -5:
#p.terminate()
if self.global_vars.pid > 0:
os.kill(self.global_vars.pid, signal.SIGKILL)
#print "Join"
p.join()
elif self.scheme == "nx":
self.connect_nx()
elif self.scheme == "sshterm":
......@@ -49,15 +72,13 @@ class RDP:
except:
self.dialog_box("Unable to connect to host: "+self.host+" at port "+self.port)
def connect_rdp(self):
def connect_rdp(self,global_vars):
rdp_command = ["rdesktop", "-khu", "-E", "-P", "-0", "-f", "-u", self.username, "-p", self.password, self.host+":"+self.port]
try:
proc = subprocess.check_call(rdp_command, stdout = subprocess.PIPE)
except subprocess.CalledProcessError as e:
if e.returncode != 1:
print e
print e.returncode
self.dialog_box("Unable to connect to host: "+self.host+" at port "+self.port)
proc = subprocess.Popen(rdp_command, stdout = subprocess.PIPE)
global_vars.pid = proc.pid
proc.wait()
self.box.response(-5)
global_vars.pid = 0
def connect_nx(self):
#Generate temproary config
......
from setuptools import setup, find_packages
setup(
name = "CloudGUI",
version = "0.1",
version = "0.2",
packages = ['cloudgui',],
scripts = ['cloud','rdp',],
)
#!/usr/bin/python
import xmltodict
import xml.dom.minidom as minidom
import sys
import json
import math
xml = sys.stdin.read()
data = minidom.parseString(xml)
node = data.documentElement
hosts = data.getElementsByTagName("HOST")
#CPU stat
cpu_usage = 0
used_cpu = 0
cpu_max = 0
#Memory stat
mem_usage = 0
used_mem = 0
mem_max = 0
#Running VMs
running_vms = 0
for host in hosts:
share = host.getElementsByTagName("HOST_SHARE")[0]
cpu_max += int(share.getElementsByTagName("MAX_CPU")[0].childNodes[0].data)
used_cpu += int(share.getElementsByTagName("USED_CPU")[0].childNodes[0].data)
cpu_usage += int(share.getElementsByTagName("CPU_USAGE")[0].childNodes[0].data)
mem_usage += int(share.getElementsByTagName("MEM_USAGE")[0].childNodes[0].data)
used_mem += int(share.getElementsByTagName("USED_MEM")[0].childNodes[0].data)
mem_max += int(share.getElementsByTagName("MAX_MEM")[0].childNodes[0].data)
running_vms += int(share.getElementsByTagName("RUNNING_VMS")[0].childNodes[0].data)
if cpu_usage < used_cpu:
alloc_cpu = 0
free_cpu = (cpu_max - used_cpu)
else:
alloc_cpu = (cpu_usage - used_cpu)
free_cpu = (cpu_max - alloc_cpu - used_cpu)
#Round memory values
mem_usage = mem_usage / 1024
used_mem = used_mem / 1024
mem_max = mem_max / 1024
if mem_max < (1024*5):
dimension = "MB"
else:
mem_usage = mem_usage / 1024
used_mem = used_mem / 1024
mem_max = mem_max / 1024
dimension = "GB"
mem_usage = round(mem_usage, 2)
used_mem = round(used_mem, 2)
mem_max = round(mem_max, 2)
if mem_usage < used_mem:
alloc_mem = 0
free_mem = (mem_max - used_mem)
else:
alloc_mem = (mem_usage - used_mem)
free_mem = (mem_max - alloc_mem - used_mem)
used_mem = used_mem
cpu_dict = {'FREE_CPU' : free_cpu, 'ALLOC_CPU' : alloc_cpu , 'USED_CPU' :
used_cpu}
mem_dict = {'FREE_MEM' : free_mem, 'ALLOC_MEM' : alloc_mem , 'USED_MEM' :
used_mem}
print json.dumps({ 'CPU' : cpu_dict, 'MEM' : mem_dict, 'VMS' : running_vms,
'DIMENSION' : dimension})
#!/bin/bash
export HOME='/var/www'
export LANG='en_US.UTF-8'
export LANGUAGE='en_US:en'
export LOGNAME='www-data'
export MAIL='/var/mail/www-data'
export PATH='/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games'
export PWD='/var/www'
export SHELL='/bin/sh'
export TERM='screen'
export USER='www-data'
#export ONE_LOCATION='/var/lib/opennebula'
export PATH="$PATH:$ONE_LOCATION/bin"
sudo -u oneadmin -i onehost list -x | /opt/webadmin/cloud/miscellaneous/stat/stat_dom.py
......@@ -8,6 +8,7 @@ import uuid
import subprocess
import ConfigParser
from pwd import getpwnam
import multiprocessing
# Get configuration file
config = ConfigParser.ConfigParser()
......@@ -100,23 +101,13 @@ def cmd_download(request, neptun, home_path):
if not dl_path.startswith(home_path):
abort(400, 'Invalid download path.')
dl_hash = str(uuid.uuid4())
if( os.path.isfile(dl_path) ):
os.symlink(dl_path, ROOT_WWW_FOLDER+'/'+dl_hash)
# Debug
# redirect('http://store.cloud.ik.bme.hu:8080/dl/'+dl_hash)
dl_pub = os.path.join(ROOT_WWW_FOLDER, dl_hash)
if os.path.isfile(dl_path):
os.symlink(dl_path, dl_pub)
return json.dumps({'LINK' : SITE_URL+'/dl/'+dl_hash})
else:
try:
os.makedirs(TEMP_DIR+'/'+neptun, 0700)
except:
pass
folder_name = os.path.basename(dl_path)
temp_path = TEMP_DIR+'/'+neptun+'/'+folder_name+'.zip'
with open(os.devnull, "w") as fnull:
# zip -rqDj vmi.zip /home/tarokkk/vpn-ik
result = subprocess.call(['/usr/bin/zip', '-rqDj', temp_path, dl_path], stdout = fnull, stderr = fnull)
os.symlink(temp_path, ROOT_WWW_FOLDER+'/'+dl_hash)
return json.dumps({'LINK' : SITE_URL+'/dl/'+dl_hash})
shutil.make_archive(dl_pub, 'zip', dl_path)
return json.dumps({'LINK' : SITE_URL+'/dl/'+dl_hash+'.zip'})
COMMANDS['DOWNLOAD'] = cmd_download
# UPLOAD
......@@ -127,7 +118,10 @@ def cmd_upload(request, neptun, home_path):
abort(400, 'Invalid upload path.')
if os.path.exists(up_path) == True and os.path.isdir(up_path):
up_hash = str(uuid.uuid4())
os.symlink(up_path, ROOT_WWW_FOLDER+'/'+up_hash)
link = ROOT_WWW_FOLDER + '/' + up_hash
os.symlink(up_path, link)
passwd = getpwnam(neptun)
os.lchown(link, passwd.pw_uid, passwd.pw_gid)
return json.dumps({ 'LINK' : SITE_URL+'/ul/'+up_hash})
else:
abort(400, 'Upload directory not exists!')
......@@ -285,40 +279,48 @@ def upload_allow(hash_num):
response.set_header('Access-Control-Allow-Headers', 'Content-Type, Content-Range, Content-Disposition, Content-Description')
return 'ok'
def _upload_save(uid, gid, input, path):
os.setegid(gid)
os.seteuid(uid)
try:
with open(path, 'wb', 0600) as output:
while True:
chunk = input.read(256*1024)
if not chunk:
break
output.write(chunk)
finally:
input.close()
@route('/ul/<hash_num>', method='POST')
def upload(hash_num):
if not os.path.exists(ROOT_WWW_FOLDER+'/'+hash_num):
link = ROOT_WWW_FOLDER+'/'+hash_num
if not os.path.exists(link):
abort (404, 'Token not found!')
try:
file_data = request.files.data
file_name = file_data.filename
except:
if os.path.exists(ROOT_WWW_FOLDER+'/'+hash_num):
os.remove(ROOT_WWW_FOLDER+'/'+hash_num)
if os.path.exists(link):
os.remove(link)
abort(400, 'No file was specified!')
up_path = os.path.realpath(ROOT_WWW_FOLDER+'/'+hash_num+'/'+file_name)
up_path = os.path.realpath(link + '/' + file_name)
if os.path.exists(up_path):
abort(400, 'File already exists')
# Check if upload path valid
if not up_path.startswith('/home'):
abort(400, 'Invalid path.')
os.remove(ROOT_WWW_FOLDER+'/'+hash_num)
# Get the real upload path
# Delete the hash link
# Get the username from path for proper ownership
username=up_path.split('/', 3)[2]
# os.setegid(getpwnam(username).pw_gid)
# os.seteuid(getpwnam(username).pw_uid)
# TODO setuid subcommand
# Check if file exist (root can overwrite anything not safe)
with open(up_path , 'wb') as f:
datalength = 0
for chunk in fbuffer(file_data.file, chunk_size=1048576):
f.write(chunk)
datalength += len(chunk)
os.chown(up_path, getpwnam(username).pw_uid, getpwnam(username).pw_gid)
os.chmod(up_path, 0644)
linkstat = os.stat(link)
os.remove(link)
p = multiprocessing.Process(target=_upload_save,
args=(linkstat.st_uid, linkstat.st_gid, file_data.file, up_path, ))
try:
p.start()
p.join()
finally:
p.terminate()
if p.exitcode:
abort(400, 'Write failed.')
try:
redirect_address = request.headers.get('Referer')
except:
......@@ -327,19 +329,11 @@ def upload(hash_num):
response.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
response.set_header('Access-Control-Allow-Headers', 'Content-Type, Content-Range, Content-Disposition, Content-Description')
redirect(redirect_address)
#return 'Upload finished: '+file_name+' - '+str(datalength)+' Byte'
# Return hard quota from quota
def hard_quota(quota):
return str(int(int(quota)*1.25))
# Define filebuffer for big uploads
def fbuffer(f, chunk_size=4096):
while True:
chunk = f.read(chunk_size)
if not chunk: break
yield chunk
# Update users .ssh/authorized_keys
def updateSSHAuthorizedKeys(username, key_list):
user_uid=getpwnam(username).pw_uid
......
......@@ -23,17 +23,30 @@ class DetailsInline(contrib.admin.StackedInline):
can_delete = False
class MyUserAdmin(contrib.auth.admin.UserAdmin):
list_display = ('username', 'full_name', 'email', 'date_joined', 'instance_count')
list_display = ('username', 'full_name', 'email', 'date_joined', 'instance_count', 'course_groups')
list_filter = ('is_superuser', 'is_active', 'groups', 'person__course_groups', )
try:
inlines = inlines + (PersonInline, SshKeyInline, DetailsInline)
except NameError:
inlines = (PersonInline, SshKeyInline, DetailsInline)
def instance_count(self, obj):
return obj.instance_set.count()
return _("%(sum)d (%(active)d active)") % { 'sum': obj.instance_set.count(),
'active' :obj.instance_set.filter(state='ACTIVE').count(), }
def course_groups(self, obj):
try:
return ", ".join(obj.person_set.all()[0].course_groups.all())
except:
return None
def full_name(self, obj):
return u"%s %s" % (obj.last_name, obj.first_name)
full_name.admin_order_field = 'last_name'
ordering = ["-date_joined"]
contrib.admin.site.unregister(contrib.auth.models.User)
......
# -*- coding: utf-8 -*-
from django_extensions.management.jobs import HourlyJob
import datetime
from django.utils.timezone import utc
from one.models import Instance
from django.template.loader import render_to_string
from one.tasks import SendMailTask
from django.utils.translation import ugettext_lazy as _
from cloud.settings import CLOUD_URL as url
from django.utils import translation
class Job(HourlyJob):
help = "Suspend/delete expired Instances."
def calc(self, orig, days=0, hours=0):
return (orig + datetime.timedelta(days=days, hours=hours)).replace(minute=0, second=0, microsecond=0)
def execute(self):
# executing empty sample job TODO
now = datetime.datetime.utcnow().replace(tzinfo=utc)
d = {
'1m': self.calc(orig=now, days=30),
'2w': self.calc(orig=now, days=14),
'1w': self.calc(orig=now, days=7),
'1d': self.calc(orig=now, days=1),
'1h': self.calc(orig=now, hours=1),
}
# for i in d:
# print i+':'+unicode(d[i])
# delete
for i in Instance.objects.filter(state__in=['ACTIVE', 'STOPPED'], time_of_delete__isnull=False):
try:
translation.activate(i.owner.person_set.get().language)
except:
pass
# print u'%s delete: %s' % (i.name, i.time_of_delete)
delete = i.time_of_delete.replace(minute=0, second=0, microsecond=0)
continue
if i.time_of_delete < now:
# msg = render_to_string('mails/notification-delete-now.txt', { 'user': i.owner, 'instance': i, 'url': url } )
# SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
pass
else:
for t in d:
if delete == d[t]:
msg = render_to_string('mails/notification-delete.txt', { 'user': i.owner, 'instance': i, 'url': url } )
SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
# suspend
for i in Instance.objects.filter(state='ACTIVE', time_of_suspend__isnull=False):
try:
translation.activate(i.owner.person_set.get().language)
except:
pass
# print u'%s suspend: %s' % (i.name, i.time_of_suspend)
suspend = i.time_of_suspend.replace(minute=0, second=0, microsecond=0)
if i.time_of_suspend < now:
msg = render_to_string('mails/notification-suspend-now.txt', { 'user': i.owner, 'instance': i, 'url': url } )
SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
i.stop()
else:
for t in d:
if suspend == d[t]:
msg = render_to_string('mails/notification-suspend.txt', { 'user': i.owner, 'instance': i, 'url': url } )
SendMailTask.delay(to=i.owner.email, subject='[IK Cloud] %s' % i.name, msg=msg)
......@@ -2,9 +2,11 @@ from one.models import *
from django_extensions.management.jobs import HourlyJob
class Job(HourlyJob):
help = "Update Disks and Networks from OpenNebula."
help = "Update Disks, Networks and Instances from OpenNebula."
def execute(self):
Disk.update()
Network.update()
for i in Instance.objects.filter(state__in=['ACTIVE', 'STOPPED'], time_of_delete__isnull=False):
i.update_state()
pass
......@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-21 18:06+0100\n"
"PO-Revision-Date: 2013-02-21 18:09+0100\n"
"POT-Creation-Date: 2013-03-07 18:16+0100\n"
"PO-Revision-Date: 2013-03-07 17:02+0100\n"
"Last-Translator: \n"
"Language-Team: Hungarian <cloud@ik.bme.hu>\n"
"Language: hu\n"
......@@ -17,108 +17,117 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"X-Generator: Lokalize 1.4\n"
#: static/script/cloud.js:24
#: static/script/cloud.js:24 static/script/cloud.min.js:1
msgid "Are you sure deleting key?"
msgstr "Biztosan törli a kulcsot?"
#: static/script/cloud.js:24 static/script/cloud.js.c:246
#: static/script/cloud.js:320 static/script/cloud.js.c:533
#: static/script/store.js:273
#: static/script/cloud.js:24 static/script/cloud.js.c:296
#: static/script/cloud.js:370 static/script/cloud.js.c:623
#: static/script/cloud.min.js:1 static/script/store.js:288
#: static/script/store.min.js:1
msgid "Delete"
msgstr "Törlés"
#: static/script/cloud.js:36
#: static/script/cloud.js:36 static/script/cloud.min.js:1
msgid ""
"Are you sure about reseting store credentials?<br /> You will lose your "
"access to your store account on your existing virtual machines!"
msgstr ""
"Biztosan újragenerálja az adattár-kulcsait?<br /> "
"El fogja veszteni az adattár-hozzáférést a már futó virtuális gépekből!"
"Biztosan újragenerálja az adattár-kulcsait?<br /> El fogja veszteni az "
"adattár-hozzáférést a már futó virtuális gépekből!"
#: static/script/cloud.js:36
#: static/script/cloud.js:36 static/script/cloud.min.js:1
msgid "Reset"
msgstr "Újragenerálás"
#: static/script/cloud.js:65 static/script/store.js:309
#: static/script/cloud.js:75 static/script/cloud.min.js:1
#: static/script/store.js:323 static/script/store.min.js:1
msgid "Rename"
msgstr "Átnevezés"
#: static/script/cloud.js:221 static/script/store.js:273
#: static/script/cloud.js:271 static/script/cloud.min.js:1
#: static/script/store.js:288 static/script/store.min.js:1
msgid "Cancel"
msgstr "Mégsem"
#: static/script/cloud.js:235
#: static/script/cloud.js:285 static/script/cloud.min.js:1
#, c-format
msgid "Are you sure stopping %s?"
msgstr "Biztosan felfüggeszti a következőt: %s?"
#: static/script/cloud.js:236
#: static/script/cloud.js:286 static/script/cloud.min.js:1
msgid "Stop"
msgstr "Felfüggesztés"
#: static/script/cloud.js:245
#: static/script/cloud.js:295 static/script/cloud.min.js:1
#, c-format
msgid "Are you sure deleting %s?"
msgstr "Biztosan törli a következőt: %s?"
#: static/script/cloud.js:255
#: static/script/cloud.js:305 static/script/cloud.min.js:1
#, c-format
msgid "Are you sure restarting %s?"
msgstr "Biztosan újraindítja a következőt: %s?"
#: static/script/cloud.js:256
#: static/script/cloud.js:306 static/script/cloud.min.js:1
msgid "Restart"
msgstr "Újraindítás"
#: static/script/cloud.js:319
#: static/script/cloud.js:369 static/script/cloud.min.js:1
#, c-format
msgid "Are you sure deleting this %s template?"
msgstr "Biztosan törli a következő sablont: %s?"
#: static/script/cloud.js:452 static/script/cloud.js.c:459
#: static/script/cloud.js:547 static/script/cloud.js.c:550
#: static/script/cloud.min.js:1
msgid "Add owner"
msgstr "Tulajdonos hozzáadása"
#: static/script/cloud.js:457
#: static/script/cloud.js:550 static/script/cloud.min.js:1
msgid "Unknown"
msgstr "Ismeretlen"
#: static/script/cloud.js:533
#: static/script/cloud.js:623 static/script/cloud.min.js:1
#, c-format
msgid "Are you sure deleting <strong>%s</strong>"
msgstr "Törli a következő fájlt: <strong>%s</strong>"
#: static/script/store.js:57 static/script/store.js.c:66
#: static/script/store.js:75 static/script/store.js.c:205
#: static/script/store.js:267
#: static/script/store.js:52 static/script/store.js.c:61
#: static/script/store.js:70 static/script/store.js.c:220
#: static/script/store.js:282 static/script/store.min.js:1
msgid "file"
msgstr "fájl"
#: static/script/store.js:268
#: static/script/store.js:125 static/script/store.min.js:1
msgid "Toplist"
msgstr "Legújabb fájlok"
#: static/script/store.js:127 static/script/store.min.js:1
msgid "Back to the root folder"
msgstr "Vissza a gyökérmappába"
#: static/script/store.js:283 static/script/store.min.js:1
#, c-format
msgid "You are removing the file <strong>%s</strong>."
msgstr "Törli a következő fájlt: <strong>%s</strong>."
#: static/script/store.js:270
#: static/script/store.js:285 static/script/store.min.js:1
#, c-format
msgid "You are removing the folder <strong>%s</strong> (and its content)."
msgstr "Törli a következő könyvtárat és tartalmát: <strong>%s</strong>."
#: static/script/store.js:273
#: static/script/store.js:288 static/script/store.min.js:1
msgid "Are you sure?"
msgstr "Biztos benne?"
#: static/script/store.js:427 static/script/store.js.c:429
#: static/script/store.js:446 static/script/store.js.c:448
#: static/script/store.min.js:1
msgid "Upload"
msgstr "Feltöltés"
#: static/script/store.js:429
#: static/script/store.js:448 static/script/store.min.js:1
msgid "done, processing..."
msgstr "kész, feldolgozás..."
#, fuzzy
#~ msgid "Are you sure about reseting store credentials"
#~ msgstr "Biztosan újraindítja a következőt: %s?"
#~ msgid "Please choose a different name."
#~ msgstr "Kérem, válasszon eltérő nevet."
......@@ -14,7 +14,7 @@ from django.db.models.signals import post_save
from django import forms
from django.utils.translation import ugettext_lazy as _
from firewall.models import Host, Rule, Vlan
from firewall.models import Host, Rule, Vlan, Record
from school.models import Person, Group
from store.api import StoreApi
from .util import keygen
......@@ -224,7 +224,7 @@ class Disk(models.Model):
return u"%s (#%d)" % (self.name, self.id)
@staticmethod
def update():
def update(delete=True):
"""Get and register virtual disks from OpenNebula."""
import subprocess
proc = subprocess.Popen(["/opt/occi.sh", "storage", "list"],
......@@ -244,6 +244,7 @@ class Disk(models.Model):
except:
Disk(id=id, name=name).save()
l.append(id)
if delete:
Disk.objects.exclude(id__in=l).delete()
class Network(models.Model):
......@@ -400,34 +401,46 @@ class Instance(models.Model):
@models.permalink
def get_absolute_url(self):
return ('vm_show', None, {'iid':self.id})
return ('one.views.vm_show', None, {'iid':self.id})
def get_port(self):
def get_port(self, use_ipv6=False):
"""Get public port number for default access method."""
proto = self.template.access_type
if self.template.network.nat:
if self.template.network.nat and not use_ipv6:
return {"rdp": 23000, "nx": 22000, "ssh": 22000}[proto] + int(self.ip.split('.')[2]) * 256 + int(self.ip.split('.')[3])
else:
return {"rdp": 3389, "nx": 22, "ssh": 22}[proto]
def get_connect_host(self):
def get_connect_host(self, use_ipv6=False):
"""Get public hostname."""
if self.firewall_host is None:
return _('None')
try:
if use_ipv6:
return self.firewall_host.record_set.filter(type='AAAA')[0].get_data()['name']
else:
if self.template.network.nat:
return 'cloud'
ip = self.firewall_host.pub_ipv4
return Record.objects.filter(type='A', address=ip)[0].get_data()['name']
else:
return self.ip
return self.firewall_host.record_set.filter(type='A')[0].get_data()['name']
except:
if self.template.network.nat:
return self.firewall_host.pub_ipv4
else:
return self.firewall_host.ipv4
def get_connect_uri(self):
def get_connect_uri(self, use_ipv6=False):
"""Get access parameters in URI format."""
try:
proto = self.template.access_type
if proto == 'ssh':
proto = 'sshterm'
port = self.get_port()
host = self.get_connect_host()
port = self.get_port(use_ipv6=use_ipv6)
host = self.get_connect_host(use_ipv6=use_ipv6)
pw = self.pw
return ("%(proto)s:cloud:%(pw)s:%(host)s:%(port)d" %
{"port": port, "proto": proto, "pw": pw,
"host": self.firewall_host.pub_ipv4})
"host": host})
except:
return
......@@ -540,11 +553,13 @@ class Instance(models.Model):
inst.save()
inst.update_state()
host = Host(vlan=Vlan.objects.get(name=template.network.name),
owner=owner, shared_ip=True)
owner=owner)
host.hostname = hostname
host.mac = x.getElementsByTagName("MAC")[0].childNodes[0].nodeValue
host.ipv4 = inst.ip
if inst.template.network.nat:
host.pub_ipv4 = Vlan.objects.get(name=template.network.name).snat_ip
host.shared_ip = True
host.ipv6 = "auto"
try:
host.save()
......@@ -575,7 +590,10 @@ class Instance(models.Model):
if self.firewall_host:
h = self.firewall_host
self.firewall_host = None
try:
self.save()
except:
pass
h.delete()
def _update_vm(self, template):
......@@ -611,12 +629,12 @@ class Instance(models.Model):
self._change_state("POWEROFF")
def restart(self):
self._change_state("RESET")
def renew(self, which):
if which == 'suspend':
def renew(self, which='both'):
if which in ['suspend', 'both']:
self.time_of_suspend = self.share.get_type()['suspendx']
elif which == 'delete':
if which in ['delete', 'both']:
self.time_of_delete = self.share.get_type()['deletex']
else:
if not (which in ['suspend', 'delete', 'both']):
raise ValueError('No such expiration type.')
self.save()
def save_as(self):
......@@ -633,7 +651,7 @@ class Instance(models.Model):
def check_if_is_save_as_done(self):
if self.state != 'DONE':
return False
Disk.update()
Disk.update(delete=False)
imgname = "template-%d-%d" % (self.template.id, self.id)
disks = Disk.objects.filter(name=imgname)
if len(disks) != 1:
......
html
{
min-height: 100%;
position: relative;
}
body
{
min-height:100%;
......@@ -15,6 +20,7 @@ body
width:970px;
text-align:left;
margin:0 auto;
padding-bottom: 100px;
}
.contentblock
......@@ -198,6 +204,13 @@ input[type=submit], input[type=button], input[type=reset]{
background: rgba(0,0,0,0.2);
};
}
input:disabled {
background-color: rgba(255,0,0,0.2);
color: #222;
&:hover {
background-color: rgba(255,0,0,0.5);
}
}
textarea {
border-radius: 2px;
......@@ -263,3 +276,29 @@ textarea::-moz-placeholder{
textarea:-ms-input-placeholder{
color: @placeholderColor;
}
body > footer {
z-index: 999;
position: absolute;
bottom: 0;
width: 100%;
text-align: center;
border-top: 1px solid #888;
box-shadow:0 0 30px rgba(0,0,0,0.4);
margin:0;
background-color: white;
}
#http-error {
margin: 20px auto;
width: 500px;
border-radius: 4px;
border: 1px solid #888;
background: #FFFF66;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
padding: 20px;
}
.irasmu p {
margin-top: 20px;
}
from celery.task import Task, PeriodicTask
import logging
import celery
import os
import sys
import time
from django.core.mail import send_mail
logger = logging.getLogger(__name__)
class SendMailTask(Task):
def run(self, to, subject, msg, sender=u'noreply@cloud.ik.bme.hu'):
send_mail(subject, msg, sender, [ to ], fail_silently=False)
logger.info("[django][one][tasks.py] %s->%s [%s]" % (sender, to, subject) )
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
<!doctype html>
<html lang="{{LANGUAGE_CODE}}">
<head>
<meta charset="UTF-8">
<title>404 - {% trans ":(" %}</title>
</head>
<body>
{% block content %}
<div id="http-error">
<h1>404 - {% trans ":(" %}</h1>
</body>
</html>
<p>
{% trans "The requested page does not exists... Please go away..." %}
</p>
</div>
{% endblock %}
{% extends "base.html" %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div id="http-error">
<h1>500 - {% trans ":(" %}</h1>
<p>
{% trans "Internal Server Error... Please leave the server alone..." %}
</p>
</div>
{% endblock %}
<!DOCTYPE html>
{% load i18n %}
{% load staticfiles %}
{% get_current_language as lang %}
<html lang="{{lang}}">
<head>
<title>{% block title %}IK Cloud{% endblock %}</title>
<link href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link rel="icon" type="image/png" href="/static/favicon.png" />
<link rel="stylesheet/less" href="/static/style/style.less" />
<link href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css" />
<link rel="icon" type="image/png" href="{% static "favicon.png" %}" />
{% if DEBUG %}<link rel="stylesheet/less" href="{% static "style/style.less" %}" />{% else %}
<link href="{% static "style/style.css" %}" rel="stylesheet" type="text/css" />{% endif %}
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="/static/script/jquery.min.js"></script>
<script src="{% static "script/jquery.min.js" %}"></script>
<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
<script type="text/javascript">
window.localStorage.removeItem('https://cloud.ik.bme.hu/static/style/style.less:timestamp');
{% if DEBUG %}window.localStorage.removeItem('https://cloud.ik.bme.hu/static/style/style.less:timestamp');{% endif %}
var current_user={{user.id}};
</script>
<script src="/static/script/less.min.js"></script>
<script src="/static/script/knockout.min.js"></script>
<script type="text/javascript" src="/static/script/util.js"></script>
<script type="text/javascript" src="/static/script/cloud.js"></script>
{% if DEBUG %}<script src="{% static "script/less.min.js" %}"></script>{% endif %}
<script src="{% static "script/knockout.min.js" %}"></script>
{% if DEBUG %}<script type="text/javascript" src="{% static "script/util.js" %}"></script>
{% else %}<script type="text/javascript" src="{% static "script/util.min.js" %}"></script>
{% endif %}
{% if DEBUG %}<script type="text/javascript" src="{% static "script/cloud.js" %}"></script>
{% else %}<script type="text/javascript" src="{% static "script/cloud.min.js" %}"></script>
{% endif %}
{{ form.media }}
{% block js %}{% endblock %}
</head>
......@@ -26,25 +32,27 @@
{% block login %}
<div id="loginblock"><p>
{% if user.is_authenticated %}
Bejelentkezve: {{ user.username }}.
<a href="/logout/">Kijelentkezés</a>.
{% trans "Logged in:" %} {{ user.username }}.
<a href="{% url logout %}">{% trans "Logout" %}</a>.
{% if user.is_staff %}
<a href="/admin/">Admin</a>.
<a href="{% url admin:index %}">{% trans "Admin" %}</a>.
{% endif %}
{% else %}
<a href="/login/">Bejelentkezés</a>.
<a href="{% url login %}">{% trans "Login" %}</a>.
{% endif %}
{% if user.is_authenticated %}
{% if lang == 'hu' %}
<a href="/language/en/">In English</a>.
<a href="{% url school.views.language "en" %}">In English</a>.
{% else %}
<a href="/language/hu/">Magyarul</a>.
<a href="{% url school.views.language "hu" %}">Magyarul</a>.
{% endif %}
{% endif %}
</p>
</div>
{% endblock %}
{% block header %}
{% block header_title %}
<h1><a href="/">IK Cloud</a></h1>
<h1><a href="{% url one.views.index %}">IK Cloud</a></h1>
{% endblock %}
{% endblock %}
</div>
......@@ -61,11 +69,27 @@
{% block content %}{% endblock %}
<div class="clear"></div>
</div>
<footer>
<a href="/sites/legal/">{% trans "Legal notice" %}</a> |
<a href="/sites/policy/">{% trans "Policy" %}</a> |
<a href="/sites/help/">{% trans "Help" %}</a> |
<a href="/sites/support/">{% trans "Support" %}</a>
</footer>
<div id="modal" style="display: none">
<div id="shadow"></div>
<div id="modal-container">
</div>
</div>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-39125666-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>
{% extends "box/base/box.html" %}
{% load i18n %}
{% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block title %}
......@@ -8,8 +9,9 @@
{% endblock title %}
{% block boxhelp %}
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" />
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is your global data store.{% endblocktrans %}</p>
......@@ -24,6 +26,10 @@
WinSCP) to access your files at {{serv}}. You will need to register a
public key bellow.{% endblocktrans %}</p>
</div>
</div>
<div class="icon">
<img src="" alt="toggle" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="files" id="toggle-box-files"/>
</div>
</div>
{% endblock %}
......@@ -80,7 +86,7 @@
</li>
<li class="entry small-row">
<div class="summary" id="new-folder">
<div class="name toplist" data-bind="click: loadTopList">{% trans "Toplist" %}</div>
<div class="name toplist" data-bind="click: toggleToplist, text: getToplistText"></div>
<div class="clear"></div>
</div>
</li>
......@@ -100,7 +106,7 @@
</div>
<div class="details">
<div class="container">
<form style="padding-bottom: 10px" action="/key/add/" method="POST">
<form style="padding-bottom: 10px" action="{% url one.views.key_add %}" method="POST">
{% csrf_token %}
<textarea style="margin-bottom: 5px" name="key" placeholder="{% trans "Public key in OpenSSH format" %}"></textarea><br />
<input type="submit" style="margin-left: 10px;" value="{% trans "Save" %}" />
......@@ -139,7 +145,7 @@
<p id="upload-error-unknown" style="display: none"></p>
</div>
<div style="display: none" class="upload-zone" id="old-upload-form">
<form action="/" method="POST" data-bind="attr: {action: uploadURL}" enctype="multipart/form-data">
<form action="{% url one.views.home %}" method="POST" data-bind="attr: {action: uploadURL}" enctype="multipart/form-data">
<input type="file" name="data" />
<input type="submit" value="Feltöltés" />
</form>
......
{% extends "box/base/entry.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block summary %}
......@@ -8,13 +9,13 @@
<div class="info" data-bind="text: size"></div>
<div class="actions">
<a href="#" data-bind="click: $parent.rename, clickBubble: false">
<img src="/static/icons/pencil.png" alt="{% trans "rename" %}" />
<img src="{% static "icons/pencil.png" %}" alt="{% trans "rename" %}" />
</a>
<a href="#" data-bind="click: $parent.delete, clickBubble: false">
<img src="/static/icons/minus-circle.png" alt="{% trans "remove" %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans "remove" %}" />
</a>
<a href="#" data-bind="click: $parent.download, clickBubble: false">
<img src="/static/icons/download-cloud.png" alt="{% trans "download" %}" />
<img src="{% static "icons/download-cloud.png" %}" alt="{% trans "download" %}" />
</a>
</div>
<div class="clear"></div>
......
{% extends "box/base/entry.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
......@@ -15,7 +16,7 @@
</div>
<div class="actions">
<a href="#" class="remove delete-key" data-id="{{key.id}}">
<img src="/static/icons/minus-circle.png" alt="{% trans 'Remove' %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans 'Remove' %}" />
</a>
</div>
<div class="clear"></div>
......
{% extends "box/base/box.html" %}
{% load i18n %}
{% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block title %}
......@@ -9,8 +10,9 @@
{% block boxhelp %}
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" />
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is the list of your own templates.{% endblocktrans %}</p>
......@@ -19,6 +21,10 @@
machine, and it will be ready to run by your students in minutes.
{% endblocktrans %}</p>
</div>
</div>
<div class="icon">
<img src="" alt="toggle" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="templates" id="toggle-box-templates"/>
</div>
</div>
{% endblock %}
......@@ -53,17 +59,17 @@
<div class="summary public-template">
<div class="name">
{{t.name}}
<img src="/static/icons/lock-small.png" alt="{% trans "locked" %}"
<img src="{% static "icons/lock-small.png" %}" alt="{% trans "locked" %}"
title="{% trans "This is a shared template." %}" />
</div>
<div class="status">{{t.state}}</div>
<div class="actions">
{% if t.state == 'READY' %}
<a href="#" class="try-template-button" data-id="{{t.id}}" title="{% trans "Try" %}">
<img src="/static/icons/control.png" alt="{% trans "Start" %}"/>
<img src="{% static "icons/control.png" %}" alt="{% trans "Start" %}"/>
</a>
<a href="#" class="template-share" data-id="{{t.id}}" data-gid="{{group.id}}" title="{% trans "Share" %}">
<img src="/static/icons/user-share.png" alt="{% trans "Share" %}" />
<img src="{% static "icons/user-share.png" %}" alt="{% trans "Share" %}" />
</a>
{% endif %}
</div>
......@@ -75,14 +81,24 @@
<div class="quota">
<div class="used" style="width: {{ i.get_instance_pc|unlocalize }}%"></div>
</div>
<form action="/vm/unshare/{{i.id}}/" method="post">
<form action="{% url one.views.vm_unshare i.id %}" method="post">
<span title="{{i.name}}">{{i.name|truncatechars:20}}</span>
({{i.get_running}}/{{i.instance_limit}})
({{i.get_running}}/{{i.instance_limit}}) {{i.type}}
<a href="#" class="edit" data-id="{{i.id}}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" title="{% trans "Edit" %}" />
</a>
{% csrf_token %}
<input type="submit" class="template-unshare" value="{% trans "Delete" %}" style="float: right"/>
</form>
<div class="clear"></div>
</li>
<li class="description{% if not i.description %} empty{% endif %}">
{% if i.description %}
{{i.description}}
{% else %}
{% trans "No description available" %}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
......
{% extends "box/base/summary.html" %}
{% load i18n %}
{% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
......@@ -13,14 +14,24 @@
<div class="quota">
<div class="used" style="width: {{ i.get_instance_pc|unlocalize }}%"></div>
</div>
<form action="/vm/unshare/{{i.id}}/" method="post">
<form action="{% url one.views.vm_unshare i.id %}" method="post">
<span title="{{i.name}}">{{i.name|truncatechars:20}}</span>
({{i.get_running}}/{{i.instance_limit}})
({{i.get_running}}/{{i.instance_limit}}) {{i.type}}
<a href="#" class="edit" data-id="{{i.id}}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" title="{% trans "Edit" %}" />
</a>
{% csrf_token %}
<input class="template-unshare" type="submit" value="{% trans "Delete" %}" style="float: right"/>
</form>
<div class="clear"></div>
</li>
<li class="description{% if not i.description %} empty{% endif %}">
{% if i.description %}
{{i.description}}
{% else %}
{% trans "No description available" %}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
......@@ -32,25 +43,25 @@
{% endblock %}
{% block status %}
{{vm.state}}
{{t.state}}
{% endblock status %}
{% block actions %}
<a href="#" class="edit-template" data-id="{{ t.id }}" title="{% trans "Edit" %}">
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" />
</a>
{% if t.state == 'READY' %}
<a href="#" class="try-template" data-id="{{t.id}}" title="{% trans "Try" %}">
<img src="/static/icons/control.png" alt="{% trans "Start" %}"/>
<img src="{% static "icons/control.png" %}" alt="{% trans "Start" %}"/>
</a>
<!--<a href="#" title="{% trans "Edit" %}">
<img src="/static/icons/pencil.png" alt="{% trans "Edit" %}" />
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit" %}" />
</a>-->
<a href="#" class="template-share" data-id="{{t.id}}" data-gid="{{group.id}}" title="{% trans "Share" %}">
<img src="/static/icons/user-share.png" alt="{% trans "Share" %}" />
<img src="{% static "icons/user-share.png" %}" alt="{% trans "Share" %}" />
</a>
{% endif %}
<a href="#" class="delete-template" data-id="{{ t.id }}" data-name="{{ t.name }}" title="{% trans "Remove" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Remove" %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Remove" %}" />
</a>
<!--<a href="#" class="edit-template" data-id="{{ t.id }}" title="{% trans "Edit" %}">
<img src="/static/icons/pencil.png" alt="{% trans "Edit" %}" />
</a>-->
{% endblock actions %}
{% extends "box/base/box.html" %}
{% load i18n %}
{% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block title %}
......@@ -9,8 +10,9 @@
{% block boxhelp %}
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" />
<img class="help" src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is the list of your running virtual machines.{% endblocktrans %}</p>
......@@ -19,6 +21,10 @@
<p>{% blocktrans %}Please note, that users and shares both have a limit
of launchable instances.{% endblocktrans %}</p>
</div>
</div>
<div class="icon">
<img src="" alt="{% trans "Show/hide box" %}" class="toggle-box" data-id="vms" id="toggle-box-vms"/>
</div>
</div>
{% endblock %}
......@@ -103,7 +109,7 @@
<li>
&nbsp;
<span class="value">
<form method="POST" action="/vm/new/s{{s.pk}}/">
<form method="POST" action="{% url one.views.vm_new share=s.id %}">
{% csrf_token %}
<input {% if s.running_shared >= s.per_user_limit or s.get_running >= s.instance_limit%}disabled="disabled" value="{% trans "Quota reached" %}" {%else%}value="{% trans "Launch" %}"{% endif %} type="submit" />
</form>
......
{% extends "box/base/entry.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
......@@ -26,7 +27,7 @@
</li>
<li class="template">
{% trans "Type" %}:
<span class="value">{{vm.share.type}}</span>
<span class="value">{% if vm.share %}{{vm.share.type}}{% else %}{% trans "Try" %}{% endif %}</span>
<div class="clear"></div>
</li>
<li class="template">
......@@ -56,9 +57,9 @@
<li class="date">
{% trans "time of suspend"|capfirst %}:
<span class="value"> <abbr title="{{vm.time_of_suspend}}">{{vm.time_of_suspend|timeuntil}}</abbr>
<a href="#" class="renew-vm-button renew-suspend-vm-button" data-id="{{ vm.id }}" title="{% trans "Renew suspend time" %}">
<img src="/static/icons/control-double.png" alt="{% trans "Renew suspend time" %}" />
</a>
{% if vm.share %}<a href="#" class="renew-vm renew-suspend-vm" data-id="{{ vm.id }}" title="{% trans "Renew suspend time" %}">
<img src="{% static "icons/control-double.png" %}" alt="{% trans "Renew suspend time" %}" />
</a>{% endif %}
</span>
</li>
{% endif %}
......@@ -66,16 +67,16 @@
<li class="date">
{% trans "time of delete"|capfirst %}:
<span class="value"> <abbr title="{{vm.time_of_delete}}">{{vm.time_of_delete|timeuntil}}</abbr>
<a href="#" class="renew-vm-button renew-delete-vm-button" data-id="{{ vm.id }}" title="{% trans "Renew deletion time" %}">
<img src="/static/icons/control-double.png" alt="{% trans "Renew deletion time" %}" />
</a>
{% if vm.share %}<a href="#" class="renew-vm renew-delete-vm" data-id="{{ vm.id }}" title="{% trans "Renew deletion time" %}">
<img src="{% static "icons/control-double.png" %}" alt="{% trans "Renew deletion time" %}" />
</a>{% endif %}
</span>
</li>
{% endif %}
<li>
&nbsp;
<span class="value">
<a href="/vm/show/{{vm.id}}/" title="{{vm.name}}">{% trans "More details" %}</a>
<a href="{{ vm.get_absolute_url }}" title="{{vm.name}}">{% trans "More details" %}</a>
</span>
</li>
</ul>
......
{% extends "box/base/summary.html" %}
{% load staticfiles %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
......@@ -12,53 +13,53 @@
<div class="name {% if vm.state == 'ACTIVE' %}vm-on{% else %}vm-off{% endif %}">
<span id="vm-{{vm.id}}-name">{{vm.name|truncatechars:20}}</span>
<small id="vm-{{vm.id}}-name-details" class="details">
(<a href="/vm/show/{{vm.id}}/" title="{{vm.name}}">{% trans "More details" %}</a>)
(<a href="{{ vm.get_absolute_url }}" title="{{vm.name}}">{% trans "More details" %}</a>)
</small>
</div>
{% endblock %}
{% block status %}
{{vm.state}}
{% if vm.template.state != "READY" %} {{vm.template.state}} {% else %} {{vm.state}} {% endif %}
{% endblock status %}
{% block actions %}
<a href="#" class="rename-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Edit name" %}">
<img src="/static/icons/pencil.png" alt="{% trans "Edit name" %}" />
<img src="{% static "icons/pencil.png" %}" alt="{% trans "Edit name" %}" />
</a>
{% if vm.waiting %}
<a href="#">
<img src="/static/image/load.gif" />
<img src="{% static "image/load.gif" %}" />
</a>
{% elif vm.state == 'ACTIVE' %}
<a href="{{vm.get_connect_uri}}" data-id="{{ vm.id }}" class="connect-vm" title="{% trans "Connect" %}">
<img src="/static/icons/plug.png" alt="{% trans "Connect" %}" />
<img src="{% static "icons/plug.png" %}" alt="{% trans "Connect" %}" />
</a>
<a href="#" class="stop-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Pause" %}">
<img src="/static/icons/control-pause.png" alt="{% trans "Pause" %}" />
<img src="{% static "icons/control-pause.png" %}" alt="{% trans "Pause" %}" />
</a>
<a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a>
<a href="#" class="restart-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Restart" %}">
<img src="/static/icons/arrow-circle-double.png" alt="↺" />
<img src="{% static "icons/arrow-circle-double.png" %}" alt="↺" />
</a>
{% elif vm.state == 'PENDING' %}
<a href="#">
<img src="/static/image/load.gif" />
<img src="{% static "image/load.gif" %}" />
</a>
<a style="float: right" href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a>
{% elif vm.state == 'STOPPED' %}
<a href="#" class="resume-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Resume" %}">
<img src="/static/icons/control.png" alt="{% trans "Resume" %}" />
<img src="{% static "icons/control.png" %}" alt="{% trans "Resume" %}" />
</a>
<a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a>
{% elif vm.state == 'FAILED' %}
<a href="#" class="delete-vm" data-name="{{ vm.name }}" data-id="{{ vm.id }}" title="{% trans "Delete" %}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" />
</a>
{% endif %}
{% endblock actions %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
<form action="{% url one.views.ajax_share_edit_wizard share.id %}" method="post" id="template-wizard">
{% csrf_token %}
<div id="new-share" class="wizard">
<h2>
{% blocktrans with t=share.name%}Editing share: {{t}}{% endblocktrans %}
</h2>
<p>{% trans "Change the parameters as needed." %}</p>
<ul>
<li>
<label for="share-name">{% trans "Name of share" %}</label>
<input type="text" name="name" id="share-name" value="{{share.name}}" />
<div class="clear"></div>
</li>
<li class="li-share-type">
<label for="share-type">{% trans "Type" %}</label>
<ul class="radio">
{% for s in types %}
<li>
<label>
<input type="radio" name="type" value="{{s.id}}" id="share-type-{{s.id}}"
{% if s.id == share.type %}checked="checked"{% endif %} />{{s.verbose_name}}
</label>
</li>
{% endfor %}
</ul>
{% for s in types %}
<p id="share-type-summary-{{s.id}}" class="type-summary clear"
{% if not s.id == share.type %}style="display:none"{% endif %}>
{{s.help_text}}
({% if s.suspend %}
<span class="suspend"
title="{% blocktrans with time=s.suspend %}Suspend after {{time}}.{%endblocktrans%}">{{s.suspendx|timeuntil}}</span>
{%endif%}{% if s.delete %}
<span class="delete"
title="{% blocktrans with time=s.delete %}Delete after {{time}}.{%endblocktrans%}">{{s.deletex|timeuntil}}</span>
{%endif%})
</p>
{% endfor %}
<div class="clear"></div>
</li>
<li>
<label for="share-instance-limit">{% trans "Maximal count of instances" %}</label>
<input type="number" name="instance_limit" id="share-instance-limit" value="{{share.instance_limit}}" />
<div class="clear"></div>
</li>
<li>
<label for="share-per-user-limit">{% trans "Maximal count of instaces/user" %}</label>
<input type="number" name="per_user_limit" id="share-per-user-limit" value="{{share.per_user_limit}}" />
<div class="clear"></div>
</li>
<li style="border: none" class="clear">
<label for="share-description">{% trans "Description" %}</label>
<textarea name="description" id="share-description" style="text-align: left">{{share.description}}</textarea>
<div class="clear"></div>
</li>
</ul>
<nav>
<input type="reset" class="prev" value="{% trans "Cancel" %}" />
<input type="submit" value="{% trans "Save" %}"/>
<div class="clear"></div>
</nav>
<script type="text/javascript">
$(function(){
$('#new-share nav .prev').click(function(){
$('#modal').hide();
})
$("#new-share input[name='type']").click(function(e){ /* TODO */
var v = $("#new-share input[name='type']:checked").val();
$("p.type-summary").hide();
$("#share-type-summary-" + v).show();
});
})
</script>
</div>
</form>
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
<form action="{% url one.views.ajax_template_edit_wizard template.id %}" method="post" id="template-wizard">
{% csrf_token %}
<div id="new-template-step-2" class="wizard">
<h2>{% trans "Edit template" %}</h2>
<p>{% trans "Change the parameters as needed." %}</p>
<ul>
<li>
<label for="new-template-name">{% trans "Name" %}</label>
<input type="text" name="name" id="new-template-name" value="{{template.name}}"
class="validated" />
<div class="clear"></div>
</li>
<li class="new-tpl-size">
<label for="new-template-size">{% trans "Size" %}</label>
<ul class="radio">
{% for s in sizes %}
<li>
<label>
<input type="radio" name="size" value="{{s.id}}" id="new-template-size-{{s.id}}"
{% if s == template.instance_type %}checked="checked"{% endif %} />
{{s.name}}
</label>
</li>
{% endfor %}
</ul>
{% for s in sizes %}
<p id="new-template-size-summary-{{s.id}}" class="size-summary clear"
{% if s != template.instance_type %}style="display:none"{% endif %}>
<span class="cpu">
{% blocktrans count n=s.CPU %}{{n}} core{% plural %}{{n}} cores{% endblocktrans %}
</span>
<span class="memory">{{s.RAM}} MiB</span>
<span class="credit">{{s.credit}}</span>
</p>
{% endfor %}
<div class="clear"></div>
</li>
<li style="border: none">
<label for="new-template-description">{% trans "Description" %}</label>
<textarea name="description" id="new-template-description" style="text-align: left">{{template.description}}</textarea>
<div class="clear"></div>
</li>
</ul>
<nav>
<input type="reset" class="prev" value="{% trans "Cancel" %}" />
<input type="submit" class="next" value="{% trans "Save" %}" />
<div class="clear"></div>
</nav>
<script type="text/javascript">
$(function(){
var original = '{{template.name}}';
$('#new-template-step-2 nav .prev').click(function(){
$('#modal').hide();
})
$(".new-tpl-size input[name='size']").click(function(e){
var v = $(".new-tpl-size input[name='size']:checked").val();
$("p.size-summary").hide();
$("#new-template-size-summary-" + v).show();
});
$("#new-template-name").keyup(function(){
var timer;
return function(e){
var self = this;
clearTimeout(timer);
timer=setTimeout(function(){
var s = $(self).val();
$.ajax({
'type': 'GET',
'url': '{% url one.views.ajax_template_name_unique %}?name=' + s,
'success': function(data, b, c) {
if (s != $("#new-template-name").val()) {
return true;
}
if (data == "True" || s == original) {
$('#new-template-name').removeClass("error");
$('#new-template-step-2 nav .next').removeAttr("disabled");
$('#new-template-name').removeProp("title");
}
else {
$('#new-template-name').addClass("error");
$('#new-template-step-2 nav .next').attr("disabled", "disabled");
$('#new-template-name').prop("title", gettext('Please choose a different name.'));
}
}
});
}, 1000)
}
}());
$("#template-wizard").submit(function(e){
e.preventDefault();
$.ajax({
'type': 'GET',
'url': '{% url one.views.ajax_template_name_unique %}?name=' + $("#new-template-name").val(),
'success': function(data, b, c) {
if (data == "True" || s == original) {
$("#template-wizard").unbind('submit').submit()
}
else {
$('#new-template-name').addClass("error");
$('#new-template-step-2 nav .next').attr("disabled", "disabled");
$('#new-template-name').prop("title", gettext('Please choose a different name.'));
}
}
});
});
})
</script>
</div>
</form>
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block js %}
<script type="text/javascript" src="/static/script/store.js"></script>
{% if DEBUG %}<script type="text/javascript" src="{% static "script/store.js" %}"></script>
{% else %}<script type="text/javascript" src="{% static "script/store.min.js" %}"></script>
{% endif %}
{% endblock %}
{% block content %}
<div class="boxes">
......
{% load i18n %}
{% blocktrans with name=user.get_full_name %}
Dear {{name}},
{% endblocktrans %}
{% block body %}
{% endblock %}
--
{{site}}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with reason=bl.reason snort_message=bl.snort_message vm=instance.name %}
Our network intrusion detection system showed that your machine
"{{vm}}" pursues the following forbidden network activity: {{reason}}.
"{{vm}}" has been BANNED from all network activity
including remote desktop and shell connection.
Details:
{{snort_message}}
{% endblocktrans %}
{% blocktrans with url=url %}
Please, reply to this notification, or delete the instance on the
cloud portal: {{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_delete %}
Your {{state}} virtual machine "{{vm}}" has been DELETED
at {{date}}.
{% endblocktrans %}
{% blocktrans %}
The disk image is IRRECOVERABLY REMOVED.
{% endblocktrans %}
{% blocktrans with url=url %}
You can start a new instance of the template on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_delete time=exp|timeuntil %}
Your {{state}} virtual machine "{{vm}}" is going to be DELETED
at {{date}} (in {{time}}).
{% endblocktrans %}
{% blocktrans %}
The disk image will be IRRECOVERABLY REMOVED.
{% endblocktrans %}
{% blocktrans with url=url %}
You can renew or delete the instance on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_suspend %}
Your {{state}} virtual machine "{{vm}}" has been STOPPED
at {{date}}.
{% endblocktrans %}
{% blocktrans with deldate=instance.time_of_delete %}
The disk and memory image is stored, and you can resume it
until the final expiration time ({{deldate}}).
{% endblocktrans %}
{% blocktrans with url=url %}
You can also renew or delete the instance on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% extends "mails/base.txt" %}
{% load i18n %}
{% block body %}
{% blocktrans with vm=instance.name state=instance.state|lower date=instance.time_of_suspend time=exp|timeuntil url=url %}
Your {{state}} virtual machine "{{vm}}" is going to be STOPPED
at {{date}} (in {{time}}).
{% endblocktrans %}
{% blocktrans with deldate=instance.time_of_delete %}
The disk and memory image will be stored, and you can resume it
until the final expiration time ({{deldate}}).
{% endblocktrans %}
{% blocktrans with url=url %}
You can also renew or delete the instance on the cloud portal:
{{url}}
{% endblocktrans %}
{% endblock %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
<form action="/ajax/share/{{base.id}}/" method="post" id="template-wizard">
<form action="{% url one.views.ajax_share_wizard id=base.id %}" method="post" id="template-wizard">
{% csrf_token %}
<div id="new-share" class="wizard">
<h2>
......
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
<form action="/ajax/templateWizard" method="post" id="template-wizard">
<form action="{% url one.views.ajax_template_wizard %}" method="post" id="template-wizard">
{% csrf_token %}
<div id="new-template-step-1" class="wizard">
<div class="progress">
......@@ -28,7 +29,7 @@
<input type="radio" name="base" value="{{m.id}}" />
{{m.name}}
{% if m.public %}
<img src="/static/icons/lock-small.png" alt="{% trans "locked" %}"
<img src="{% static "icons/lock-small.png" %}" alt="{% trans "locked" %}"
title="{% trans "This is a shared template." %}" />
{% endif %}
</label>
......@@ -56,7 +57,7 @@
else {
$.ajax({
'type': 'POST',
'url': '/ajax/templateWizard',
'url': '{% url one.views.ajax_template_wizard %}',
'data': $('#template-wizard').serialize(),
'success': function(data) {
$('#modal-container').html(data);
......
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
<form action="/vm/new/{{base.id}}/" method="post" id="template-wizard">
<form action="{% url new_vm_from_template base.id %}" method="post" id="template-wizard">
{% csrf_token %}
<div id="new-template-step-2" class="wizard">
<div class="progress">
......@@ -75,7 +76,7 @@
var s = $(self).val();
$.ajax({
'type': 'GET',
'url': '/ajax/template_name_unique/' + s,
'url': '{% url one.views.ajax_template_name_unique %}?name=' + s,
'success': function(data, b, c) {
if (s != $("#new-template-name").val()) {
return true;
......@@ -99,7 +100,7 @@
e.preventDefault();
$.ajax({
'type': 'GET',
'url': '/ajax/template_name_unique/' + $("#new-template-name").val(),
'url': '{% url one.views.ajax_template_name_unique %}?name=' + $("#new-template-name").val(),
'success': function(data, b, c) {
if (data == "True") {
$("#template-wizard").unbind('submit').submit()
......
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block js %}
<script type="text/javascript">
......@@ -8,14 +9,28 @@
$.ajax({
type: 'GET',
dataType: 'json',
url: '/ajax/vm/status/{{ id }}',
url: '{% url one.views.vm_ajax_instance_status id %}',
success: function(data){
if( !data.booting && data.state == 'ACTIVE'){
if (!data.booting && data.state == 'ACTIVE'){
window.location.reload();
}
}
})
},2000);
});
}, 5000);
{% endif %}
{% if i.template.state == 'SAVING' %}
var savingTimer=setInterval(function(){
$.ajax({
type: 'GET',
dataType: 'json',
url: '{% url one.views.vm_ajax_instance_status id %}',
success: function(data){
if(data.template.state == 'READY'){
window.location.href='{% url one.views.home %}';
}
}
});
}, 10000);
{% endif %}
</script>
{% endblock %}
......@@ -61,13 +76,18 @@
<div class="content">
{% if state == "PENDING" or state == "ACTIVE" and booting %}
<p style="font-size:25px; line-height:2em;text-align:center;">
<img src="/static/image/load.gif" />
<img src="{% static "image/load.gif" %}" />
{% trans "Starting..." %}
</p>
{% elif i.template.state == "SAVING" %}
<p style="font-size:25px; line-height:2em;text-align:center;">
<img src="{% static "image/load.gif" %}" />
{% trans "Saving..." %}
</p>
{% elif state == "ACTIVE" and not booting %}
<p id="connect" style="display:block; font-size:25px; line-height:2em;text-align:center;">
<a href="{{uri}}" class="button" onclick="return connectbutton();">
<img src="/static/image/load.gif" id="connecting" style="display:none;" />
<img src="{% static "image/load.gif" %}" id="connecting" style="display:none;" />
{% trans "Running" %}
</a>
</p>
......@@ -90,8 +110,9 @@
<div class="contentblock" id="ports">
<h2>
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" />
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is a list about the network ports
......@@ -105,23 +126,24 @@
{% endblocktrans %}</p>
</div>
</div>
</div>
{% trans "Port administration" %}</h2>
<div class="content">
<form action="{% url vm_port_add i.id %}" method="post">
<form action="{% url one.views.vm_port_add i.id %}" method="post">
{% csrf_token %}
<table>
<tr>
<th>{% trans "Protocol" %}</th>
<th>{% trans "Public port" %}</th>
<th colspan="2">{% trans "Private port" %}</th>
{% if i.template.network.nat %}<th colspan="2">{% trans "Private port" %}</th>{%endif%}
</tr>
{% for port in ports %}
<tr>
<td>{{port.proto}}</td>
<td>{{port.public}}</td>
<td>{{port.private}}</td>
{% if i.template.network.nat %}<td>{{port.private}}</td>{%endif%}
<td>
<a href="/vm/port_del/{{i.id}}/{{port.proto}}/{{port.public}}/">{% trans "Delete" %}</a>
<a href="{% url one.views.vm_port_del i.id port.proto port.public %}">{% trans "Delete" %}</a>
</td>
</tr>
{% endfor %}
......@@ -135,9 +157,11 @@
<td>
<input style="min-width:70px;width:70px;" type="text" name="public"/>
</td>
{% if i.template.network.nat %}
<td>
<input style="min-width:70px;width:70px;" type="text" name="private"/>
</td>
{% endif %}
<td>
<input type="submit" style="min-width:3em" value="{% trans "Add" %}" />
</td>
......
{% load l10n %}
<html>
<head>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1.0', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {
// Create the data table.
var data_cpu = new google.visualization.DataTable();
data_cpu.addColumn('string', 'Topping');
data_cpu.addColumn('number', 'Slices');
data_cpu.addRows([
['Free CPU', {{STAT.CPU.FREE_CPU}}],
['Allocated CPU', {{STAT.CPU.ALLOC_CPU}}],
['Used CPU', {{STAT.CPU.USED_CPU}}],
]);
// Set chart options
var cpu_options = {'title':'Cloud CPU usage percent (100/CPU)',
'width':400,
'height':300,
slices: {0: {color: 'blue'}, 1:{color: 'orange'},
2:{color: 'red'}}
};
var data_mem = new google.visualization.DataTable();
data_mem.addColumn('string', 'Topping');
data_mem.addColumn('number', 'Slices');
data_mem.addRows([
['Free Memory', {{STAT.MEM.FREE_MEM|unlocalize}}],
['Allocated Memory', {{STAT.MEM.ALLOC_MEM|unlocalize}}],
['Used Memory', {{STAT.MEM.USED_MEM|unlocalize}}],
]);
// Set chart options
var mem_options = {'title':'Cloud Memory usage in {{STAT.DIMENSION}}',
'width':400,
'height':300,
slices: {0: {color: 'blue'}, 1:{color: 'orange'},
2:{color: 'red'}}
};
// Instantiate and draw our chart, passing in some options.
var chart = new
google.visualization.PieChart(document.getElementById('chart_cpu_div'));
chart.draw(data_cpu, cpu_options);
var chart = new
google.visualization.PieChart(document.getElementById('chart_mem_div'));
chart.draw(data_mem, mem_options);
}
</script>
</head>
<body>
<!--Div that will hold the pie chart-->
<div>Running VMs: {{STAT.VMS}}</div>
<div id="chart_cpu_div"></div>
<div id="chart_mem_div"></div>
</body>
</html>
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
<div class="content">
<table>
......@@ -7,8 +8,9 @@
<td>
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" />
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
{% if i.template.os_type == 'linux' %}
......@@ -30,16 +32,17 @@
{% endif %}
</div>
</div>
</div>
{{i.template.access_type|upper}}
</td>
</tr>
<tr>
<th>{% trans "IP" %}:</th>
<td>{{ i.firewall_host.pub_ipv4 }}</td>
<td>{{ i.hostname }}</td>
</tr>
<tr>
<th>{% trans "Port" %}:</th>
<td>{{ i.get_port}}</td>
<td>{{ i.port}}</td>
</tr>
<tr>
<th>{% trans "Username" %}:</th>
......
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
class ViewsTestCase(TestCase):
def test_index(self):
'''Test whether index is reachable.'''
resp = self.client.get('/', follow=True)
self.assertEqual(resp.status_code, 200)
......@@ -6,10 +6,10 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-21 18:06+0100\n"
"PO-Revision-Date: 2013-02-19 18:47+0100\n"
"POT-Creation-Date: 2013-03-07 18:16+0100\n"
"PO-Revision-Date: 2013-03-07 17:48+0100\n"
"Last-Translator: \n"
"Language-Team: American English <kde-l10n-hu@kde.org>\n"
"Language-Team: American English <cloud@ik.bme.hu>\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
......@@ -159,127 +159,179 @@ msgstr "Érvénytelen Neptun-kód."
msgid "Invalid NEPTUN code"
msgstr "Érvénytelen Neptun-kód"
#: templates/show-group.html:8
#: templates/show-group.html:9
msgid "Owners of"
msgstr "Tulajdonosok"
#: templates/show-group.html:22 templates/box/person/entry.html:22
#: templates/show-group.html:23 templates/box/person/entry.html:23
msgid "Remove"
msgstr "Eltávolítás"
#: templates/show-group.html:30 templates/box/person/entry.html:31
#: templates/show-group.html:31 templates/box/person/entry.html:32
msgid "This user never logged in, no data available"
msgstr "Ez a felhasználó még nem lépett be, nincs adat róla"
#: templates/show-group.html:34 templates/box/person/entry.html:35
#: templates/show-group.html:35 templates/box/person/entry.html:36
msgid "Name"
msgstr "Név"
#: templates/show-group.html:37 templates/box/person/entry.html:38
#: templates/show-group.html:38 templates/box/person/entry.html:39
msgid "NEPTUN"
msgstr "NEPTUN"
#: templates/show-group.html:50
#: templates/show-group.html:51
msgid "Add owner"
msgstr "Tulajdonos hozzáadása"
#: templates/show-group.html:55
#: templates/show-group.html:56
msgid "Owner name/NEPTUN"
msgstr "Tulajdonos neve/NEPTUN-kódja"
#: templates/show-group.html:68
#: templates/show-group.html:69
msgid "This group has no shared templates."
msgstr "Ennek a csoportnak egy sablon sincs megosztva."
#: templates/show-group.html:71
#: templates/show-group.html:72
msgid "Share one, and the group members can start their own virtual machine."
msgstr ""
"Osszon meg egyet, hogy a csoport tagjai is elindíthassák egy példányát."
#: templates/box/group/box.html:7
#: templates/box/group/box.html:11 templates/box/person/box.html:11
msgid "Help"
msgstr "Segítség"
#: templates/box/group/box.html:14
msgid "This is the list of groups you own."
msgstr "Ez az ön csoportjainak felsorolása."
#: templates/box/group/box.html:15
msgid "Groups are collections of users."
msgstr "A csoportok felhasználók halmazai."
#: templates/box/group/box.html:16
msgid ""
"You can share templates with your groups, so\n"
" that they can run instances of those templates.\n"
" "
msgstr ""
"Megoszthatja a sablonokat csoportjaival, \n"
" így a tagok elindíthatják a sablonokból saját példányaikat.\n"
" "
#: templates/box/group/box.html:22 templates/box/person/box.html:21
msgid "Show/hide box"
msgstr "Doboz megjelenítése/rejtése"
#: templates/box/group/box.html:28
msgid "My Groups"
msgstr "Saját csoportok"
#: templates/box/group/box.html:19
#: templates/box/group/box.html:40
msgid "You have no groups."
msgstr "Nincs még csoportja."
#: templates/box/group/box.html:21
#: templates/box/group/box.html:42
msgid "Create a new one, and add your students to the new group."
msgstr "Hozzon létre egyet, és vegy fel hallgatóit."
#: templates/box/group/box.html:29
#: templates/box/group/box.html:50
msgid "Show hidden groups"
msgstr "Elrejtett csoportok megjelenítése"
#: templates/box/group/box.html:35 templates/box/group/box.html.py:41
#: templates/box/group/box.html:56 templates/box/group/box.html.py:62
msgid "Create new group"
msgstr "Új csoport létrehozása"
#: templates/box/group/box.html:44
#: templates/box/group/box.html:65
msgid "Group name"
msgstr "Csoport neve"
#: templates/box/group/box.html:48 templates/box/group/entry.html:42
#: templates/box/group/box.html:69 templates/box/group/entry.html:43
msgid "Semester"
msgstr "Félév"
#: templates/box/group/box.html:56
#: templates/box/group/box.html:77
msgid "Members"
msgstr "Tagok"
#: templates/box/group/box.html:57
#: templates/box/group/box.html:78
msgid "Student NEPTUN codes, one per line"
msgstr "Hallgatók NEPTUN-kódja, soronként egy"
#: templates/box/group/box.html:62
#: templates/box/group/box.html:83
msgid "Cancel"
msgstr "Mégsem"
#: templates/box/group/box.html:63
#: templates/box/group/box.html:84
msgid "Done"
msgstr "Kész"
#: templates/box/group/entry.html:15 templates/box/group/entry.html.py:56
#: templates/box/group/entry.html:16 templates/box/group/entry.html.py:57
msgid "More details"
msgstr "Részletek"
#: templates/box/group/entry.html:19
#: templates/box/group/entry.html:20
msgid "Delete"
msgstr "Törlés"
#: templates/box/group/entry.html:22
#: templates/box/group/entry.html:23
msgid "Hide"
msgstr "Elrejtés"
#: templates/box/group/entry.html:32
#: templates/box/group/entry.html:33
msgid "Course"
msgstr "Tárgy"
#: templates/box/group/entry.html:37
#: templates/box/group/entry.html:38
msgid "Not assigned"
msgstr "Nincs hozzárendelve"
#: templates/box/group/entry.html:46
#: templates/box/group/entry.html:47
msgid "Owner(s)"
msgstr "Tulajdonosok"
#: templates/box/group/entry.html:50
#: templates/box/group/entry.html:51
msgid "Member count"
msgstr "Tagok száma"
#: templates/box/person/box.html:7
#: templates/box/person/box.html:14
msgid "This is the list of this group's members."
msgstr "Ez a csoport tagjainak felsorolása."
#: templates/box/person/box.html:15
msgid ""
"Members are the people who can start new\n"
" instances of templates shared with the group.\n"
" "
msgstr ""
"A tagok azok a személyek, akik jogosultak a csoportnak\n"
" megosztott sablonok példányainak indítására.\n"
" "
#: templates/box/person/box.html:27
msgid "Members of"
msgstr "Tagok"
#: templates/box/person/box.html:17 templates/box/person/box.html.py:20
#: templates/box/person/box.html:37 templates/box/person/box.html.py:40
msgid "Add user"
msgstr "Felhasználó hozzáadása"
#: templates/box/person/box.html:19
#: templates/box/person/box.html:39
msgid "User NEPTUN code"
msgstr "Felhasználó Neptun-kódja"
#~ msgid "Templates are customized versions of the base images."
#~ msgstr "A sablonok alaprendszerek testre szabott változatai."
#~ msgid ""
#~ "You can install all the needed software on a master\n"
#~ " machine, and it will be ready to run by your students in "
#~ "minutes.\n"
#~ " "
#~ msgstr ""
#~ "Telepítheti az összes szükséges szoftvert egy mestergépen, és az "
#~ "ígykészült sablon pár perc múltán készen is állhat a hallgatók számára."
#~ msgid "Templates"
#~ msgstr "Sablonok"
......
{% extends "box/base/box.html" %}
{% load i18n %}
{% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block boxhelp %}
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is the list of groups you own.{% endblocktrans %}</p>
<p>{% blocktrans %}Groups are collections of users.{% endblocktrans %}</p>
<p>{% blocktrans %}You can share templates with your groups, so
that they can run instances of those templates.
{% endblocktrans %}</p>
</div>
</div>
<div class="icon">
<img src="" alt="toggle" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="groups" id="toggle-box-groups"/>
</div>
</div>
{% endblock %}
{% block title %}
{% trans "My Groups" %}
{% endblock title %}
......@@ -36,7 +57,7 @@
<div class="clear"></div>
</div>
<div id="new-group-wizard" style="display: none">
<form action="/group/new/" method="POST" class="wizard">
<form action="{% url school.views.group_new %}" method="POST" class="wizard">
{% csrf_token %}
<h3>{% trans "Create new group" %}</h3>
<ul>
......
{% extends "box/base/entry.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
......@@ -12,14 +13,14 @@
<div class="summary">
<div class="name">
{{ group.name }}
<small class="details">(<a href="/group/show/{{group.id}}">{% trans "More details" %}</a>)</small>
<small class="details">(<a href="{{ group.get_absolute_url }}">{% trans "More details" %}</a>)</small>
</div>
<div class="actions">
<a href="#" class="delete" data-id="{{group.id}}" data-name="{{group.name}}">
<img src="/static/icons/minus-circle.png" alt="{% trans "Delete" %}" title="{% trans "Delete" %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans "Delete" %}" title="{% trans "Delete" %}" />
</a>
<a href="#" class="hide-group" data-id="{{group.id}}">
<img src="/static/icons/eye-half.png" alt="{% trans "Hide" %}" title="{% trans "Hide" %}" />
<img src="{% static "icons/eye-half.png" %}" alt="{% trans "Hide" %}" title="{% trans "Hide" %}" />
</a>
</div>
<div class="clear"></div>
......@@ -53,7 +54,7 @@
<li>
&nbsp;
<span class="value">
<a href="/group/show/{{group.id}}">{% trans "More details" %}</a>
<a href="{{group.get_absolute_url}}">{% trans "More details" %}</a>
</span>
</li>
</ul>
......
{% extends "box/base/box.html" %}
{% load i18n %}
{% load l10n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block boxhelp %}
<div class="boxhelp">
<div class="help">
<div class="icon">
<img src="{% static "icons/information-frame.png" %}" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
<p>{% blocktrans %}This is the list of this group's members.{% endblocktrans %}</p>
<p>{% blocktrans %}Members are the people who can start new
instances of templates shared with the group.
{% endblocktrans %}</p>
</div>
</div>
<div class="icon">
<img src="" alt="eye" title="{% trans "Show/hide box" %}" class="toggle-box" data-id="members" id="toggle-box-members"/>
</div>
</div>
{% endblock %}
{% block title %}
{% trans "Members of" %}: {{group.name}}
{% endblock title %}
......
{% extends "box/base/entry.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
......@@ -19,7 +20,7 @@
</div>
<div class="actions">
<a href="#" class="remove" data-gid="{{group.id}}" data-neptun="{{member.code}}">
<img src="/static/icons/minus-circle.png" alt="{% trans 'Remove' %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans 'Remove' %}" />
</a>
</div>
<div class="clear"></div>
......
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% get_current_language as LANGUAGE_CODE %}
{% block content %}
<div class="boxes">
......@@ -19,7 +20,7 @@
</div>
<!--<div class="actions">
<a href="#" class="remove" data-gid="{{group.id}}" data-neptun="{{owner.code}}">
<img src="/static/icons/minus-circle.png" alt="{% trans 'Remove' %}" />
<img src="{% static "icons/minus-circle.png" %}" alt="{% trans 'Remove' %}" />
</a>
</div>-->
<div class="clear"></div>
......
......@@ -98,8 +98,10 @@ def login(request):
co.save()
g.save()
try:
affiliation = request.META['affiliation']
except KeyError:
affiliation = ''
if affiliation == '':
affiliation = []
else:
......
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 sign in to comment