Commit 2bd43c4c by tarokkk

Merge branch 'master' of giccero.cloud.ik.bme.hu:cloud

parents 6d78f082 d30fc623
...@@ -197,6 +197,7 @@ store_settings = { ...@@ -197,6 +197,7 @@ store_settings = {
"store_client_key": "/opt/webadmin/cloud/client.key", "store_client_key": "/opt/webadmin/cloud/client.key",
"store_client_cert": "/opt/webadmin/cloud/client.crt", "store_client_cert": "/opt/webadmin/cloud/client.crt",
"store_url": "http://localhost:9000", "store_url": "http://localhost:9000",
"store_public": "store.ik.bme.hu",
} }
......
...@@ -93,11 +93,16 @@ urlpatterns = patterns('', ...@@ -93,11 +93,16 @@ urlpatterns = patterns('',
url(r'^ajax/group/(?P<gid>\d+)/add/$', url(r'^ajax/group/(?P<gid>\d+)/add/$',
'school.views.group_ajax_add_new_member', 'school.views.group_ajax_add_new_member',
name='group_ajax_add_new_member'), name='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'),
url(r'^ajax/group/(?P<gid>\d+)/remove/$', url(r'^ajax/group/(?P<gid>\d+)/remove/$',
'school.views.group_ajax_remove_member', 'school.views.group_ajax_remove_member',
name='group_ajax_remove_member'), name='group_ajax_remove_member'),
url(r'^ajax/group/delete/$', 'school.views.group_ajax_delete', url(r'^ajax/group/delete/$', 'school.views.group_ajax_delete',
name='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'^key/add/$', 'one.views.key_add', name='key_add'),
url(r'^ajax/key/delete/$', 'one.views.key_ajax_delete', url(r'^ajax/key/delete/$', 'one.views.key_ajax_delete',
name='key_ajax_delete'), name='key_ajax_delete'),
......
...@@ -300,8 +300,8 @@ class firewall: ...@@ -300,8 +300,8 @@ class firewall:
'\n'.join(self.RULES_NAT) + '\n') '\n'.join(self.RULES_NAT) + '\n')
def ipset(): def ipset():
week = datetime.now()-timedelta(days=7) week = datetime.now()-timedelta(days=2)
return models.Blacklist.objects.filter(Q(type='tempban', modified_at__gte=week) | Q(type='permban')).values_list('ipv4', flat=True) return models.Blacklist.objects.filter(Q(type='tempban', modified_at__gte=week) | Q(type='permban')).values('ipv4', 'reason')
def ipv6_to_octal(ipv6): def ipv6_to_octal(ipv6):
...@@ -450,8 +450,8 @@ def dhcp(): ...@@ -450,8 +450,8 @@ def dhcp():
'router': i_vlan.ipv4, 'router': i_vlan.ipv4,
'ntp': i_vlan.ipv4, 'ntp': i_vlan.ipv4,
'dnsserver': settings['rdns_ip'], 'dnsserver': settings['rdns_ip'],
'extra': "range %s" % (i_vlan.dhcp_pool 'extra': ("range %s" % i_vlan.dhcp_pool
if m else "deny unknown clients"), if m else "deny unknown-clients"),
'interface': i_vlan.interface, 'interface': i_vlan.interface,
'name': i_vlan.name, 'name': i_vlan.name,
'tftp': i_vlan.ipv4 'tftp': i_vlan.ipv4
......
...@@ -45,7 +45,7 @@ def firewall_api(request): ...@@ -45,7 +45,7 @@ def firewall_api(request):
obj.reason=data["reason"] obj.reason=data["reason"]
obj.snort_message=data["snort_message"] obj.snort_message=data["snort_message"]
obj.save() obj.save()
return HttpResponse(_("OK")); return HttpResponse(unicode(_("OK")));
if not (data["vlan"] == "vm-net" or data["vlan"] == "war"): if not (data["vlan"] == "vm-net" or data["vlan"] == "war"):
raise Exception(_("Only vm-net and war can be used.")) raise Exception(_("Only vm-net and war can be used."))
...@@ -88,4 +88,4 @@ def firewall_api(request): ...@@ -88,4 +88,4 @@ def firewall_api(request):
except: except:
return HttpResponse(_("Something went wrong!\n")); return HttpResponse(_("Something went wrong!\n"));
return HttpResponse(_("OK")); return HttpResponse(unicode(_("OK")));
from celery import Celery, task from celery import Celery, task
import subprocess import subprocess
import time, re import time, re
import socket
BROKER_URL = 'amqp://nyuszi:teszt@localhost:5672/django'
IRC_CHANNEL = '/home/cloud/irc/irc.atw.hu/#ik/in'
try:
from local_settings import *
except:
pass
CELERY_CREATE_MISSING_QUEUES=True CELERY_CREATE_MISSING_QUEUES=True
celery = Celery('tasks', broker='amqp://nyuszi:teszt@localhost:5672/django') celery = Celery('tasks', broker=BROKER_URL)
@task(name="firewall.tasks.reload_firewall_task") @task(name="firewall.tasks.reload_firewall_task")
def t(data4, data6): def t(data4, data6):
...@@ -28,7 +37,7 @@ def t(data): ...@@ -28,7 +37,7 @@ def t(data):
print "blacklist" print "blacklist"
r = re.compile(r'^add blacklist ([0-9.]+)$') r = re.compile(r'^add blacklist ([0-9.]+)$')
data_new = data data_new = [ x['ipv4'] for x in data]
data_old = [] data_old = []
p = subprocess.Popen(['/usr/bin/sudo', '/usr/sbin/ipset', 'save', 'blacklist'], shell=False, stdout=subprocess.PIPE) p = subprocess.Popen(['/usr/bin/sudo', '/usr/sbin/ipset', 'save', 'blacklist'], shell=False, stdout=subprocess.PIPE)
...@@ -37,8 +46,8 @@ def t(data): ...@@ -37,8 +46,8 @@ def t(data):
if x: if x:
data_old.append(x.group(1)) data_old.append(x.group(1))
l_add = list(set(data).difference(set(data_old))) l_add = list(set(data_new).difference(set(data_old)))
l_del = list(set(data_old).difference(set(data))) l_del = list(set(data_old).difference(set(data_new)))
ipset = [] ipset = []
ipset.append('create blacklist hash:ip family inet hashsize 4096 maxelem 65536') ipset.append('create blacklist hash:ip family inet hashsize 4096 maxelem 65536')
...@@ -50,4 +59,12 @@ def t(data): ...@@ -50,4 +59,12 @@ def t(data):
p = subprocess.Popen(['/usr/bin/sudo', '/usr/sbin/ipset', 'restore', '-exist'], shell=False, stdin=subprocess.PIPE) p = subprocess.Popen(['/usr/bin/sudo', '/usr/sbin/ipset', 'restore', '-exist'], shell=False, stdin=subprocess.PIPE)
p.communicate("\n".join(ipset) + "\n") p.communicate("\n".join(ipset) + "\n")
try:
with open(IRC_CHANNEL, 'w') as f:
for x in data:
if x['ipv4'] in l_add:
f.write('%(ip)s(%(hostname)s) kibachva %(reason)s miatt\n' % { 'ip': x['ipv4'], 'reason': x['reason'], 'hostname': socket.gethostbyaddr(x['ipv4'])[0]})
except:
print "nem sikerult mircre irni"
raise
...@@ -6,8 +6,8 @@ msgid "" ...@@ -6,8 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-19 18:42+0100\n" "POT-Creation-Date: 2013-02-21 18:06+0100\n"
"PO-Revision-Date: 2013-02-10 14:27+0100\n" "PO-Revision-Date: 2013-02-21 18:09+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hungarian <cloud@ik.bme.hu>\n" "Language-Team: Hungarian <cloud@ik.bme.hu>\n"
"Language: hu\n" "Language: hu\n"
...@@ -17,75 +17,108 @@ msgstr "" ...@@ -17,75 +17,108 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
"X-Generator: Lokalize 1.4\n" "X-Generator: Lokalize 1.4\n"
#: static/cloud.js:187 static/cloud.js.c:764 #: static/script/cloud.js:24
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
msgid "Delete"
msgstr "Törlés"
#: static/script/cloud.js:36
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!"
#: static/script/cloud.js:36
msgid "Reset"
msgstr "Újragenerálás"
#: static/script/cloud.js:65 static/script/store.js:309
msgid "Rename"
msgstr "Átnevezés"
#: static/script/cloud.js:221 static/script/store.js:273
msgid "Cancel" msgid "Cancel"
msgstr "Mégsem" msgstr "Mégsem"
#: static/cloud.js:201 #: static/script/cloud.js:235
#, c-format #, c-format
msgid "Are you sure stopping %s?" msgid "Are you sure stopping %s?"
msgstr "Biztosan felfüggeszti a következőt: %s?" msgstr "Biztosan felfüggeszti a következőt: %s?"
#: static/cloud.js:202 #: static/script/cloud.js:236
msgid "Stop" msgid "Stop"
msgstr "Felfüggesztés" msgstr "Felfüggesztés"
#: static/cloud.js:211 #: static/script/cloud.js:245
#, c-format #, c-format
msgid "Are you sure deleting %s?" msgid "Are you sure deleting %s?"
msgstr "Biztosan törli a következőt: %s?" msgstr "Biztosan törli a következőt: %s?"
#: static/cloud.js:212 static/cloud.js.c:286 static/cloud.js.c:430 #: static/script/cloud.js:255
#: static/cloud.js:764
msgid "Delete"
msgstr "Törlés"
#: static/cloud.js:221
#, c-format #, c-format
msgid "Are you sure restarting %s?" msgid "Are you sure restarting %s?"
msgstr "Biztosan újraindítja a következőt: %s?" msgstr "Biztosan újraindítja a következőt: %s?"
#: static/cloud.js:222 #: static/script/cloud.js:256
msgid "Restart" msgid "Restart"
msgstr "Újraindítás" msgstr "Újraindítás"
#: static/cloud.js:285 #: static/script/cloud.js:319
#, c-format #, c-format
msgid "Are you sure deleting this %s template?" msgid "Are you sure deleting this %s template?"
msgstr "Biztosan törli a következő sablont: %s?" msgstr "Biztosan törli a következő sablont: %s?"
#: static/cloud.js:430 #: static/script/cloud.js:452 static/script/cloud.js.c:459
msgid "Add owner"
msgstr "Tulajdonos hozzáadása"
#: static/script/cloud.js:457
msgid "Unknown"
msgstr "Ismeretlen"
#: static/script/cloud.js:533
#, c-format #, c-format
msgid "Are you sure deleting <strong>%s</strong>" msgid "Are you sure deleting <strong>%s</strong>"
msgstr "Törli a következő fájlt: <strong>%s</strong>" msgstr "Törli a következő fájlt: <strong>%s</strong>"
#: static/cloud.js:554 static/cloud.js.c:563 static/cloud.js.c:572 #: static/script/store.js:57 static/script/store.js.c:66
#: static/cloud.js:703 static/cloud.js.c:758 #: static/script/store.js:75 static/script/store.js.c:205
#: static/script/store.js:267
msgid "file" msgid "file"
msgstr "fájl" msgstr "fájl"
#: static/cloud.js:759 #: static/script/store.js:268
#, c-format #, c-format
msgid "You are removing the file <strong>%s</strong>." msgid "You are removing the file <strong>%s</strong>."
msgstr "Törli a következő fájlt: <strong>%s</strong>." msgstr "Törli a következő fájlt: <strong>%s</strong>."
#: static/cloud.js:761 #: static/script/store.js:270
#, c-format #, c-format
msgid "You are removing the folder <strong>%s</strong> (and its content)." 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>." msgstr "Törli a következő könyvtárat és tartalmát: <strong>%s</strong>."
#: static/cloud.js:764 #: static/script/store.js:273
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Biztos benne?" msgstr "Biztos benne?"
#: static/cloud.js:916 static/cloud.js.c:918 #: static/script/store.js:427 static/script/store.js.c:429
msgid "Upload" msgid "Upload"
msgstr "Feltöltés" msgstr "Feltöltés"
#: static/cloud.js:918 #: static/script/store.js:429
msgid "done, processing..." msgid "done, processing..."
msgstr "kész, feldolgozás..." msgstr "kész, feldolgozás..."
#: static/cloud.js:981 #, fuzzy
msgid "Please choose a different name." #~ msgid "Are you sure about reseting store credentials"
msgstr "Kérem, válasszon eltérő nevet." #~ msgstr "Biztosan újraindítja a következőt: %s?"
#~ msgid "Please choose a different name."
#~ msgstr "Kérem, válasszon eltérő nevet."
...@@ -9,6 +9,9 @@ $(function() { ...@@ -9,6 +9,9 @@ $(function() {
$(this).next('.details').slideDown(700); $(this).next('.details').slideDown(700);
} }
}) })
$('a').click(function(e){
e.stopPropagation();
});
$('.delete-template').click(function(e) { $('.delete-template').click(function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
...@@ -30,7 +33,7 @@ $(function() { ...@@ -30,7 +33,7 @@ $(function() {
}); });
}); });
$('#reset-key').click(function(e){ $('#reset-key').click(function(e){
vm_confirm_popup(gettext('Are you sure about reseting store credentials'), gettext('Reset'), function(){ vm_confirm_popup(gettext('Are you sure about reseting store credentials?<br /> You will lose your access to your store account on your existing virtual machines!'), gettext('Reset'), function(){
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/ajax/key/reset/', url: '/ajax/key/reset/',
...@@ -41,7 +44,7 @@ $(function() { ...@@ -41,7 +44,7 @@ $(function() {
}); });
}); });
$('.entry .summary').click(toggleDetails); $('.entry .summary').click(toggleDetails);
if(window.navigator.userAgent.indexOf('cloud-gui') > -1) { if(window.navigator.userAgent.indexOf('cloud-gui') < 0) {
$('.connect-vm').click(function(e) { $('.connect-vm').click(function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
...@@ -179,24 +182,16 @@ $(function() { ...@@ -179,24 +182,16 @@ $(function() {
$('#new-group-semester').change(updateSummary); $('#new-group-semester').change(updateSummary);
$('#new-group-members').change(updateSummary); $('#new-group-members').change(updateSummary);
}); });
$('#vm-password-show').click(function() {
$('#vm-password-show').hide();
$('#vm-password').show();
});
$('.hidden-password').each(function() {
$(this).val('******');
});
$('.hidden-password').click(function() { $('.hidden-password').click(function() {
if(!$(this).hasClass('shown')) { if($(this).attr('type') == 'password'){
$(this).val($(this).data('value')); $(this).attr('type', 'text');
$(this).addClass('shown'); $(this).addClass('shown');
} else { } else {
$(this).val('******'); $(this).attr('type', 'password');
$(this).removeClass('shown'); $(this).removeClass('shown');
} }
}) });
toggleDetails.apply($('.selected-summary')); $('.selected-summary').next().show();
toggleDetails.apply($('.selected-summary'));
/** /**
* Connect button new window * Connect button new window
*/ */
...@@ -204,15 +199,12 @@ $(function() { ...@@ -204,15 +199,12 @@ $(function() {
function get_vm_details(id) { function get_vm_details(id) {
$.get('/vm/credentials/' + id, function(data) { $.get('/vm/credentials/' + id, function(data) {
$('#modal-container').html(data); $('#modal-container').html(data);
$('.hidden-password').each(function() { $('#modal-container .hidden-password').click(function() {
$(this).val('******'); if($(this).attr('type') == 'password'){
}); $(this).attr('type', 'text');
$('.hidden-password').click(function() {
if(!$(this).hasClass('shown')) {
$(this).val($(this).data('value'));
$(this).addClass('shown'); $(this).addClass('shown');
} else { } else {
$(this).val('******'); $(this).attr('type', 'password');
$(this).removeClass('shown'); $(this).removeClass('shown');
} }
}) })
...@@ -430,11 +422,64 @@ $(function() { ...@@ -430,11 +422,64 @@ $(function() {
}); });
$('#new-owner').click(function() { $('#new-owner').click(function() {
$('#new-owner-form').toggle(); $('#new-owner-form input[type=text]').focus();
}); });
$('#new-owner-form input').click(function(e) { $('#new-owner-form input').click(function(e) {
e.stopPropagation(); e.stopPropagation();
}); });
$('#new-owner-form input').keyup(function() {
var timer;
return function(e){
var val=$(this).val().split(' ')[0];
clearTimeout(timer);
timer=setTimeout(function(){
if(val.length<1) return;
$.ajax({
type: 'POST',
data: 'q='+val,
url: '/ajax/group/autocomplete/',
dataType: 'json',
success: function(data){
console.log(data);
$('#new-owner-autocomplete')[0].innerHTML='<ul>';
var el=$('#new-owner-autocomplete')[0];
for(var i in data){
var d=data[i];
el.innerHTML+='<li>'
+d.name+': '
+d.neptun
+' <input type="button" value="'+gettext('Add owner')+'" data-neptun="'+d.neptun+'" />'
+'<div class="clear"></div></li>';
}
if(data.length == 0){
el.innerHTML+='<li>'
+gettext('Unknown')+': '
+val
+' <input type="button" value="'+gettext('Add owner')+'" data-neptun="'+val+'" />'
+'<div class="clear"></div></li>';
}
el.innerHTML+='</ul>';
$(el).find('input').each(function(){
var self=this;
$(this).click(function(e){
e.stopPropagation();
$.ajax({
type: 'POST',
data: 'neptun='+$(self).data('neptun'),
url: '/ajax/group/'+$('#new-owner').data('gid')+'/addOwner/',
dataType: 'json',
success: function(data){
window.location.reload();
}
})
})
})
}
});
},1000);
e.stopPropagation();
}
}());
$('#new-owner-form input[type=submit]').click(function() { $('#new-owner-form input[type=submit]').click(function() {
var neptun = $(this).prev().val(); var neptun = $(this).prev().val();
$.ajax({ $.ajax({
...@@ -464,6 +509,19 @@ $(function() { ...@@ -464,6 +509,19 @@ $(function() {
} }
}); });
}); });
/*$('#group-owners .remove').click(function(e) {
e.preventDefault();
e.stopPropagation();
var neptun = $(this).data('neptun');
$.ajax({
type: 'POST',
url: '/ajax/group/' + $(this).data('gid') + '/remove/',
data: 'neptun=' + neptun,
success: function(data) {
$('#member-' + neptun).slideUp(700);
}
});
});*/
$('#groups .delete').click(function(e) { $('#groups .delete').click(function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
......
...@@ -218,9 +218,9 @@ var cloud = (function(cloud) { ...@@ -218,9 +218,9 @@ var cloud = (function(cloud) {
*/ */
self.fadeIn = function(e) { self.fadeIn = function(e) {
//firefox sucks :S //firefox sucks :S
try{ try {
$(e).hide().slideDown(500); $(e).hide().slideDown(500);
}catch(ex){ } catch(ex) {
} }
} }
...@@ -479,6 +479,10 @@ var cloud = (function(cloud) { ...@@ -479,6 +479,10 @@ var cloud = (function(cloud) {
var model = new Model(); var model = new Model();
$(function() { $(function() {
ko.applyBindings(model); ko.applyBindings(model);
$('#keys').click(function(e) {
$('.key').slideDown(700);
$('#keys').slideUp(700);
});
}); });
document.addEventListener('dragenter', function(e) { document.addEventListener('dragenter', function(e) {
e.stopPropagation(); e.stopPropagation();
......
...@@ -42,6 +42,7 @@ body ...@@ -42,6 +42,7 @@ body
font-size:1.5em; font-size:1.5em;
margin-top:0; margin-top:0;
padding:10px; padding:10px;
position: relative;
} }
&.wide { &.wide {
margin-right: 30px; margin-right: 30px;
......
...@@ -101,6 +101,21 @@ ...@@ -101,6 +101,21 @@
float: none; float: none;
} }
} }
&.key {
.name {
background-image: url(/static/icons/key.png);
}
textarea {
margin: 10px;
width: 93%;
}
#new-key .name {
background-image: url(/static/icons/key--plus.png);
}
#reset-key .name {
background-image: url(/static/icons/key--exclamation.png);
}
}
.quota{ .quota{
left: 0; left: 0;
top: 0; top: 0;
...@@ -445,10 +460,10 @@ ...@@ -445,10 +460,10 @@
background-image: url(/static/icons/computer-off.png); background-image: url(/static/icons/computer-off.png);
} }
#template .wm .summary .name{ #template .entry .summary .name{
background-image: url(/static/icons/document-template.png) background-image: url(/static/icons/document-template.png)
} }
#template .wm .public-template .name{ #template .entry .public-template .name{
background-image: url(/static/icons/blue-document-share.png) background-image: url(/static/icons/blue-document-share.png)
} }
#new-template-button .name{ #new-template-button .name{
...@@ -599,18 +614,35 @@ table { ...@@ -599,18 +614,35 @@ table {
} }
} }
#keys {
.name {
background-image: url(/static/icons/key.png); .boxhelp {
position: relative;
.boxhelp-box {
color:#000;
position: absolute;
left: -100px;
width: 500px;
z-index: 1000000;
font-size: .7em;
background-color: #ffc;
border-radius:4px;
border:1px solid #aaa;
box-shadow:0 0 30px rgba(0,0,0,0.3);
margin:20px;
display: none;
} }
textarea { &:hover .boxhelp-box {
margin: 10px; display: block;
width: 93%;
} }
#new-key .name { .icon {
background-image: url(/static/icons/key--plus.png); display: block;
float: right;
} }
#reset-key .name { }
background-image: url(/static/icons/key--exclamation.png);
#new-owner-autocomplete {
input[type=button] {
float: right;
} }
} }
...@@ -11,13 +11,12 @@ ...@@ -11,13 +11,12 @@
<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" src="{% url django.views.i18n.javascript_catalog %}"></script>
<script type="text/javascript"> <script type="text/javascript">
//window.localStorage.clear(); window.localStorage.removeItem('https://cloud.ik.bme.hu/static/style/style.less:timestamp');
var current_user={{user.id}}; var current_user={{user.id}};
</script> </script>
<script src="/static/script/less.min.js"></script> <script src="/static/script/less.min.js"></script>
<script src="/static/script/knockout.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/util.js"></script>
<script type="text/javascript" src="/static/script/store.js"></script>
<script type="text/javascript" src="/static/script/cloud.js"></script> <script type="text/javascript" src="/static/script/cloud.js"></script>
{{ form.media }} {{ form.media }}
{% block js %}{% endblock %} {% block js %}{% endblock %}
......
<div class="contentblock"> <div class="contentblock">
<h2>{% block title %}Doboz címe (cseréld le){% endblock title %}</h2> <h2>{% block boxhelp %}{% endblock %}{% block title %}Doboz címe (cseréld le){% endblock title %}</h2>
<div class="content"> <div class="content">
{% block content %} {% block content %}
Doboz tartalma (cseréld le) Doboz tartalma (cseréld le)
......
...@@ -6,6 +6,26 @@ ...@@ -6,6 +6,26 @@
{% block title %} {% block title %}
{% trans "Data store" %} {% trans "Data store" %}
{% endblock title %} {% endblock title %}
{% block boxhelp %}
<div class="boxhelp">
<div class="icon">
<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>
<p>{% blocktrans %}You can access it from all your own virtual machines,
the lab client, this web interface, or through SFTP protocol.
{% endblocktrans %}</p>
<p>{% blocktrans %}This directory is mounted on Windows machines as Z:
drive, and on Linux ones as ~/sshfs.{% endblocktrans %}</p>
<p>{% blocktrans %}If you log in on lab machines (currently Ubuntu only),
you can see this folder also as ~/sshfs.{% endblocktrans %}</p>
<p>{% blocktrans with serv=storeserv %}You can also use an SFTP client (eg.
WinSCP) to access your files at {{serv}}. You will need to register a
public key bellow.{% endblocktrans %}</p>
</div>
</div>
{% endblock %}
{% block content %} {% block content %}
<ul class="file-list"> <ul class="file-list">
...@@ -47,7 +67,7 @@ ...@@ -47,7 +67,7 @@
</li> </li>
<!-- /ko --> <!-- /ko -->
</ul> </ul>
<ul class="file-list"> <ul class="entry-list">
<li class="entry small-row"> <li class="entry small-row">
<div class="summary" id="new-folder"> <div class="summary" id="new-folder">
<div class="name filetype-new-folder">{% trans "Create folder" %}</div> <div class="name filetype-new-folder">{% trans "Create folder" %}</div>
...@@ -64,6 +84,36 @@ ...@@ -64,6 +84,36 @@
<div class="clear"></div> <div class="clear"></div>
</div> </div>
</li> </li>
<li class="entry small-row key">
<div class="summary" id="keys">
<div class="name keys">{% trans "Manage keys" %}</div>
<div class="clear"></div>
</div>
</li>
{% for key in keys %}
{% include "box/key/entry.html" %}
{% endfor %}
<li class="entry small-row key" style="display: none">
<div class="summary" id="new-key">
<div class="name">{% trans "Add public key" %}</div>
<div class="clear"></div>
</div>
<div class="details">
<div class="container">
<form style="padding-bottom: 10px" action="/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" %}" />
</form>
</div>
</div>
</li>
<li class="entry small-row key" style="display: none">
<div class="summary" id="reset-key">
<div class="name">{% trans "Reset key" %}</div>
<div class="clear"></div>
</div>
</li>
<li class="file-upload entry small-row"> <li class="file-upload entry small-row">
<div class="summary" data-bind="click: getUploadURL"> <div class="summary" data-bind="click: getUploadURL">
<div class="quota"> <div class="quota">
......
{% extends "box/base/box.html" %}
{% load i18n %}
{% load l10n %}
{% get_current_language as LANGUAGE_CODE %}
{% block title %}
{% trans "Public keys" %}
{% endblock title %}
{% block content %}
<ul class="entry-list" id="keys">
{% for key in keys %}
{% include "box/key/entry.html" %}
{% endfor %}
<li class="entry small-row">
<div class="summary" id="new-key">
<div class="name">{% trans "Add public key" %}</div>
<div class="clear"></div>
</div>
<div class="details">
<form style="padding-bottom: 10px" action="/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" %}" />
</form>
</div>
</li>
<li class="entry small-row">
<div class="summary" id="reset-key">
<div class="name">{% trans "Reset key" %}</div>
<div class="clear"></div>
</div>
</li>
</ul>
{% endblock content %}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block content %} {% block content %}
<li class="entry" id="key-{{key.id}}"> <li class="entry key" id="key-{{key.id}}" style="display: none">
{{block.super}} {{block.super}}
</li> </li>
{% endblock content %} {% endblock content %}
......
...@@ -7,8 +7,23 @@ ...@@ -7,8 +7,23 @@
{% trans "Templates" %} {% trans "Templates" %}
{% endblock title %} {% endblock title %}
{% block boxhelp %}
<div class="boxhelp">
<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 your own templates.{% endblocktrans %}</p>
<p>{% blocktrans %}Templates are customized versions of the base images.{% endblocktrans %}</p>
<p>{% blocktrans %}You can install all the needed software on a master
machine, and it will be ready to run by your students in minutes.
{% endblocktrans %}</p>
</div>
</div>
{% endblock %}
{% block content %} {% block content %}
<ul class="vm-list entry-list"> <ul class="vm-list entry-list" id="template">
{% for t in mytemplates %} {% for t in mytemplates %}
{% include "box/template/entry.html" %} {% include "box/template/entry.html" %}
{% endfor %} {% endfor %}
......
...@@ -40,9 +40,9 @@ ...@@ -40,9 +40,9 @@
<a href="#" class="try-template" data-id="{{t.id}}" title="{% trans "Try" %}"> <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>
<a href="#" title="{% trans "Edit" %}"> <!--<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>-->
<a href="#" class="template-share" data-id="{{t.id}}" data-gid="{{group.id}}" title="{% trans "Share" %}"> <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> </a>
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
<a href="#" class="delete-template" data-id="{{ t.id }}" data-name="{{ t.name }}" title="{% trans "Remove" %}"> <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>
<a href="#" class="edit-template" data-id="{{ t.id }}" title="{% trans "Edit" %}"> <!--<a href="#" class="edit-template" data-id="{{ t.id }}" title="{% trans "Edit" %}">
<img src="/static/icons/pencil.png" alt="{% trans "Edit" %}" /> <img src="/static/icons/pencil.png" alt="{% trans "Edit" %}" />
</a> </a>-->
{% endblock actions %} {% endblock actions %}
...@@ -7,6 +7,21 @@ ...@@ -7,6 +7,21 @@
{% trans "Virtual machines" %} {% trans "Virtual machines" %}
{% endblock title %} {% endblock title %}
{% block boxhelp %}
<div class="boxhelp">
<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 your running virtual machines.{% endblocktrans %}</p>
<p>{% blocktrans %}You can launch a new VM instance if it is shared by
a teacher for one of your groups.{% endblocktrans %}</p>
<p>{% blocktrans %}Please note, that users and shares both have a limit
of launchable instances.{% endblocktrans %}</p>
</div>
</div>
{% endblock %}
{% block content %} {% block content %}
<ul class="vm-list entry-list"> <ul class="vm-list entry-list">
{% if instances %} {% if instances %}
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
{% endblock content %} {% endblock content %}
{% block name %} {% block name %}
<div class="name {% if i.state == 'ACTIVE' %}vm-on{% else %}vm-off{% endif %}"> <div class="name {% if vm.state == 'ACTIVE' %}vm-on{% else %}vm-off{% endif %}">
<span id="vm-{{vm.id}}-name">{{vm.name|truncatechars:20}}</span> <span id="vm-{{vm.id}}-name">{{vm.name|truncatechars:20}}</span>
<small id="vm-{{vm.id}}-name-details" class="details"> <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/show/{{vm.id}}/" title="{{vm.name}}">{% trans "More details" %}</a>)
......
{% extends "base.html" %} {% extends "base.html" %}
{% load i18n %} {% load i18n %}
{% get_current_language as LANGUAGE_CODE %} {% get_current_language as LANGUAGE_CODE %}
{% block js %}
<script type="text/javascript" src="/static/script/store.js"></script>
{% endblock %}
{% block content %} {% block content %}
<div class="boxes"> <div class="boxes">
{% include "box/vm/box.html" %} {% include "box/vm/box.html" %}
{% include "box/key/box.html" %}
{% if userdetails.share_quota %} {% if userdetails.share_quota %}
{% include "box/template/box.html" %} {% include "box/template/box.html" %}
{% include "box/group/box.html" %} {% include "box/group/box.html" %}
......
...@@ -88,7 +88,24 @@ ...@@ -88,7 +88,24 @@
</div> </div>
{% if i.firewall_host %} {% if i.firewall_host %}
<div class="contentblock" id="ports"> <div class="contentblock" id="ports">
<h2>{% trans "Port administration" %}</h2> <h2>
<div class="boxhelp">
<div class="icon">
<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
forwarded to the public internet.{% endblocktrans %}</p>
<p>{% blocktrans %}You can access the given private port of
the VM trough the public address of the network.
{% endblocktrans %}</p>
<p>{% blocktrans %}On the IPV6 network you can access the
listed private ports direcly using the VM's global IPV6
address (connections to other ports are dropped).
{% endblocktrans %}</p>
</div>
</div>
{% trans "Port administration" %}</h2>
<div class="content"> <div class="content">
<form action="{% url vm_port_add i.id %}" method="post"> <form action="{% url vm_port_add i.id %}" method="post">
{% csrf_token %} {% csrf_token %}
......
...@@ -4,7 +4,34 @@ ...@@ -4,7 +4,34 @@
<table> <table>
<tr> <tr>
<th>{% trans "Protocol" %}:</th> <th>{% trans "Protocol" %}:</th>
<td>{{i.template.access_type|upper}}</td> <td>
<div class="boxhelp">
<div class="icon">
<img src="/static/icons/information-frame.png" alt="{% trans "Help" %}" />
</div>
<div class="boxhelp-box">
{% if i.template.os_type == 'linux' %}
<p>{% blocktrans %}You can access Linux machines through
the SSH protocol (we recommend
<a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">
PuTTY</a> for Windows and OpenSSH for all other systems).
{% endblocktrans %}</p>
{% if i.template.access_type == 'nx' %}
<p>{% blocktrans %}Graphical log in is also supported with
the <a href="http://www.nomachine.com/download.php">
NoMachine NX Client</a> application.{% endblocktrans %}</p>
{% endif %}
{% else %}
<p>{% blocktrans %}You can access Windows machines through
the remote desktop protocol.{% endblocktrans %}</p>
<p>{% blocktrans %}We recommend the built-in remote desktop
client for Windows and Remmina for Linux.{% endblocktrans %}</p>
{% endif %}
</div>
</div>
{{i.template.access_type|upper}}
</td>
</tr> </tr>
<tr> <tr>
<th>{% trans "IP" %}:</th> <th>{% trans "IP" %}:</th>
...@@ -20,7 +47,7 @@ ...@@ -20,7 +47,7 @@
</tr> </tr>
<tr> <tr>
<th>{% trans "Password" %}:</th> <th>{% trans "Password" %}:</th>
<td><input type="text" class="hidden-password" data-value="{{ i.pw }}" /></td> <td><input type="password" class="hidden-password" value="{{ i.pw }}" /></td>
</tr> </tr>
</table> </table>
</div> </div>
...@@ -20,6 +20,7 @@ from django.utils.translation import ugettext_lazy as _ ...@@ -20,6 +20,7 @@ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import * from django.views.decorators.http import *
from django.views.generic import * from django.views.generic import *
from firewall.tasks import * from firewall.tasks import *
from cloud.settings import store_settings
from one.models import * from one.models import *
from school.models import * from school.models import *
import django.contrib.auth as auth import django.contrib.auth as auth
...@@ -41,6 +42,15 @@ def home(request): ...@@ -41,6 +42,15 @@ def home(request):
for i, s in enumerate(shares): for i, s in enumerate(shares):
s.running_shared = s.instance_set.all().exclude(state="DONE").filter(owner=request.user).count() s.running_shared = s.instance_set.all().exclude(state="DONE").filter(owner=request.user).count()
shares[i] = s shares[i] = s
try:
details = UserCloudDetails.objects.get(user=request.user)
except UserCloudDetails.DoesNotExist:
details = UserCloudDetails(user=request.user)
details.save()
try:
generated_public_key = details.ssh_key.id
except:
generated_public_key = -1
return render_to_response("home.html", RequestContext(request, { return render_to_response("home.html", RequestContext(request, {
'shares': shares, 'shares': shares,
'templates': Template.objects.filter(state='READY'), 'templates': Template.objects.filter(state='READY'),
...@@ -48,8 +58,9 @@ def home(request): ...@@ -48,8 +58,9 @@ def home(request):
'instances': _list_instances(request), 'instances': _list_instances(request),
'groups': request.user.person_set.all()[0].owned_groups.all(), 'groups': request.user.person_set.all()[0].owned_groups.all(),
'semesters': Semester.objects.all(), 'semesters': Semester.objects.all(),
'userdetails': UserCloudDetails.objects.get(user=request.user), 'userdetails': details,
'keys': request.user.sshkey_set.all() 'keys': request.user.sshkey_set.exclude(id=generated_public_key).all(),
'storeserv': store_settings['store_public'],
})) }))
@login_required @login_required
...@@ -324,7 +335,6 @@ class VmPortAddView(View): ...@@ -324,7 +335,6 @@ class VmPortAddView(View):
raise ValidationError(_("Port number is in a restricted domain (22000 to 24000).")) raise ValidationError(_("Port number is in a restricted domain (22000 to 24000)."))
inst = get_object_or_404(Instance, id=iid, owner=request.user) inst = get_object_or_404(Instance, id=iid, owner=request.user)
inst.firewall_host.add_port(proto=request.POST['proto'], public=public, private=int(request.POST['private'])) inst.firewall_host.add_port(proto=request.POST['proto'], public=public, private=int(request.POST['private']))
reload_firewall_lock()
messages.success(request, _(u"Port %d successfully added.") % public) messages.success(request, _(u"Port %d successfully added.") % public)
except: except:
messages.error(request, _(u"Adding port failed.")) messages.error(request, _(u"Adding port failed."))
...@@ -343,7 +353,6 @@ def vm_port_del(request, iid, proto, public): ...@@ -343,7 +353,6 @@ def vm_port_del(request, iid, proto, public):
inst = get_object_or_404(Instance, id=iid, owner=request.user) inst = get_object_or_404(Instance, id=iid, owner=request.user)
try: try:
inst.firewall_host.del_port(proto=proto, public=public) inst.firewall_host.del_port(proto=proto, public=public)
reload_firewall_lock()
messages.success(request, _(u"Port %d successfully removed.") % public) messages.success(request, _(u"Port %d successfully removed.") % public)
except: except:
messages.error(request, _(u"Removing port failed.")) messages.error(request, _(u"Removing port failed."))
...@@ -447,9 +456,10 @@ def key_add(request): ...@@ -447,9 +456,10 @@ def key_add(request):
key.user=request.user key.user=request.user
key.full_clean() key.full_clean()
key.save() key.save()
_update_keys(request.user)
except ValidationError as e: except ValidationError as e:
messages.error(request, unicode(e)) messages.error(request, ''.join(e.messages))
except e: except:
messages.error(request, _('Failed to add public key')) messages.error(request, _('Failed to add public key'))
return redirect('/') return redirect('/')
...@@ -459,6 +469,7 @@ def key_ajax_delete(request): ...@@ -459,6 +469,7 @@ def key_ajax_delete(request):
try: try:
key=get_object_or_404(SshKey, id=request.POST['id'], user=request.user) key=get_object_or_404(SshKey, id=request.POST['id'], user=request.user)
key.delete() key.delete()
_update_keys(request.user)
except: except:
messages.error(request, _('Failed to delete public key')) messages.error(request, _('Failed to delete public key'))
return HttpResponse('OK') return HttpResponse('OK')
...@@ -470,8 +481,19 @@ def key_ajax_reset(request): ...@@ -470,8 +481,19 @@ def key_ajax_reset(request):
det=UserCloudDetails.objects.get(user=request.user) det=UserCloudDetails.objects.get(user=request.user)
det.reset_smb() det.reset_smb()
det.reset_keys() det.reset_keys()
_update_keys(request.user)
except: except:
messages.error(request, _('Failed to reset keys')) messages.error(request, _('Failed to reset keys'))
return HttpResponse('OK') return HttpResponse('OK')
def _update_keys(user):
details = user.cloud_details
password = details.smb_password
key_list = []
for key in user.sshkey_set.all():
key_list.append(key.key)
user = user.username
StoreApi.updateauthorizationinfo(user, password, key_list)
# vim: et sw=4 ai fenc=utf8 smarttab : # vim: et sw=4 ai fenc=utf8 smarttab :
...@@ -6,7 +6,7 @@ msgid "" ...@@ -6,7 +6,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-19 18:42+0100\n" "POT-Creation-Date: 2013-02-21 18:06+0100\n"
"PO-Revision-Date: 2013-02-19 18:47+0100\n" "PO-Revision-Date: 2013-02-19 18:47+0100\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: American English <kde-l10n-hu@kde.org>\n" "Language-Team: American English <kde-l10n-hu@kde.org>\n"
...@@ -155,7 +155,7 @@ msgstr "Nem található Személy objektum." ...@@ -155,7 +155,7 @@ msgstr "Nem található Személy objektum."
msgid "Invalid NEPTUN code found." msgid "Invalid NEPTUN code found."
msgstr "Érvénytelen Neptun-kód." msgstr "Érvénytelen Neptun-kód."
#: views.py:208 views.py:223 #: views.py:208 views.py:223 views.py:262
msgid "Invalid NEPTUN code" msgid "Invalid NEPTUN code"
msgstr "Érvénytelen Neptun-kód" msgstr "Érvénytelen Neptun-kód"
...@@ -163,35 +163,35 @@ msgstr "Érvénytelen Neptun-kód" ...@@ -163,35 +163,35 @@ msgstr "Érvénytelen Neptun-kód"
msgid "Owners of" msgid "Owners of"
msgstr "Tulajdonosok" msgstr "Tulajdonosok"
#: templates/show-group.html:22 templates/box/person/box.html:24 #: templates/show-group.html:22 templates/box/person/entry.html:22
msgid "Remove" msgid "Remove"
msgstr "Eltávolítás" msgstr "Eltávolítás"
#: templates/show-group.html:30 templates/box/person/box.html:32 #: templates/show-group.html:30 templates/box/person/entry.html:31
msgid "This user never logged in, no data available" msgid "This user never logged in, no data available"
msgstr "Ez a felhasználó még nem lépett be, nincs adat róla" msgstr "Ez a felhasználó még nem lépett be, nincs adat róla"
#: templates/show-group.html:34 templates/box/person/box.html:36 #: templates/show-group.html:34 templates/box/person/entry.html:35
msgid "Name" msgid "Name"
msgstr "Név" msgstr "Név"
#: templates/show-group.html:37 templates/box/person/box.html:39 #: templates/show-group.html:37 templates/box/person/entry.html:38
msgid "NEPTUN" msgid "NEPTUN"
msgstr "NEPTUN" msgstr "NEPTUN"
#: templates/show-group.html:50 templates/show-group.html.py:53 #: templates/show-group.html:50
msgid "Add owner" msgid "Add owner"
msgstr "Tulajdonos hozzáadása" msgstr "Tulajdonos hozzáadása"
#: templates/show-group.html:52 #: templates/show-group.html:55
msgid "Owner name/NEPTUN" msgid "Owner name/NEPTUN"
msgstr "Tulajdonos neve/NEPTUN-kódja" msgstr "Tulajdonos neve/NEPTUN-kódja"
#: templates/show-group.html:66 #: templates/show-group.html:68
msgid "This group has no shared templates." msgid "This group has no shared templates."
msgstr "Ennek a csoportnak egy sablon sincs megosztva." msgstr "Ennek a csoportnak egy sablon sincs megosztva."
#: templates/show-group.html:69 #: templates/show-group.html:71
msgid "Share one, and the group members can start their own virtual machine." msgid "Share one, and the group members can start their own virtual machine."
msgstr "" msgstr ""
"Osszon meg egyet, hogy a csoport tagjai is elindíthassák egy példányát." "Osszon meg egyet, hogy a csoport tagjai is elindíthassák egy példányát."
...@@ -221,7 +221,6 @@ msgid "Group name" ...@@ -221,7 +221,6 @@ msgid "Group name"
msgstr "Csoport neve" msgstr "Csoport neve"
#: templates/box/group/box.html:48 templates/box/group/entry.html:42 #: templates/box/group/box.html:48 templates/box/group/entry.html:42
#: templates/box/person/entry.html:36
msgid "Semester" msgid "Semester"
msgstr "Félév" msgstr "Félév"
...@@ -242,11 +241,10 @@ msgid "Done" ...@@ -242,11 +241,10 @@ msgid "Done"
msgstr "Kész" msgstr "Kész"
#: templates/box/group/entry.html:15 templates/box/group/entry.html.py:56 #: templates/box/group/entry.html:15 templates/box/group/entry.html.py:56
#: templates/box/person/entry.html:50
msgid "More details" msgid "More details"
msgstr "Részletek" msgstr "Részletek"
#: templates/box/group/entry.html:19 templates/box/person/entry.html:16 #: templates/box/group/entry.html:19
msgid "Delete" msgid "Delete"
msgstr "Törlés" msgstr "Törlés"
...@@ -254,19 +252,19 @@ msgstr "Törlés" ...@@ -254,19 +252,19 @@ msgstr "Törlés"
msgid "Hide" msgid "Hide"
msgstr "Elrejtés" msgstr "Elrejtés"
#: templates/box/group/entry.html:32 templates/box/person/entry.html:26 #: templates/box/group/entry.html:32
msgid "Course" msgid "Course"
msgstr "Tárgy" msgstr "Tárgy"
#: templates/box/group/entry.html:37 templates/box/person/entry.html:31 #: templates/box/group/entry.html:37
msgid "Not assigned" msgid "Not assigned"
msgstr "Nincs hozzárendelve" msgstr "Nincs hozzárendelve"
#: templates/box/group/entry.html:46 templates/box/person/entry.html:40 #: templates/box/group/entry.html:46
msgid "Owner(s)" msgid "Owner(s)"
msgstr "Tulajdonosok" msgstr "Tulajdonosok"
#: templates/box/group/entry.html:50 templates/box/person/entry.html:44 #: templates/box/group/entry.html:50
msgid "Member count" msgid "Member count"
msgstr "Tagok száma" msgstr "Tagok száma"
...@@ -274,11 +272,11 @@ msgstr "Tagok száma" ...@@ -274,11 +272,11 @@ msgstr "Tagok száma"
msgid "Members of" msgid "Members of"
msgstr "Tagok" msgstr "Tagok"
#: templates/box/person/box.html:52 templates/box/person/box.html.py:55 #: templates/box/person/box.html:17 templates/box/person/box.html.py:20
msgid "Add user" msgid "Add user"
msgstr "Felhasználó hozzáadása" msgstr "Felhasználó hozzáadása"
#: templates/box/person/box.html:54 #: templates/box/person/box.html:19
msgid "User NEPTUN code" msgid "User NEPTUN code"
msgstr "Felhasználó Neptun-kódja" msgstr "Felhasználó Neptun-kódja"
......
...@@ -17,11 +17,11 @@ ...@@ -17,11 +17,11 @@
{{owner}} ({{owner.code}}) {{owner}} ({{owner.code}})
{% endif %} {% endif %}
</div> </div>
<div class="actions"> <!--<div class="actions">
<a href="#" class="remove" data-gid="{{group.id}}" data-neptun="{{owner.code}}"> <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> </a>
</div> </div>-->
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<div class="details"> <div class="details">
...@@ -46,14 +46,16 @@ ...@@ -46,14 +46,16 @@
</li> </li>
{% endfor %} {% endfor %}
<li class="entry small-row"> <li class="entry small-row">
<div class="summary" id="new-owner"> <div class="summary" id="new-owner" data-gid="{{group.id}}">
<div class="name">{% trans "Add owner" %}</div> <div class="name">{% trans "Add owner" %}</div>
<div id="new-owner-form">
<input type="text" placeholder="{% trans "Owner name/NEPTUN" %}" disabled="disabled" />
<input type="submit" value="{% trans "Add owner" %}" data-id="{{group.id}}" disabled="disabled" />
</div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
<div class="details" id="new-owner-form">
<div class="container">
<input type="text" placeholder="{% trans "Owner name/NEPTUN" %}" />
<div id="new-owner-autocomplete"></div>
</div>
</div>
</li> </li>
</ul> </ul>
</div> </div>
......
...@@ -183,7 +183,7 @@ def group_new(request): ...@@ -183,7 +183,7 @@ def group_new(request):
members_list = re.split('\r?\n', request.POST['members']) members_list = re.split('\r?\n', request.POST['members'])
members = [] members = []
for member in members_list: for member in members_list:
if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member) == None: if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member.strip()) == None:
messages.error(request, _('Invalid NEPTUN code found.')) messages.error(request, _('Invalid NEPTUN code found.'))
return redirect('/') return redirect('/')
person, created = Person.objects.get_or_create(code=member) person, created = Person.objects.get_or_create(code=member)
...@@ -203,7 +203,7 @@ def group_new(request): ...@@ -203,7 +203,7 @@ def group_new(request):
def group_ajax_add_new_member(request, gid): def group_ajax_add_new_member(request, gid):
group = get_object_or_404(Group, id=gid) group = get_object_or_404(Group, id=gid)
member = request.POST['neptun'] member = request.POST['neptun']
if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member) == None: if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member.strip()) == None:
status = json.dumps({'status': 'Error'}) status = json.dumps({'status': 'Error'})
messages.error(request, _('Invalid NEPTUN code')) messages.error(request, _('Invalid NEPTUN code'))
return HttpResponse(status) return HttpResponse(status)
...@@ -236,3 +236,34 @@ def group_ajax_delete(request): ...@@ -236,3 +236,34 @@ def group_ajax_delete(request):
return HttpResponse(json.dumps({ return HttpResponse(json.dumps({
'status': 'OK' 'status': 'OK'
})) }))
@login_required
def group_ajax_owner_autocomplete(request):
results = map(lambda u: {
'name': u.get_full_name(),
'neptun': u.username }, User.objects.filter(last_name__istartswith=request.POST['q'])[:5])
results += map(lambda u: {
'name': u.get_full_name(),
'neptun': u.username }, User.objects.filter(first_name__istartswith=request.POST['q'])[:5])
results += map(lambda u: {
'name': u.get_full_name(),
'neptun': u.username }, User.objects.filter(username__istartswith=request.POST['q'])[:5])
return HttpResponse(json.dumps(results, ensure_ascii=False))
@login_required
def group_ajax_add_new_owner(request, gid):
if request.user.cloud_details.share_quota == 0:
return HttpResponse({'status': 'denied'})
group = get_object_or_404(Group, id=gid)
member = request.POST['neptun']
if re.match('^[a-zA-Z][a-zA-Z0-9]{5}$', member.strip()) == None:
status = json.dumps({'status': 'Error'})
messages.error(request, _('Invalid NEPTUN code'))
return HttpResponse(status)
person, created = Person.objects.get_or_create(code=member)
group.owners.add(person)
group.save()
return HttpResponse(json.dumps({
'status': 'OK'
}))
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