Commit 3e045de3 by Dudás Ádám

Merge branch 'master' into dev-siliconbrain

Conflicts:
	cloud/urls.py
	firewall/fw.py
parents bc37daf9 de982c2f
......@@ -179,6 +179,27 @@ import djcelery
djcelery.setup_loader()
BROKER_URL = 'django://'
store_settings = {
"basic_auth": "True",
"verify_ssl": "False",
"ssl_auth": "False",
"store_client_pass": "IQu8Eice",
"store_client_user": "admin",
"store_client_key": "/opt/webadmin/cloud/client.key",
"store_client_cert": "/opt/webadmin/cloud/client.crt",
"store_url": "http://localhost:9000",
}
firewall_settings = {
"default_vlangroup": "publikus",
"reload_sleep": "10",
"dns_hostname": "dns1.ik.bme.hu",
"rdns_ip": "152.66.243.60",
"dns_ip": "152.66.243.60",
"dns_ttl": "300",
}
try:
from cloud.local_settings import *
except:
......
......@@ -32,7 +32,18 @@ urlpatterns = patterns('',
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/templateWizard$', 'one.views.ajax_template_wizard',
name='ajax_template_wizard'),
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'),
)
......@@ -80,9 +80,6 @@ class RuleAdmin(admin.ModelAdmin):
class AliasAdmin(admin.ModelAdmin):
list_display = ('alias', 'host')
class SettingAdmin(admin.ModelAdmin):
list_display = ('key', 'value', 'description')
class GroupAdmin(admin.ModelAdmin):
list_display = ('name', 'owner', 'description')
inlines = (RuleInline, )
......@@ -94,7 +91,6 @@ admin.site.register(Host, HostAdmin)
admin.site.register(Vlan, VlanAdmin)
admin.site.register(Rule, RuleAdmin)
admin.site.register(Alias, AliasAdmin)
admin.site.register(Setting, SettingAdmin)
admin.site.register(Group, GroupAdmin)
admin.site.register(VlanGroup)
admin.site.register(Firewall, FirewallAdmin)
......@@ -2,6 +2,7 @@ from django.contrib import auth
from firewall import models
from modeldict import *
import os
from cloud.settings import firewall_settings as settings
import subprocess
import re
......@@ -393,33 +394,26 @@ def dns():
m = regex.search(i_vlan.net4)
if i_vlan.name != "DMZ" and i_vlan.name != "PUB":
DNS.append("Z%s.%s.in-addr.arpa:%s:support.ik.bme.hu::::::%s" %
(m.group(2), m.group(1), models.settings['dns_hostname'],
models.settings['dns_ttl']))
(m.group(2), m.group(1), settings['dns_hostname'],
settings['dns_ttl']))
DNS.append("&%s.%s.in-addr.arpa::%s:%s:" % (m.group(2),
m.group(1), models.settings['dns_hostname'],
models.settings['dns_ttl']))
m.group(1), settings['dns_hostname'], settings['dns_ttl']))
DNS.append("Z%s:%s:support.ik.bme.hu::::::%s" % (i_vlan.domain,
models.settings['dns_hostname'], models.settings['dns_ttl']))
settings['dns_hostname'], settings['dns_ttl']))
DNS.append("&%s::%s:%s" % (i_vlan.domain,
models.settings['dns_hostname'], models.settings['dns_ttl']))
settings['dns_hostname'], settings['dns_ttl']))
if i_vlan.name == "WAR":
DNS.append("Zdns1.%s.%s.%s.in-addr.arpa:%s:"
"support.ik.bme.hu::::::%s" % (m.group(3),
m.group(2), m.group(1),
models.settings['dns_hostname'],
models.settings['dns_ttl']))
settings['dns_hostname'], settings['dns_ttl']))
DNS.append("&dns1.%s.%s.%s.in-addr.arpa::%s:%s::" %
(m.group(3), m.group(2), m.group(1),
models.settings['dns_hostname'],
models.settings['dns_ttl']))
settings['dns_hostname'], settings['dns_ttl']))
for i_host in i_vlan.host_set.all():
ipv4 = (i_host.pub_ipv4
if i_host.pub_ipv4 and not i_host.shared_ip
else i_host.ipv4)
reverse = (i_host.reverse
if i_host.reverse and len(i_host.reverse)
else i_host.hostname + u'.' + i_vlan.domain)
hostname = i_host.hostname + u'.' + i_vlan.domain
ipv4 = ( i_host.pub_ipv4 if i_host.pub_ipv4 and not i_host.shared_ip else i_host.ipv4 )
reverse = i_host.reverse if(i_host.reverse and len(i_host.reverse)) else i_host.hostname + u'.' + i_vlan.domain
hostname = i_host.get_fqdn()
# ipv4
if i_host.ipv4:
......@@ -438,18 +432,18 @@ def dns():
if i_host.ipv6:
# AAAA record
DNS.append(":%s:28:%s:%s" % (hostname,
ipv6_to_octal(i_host.ipv6), models.settings['dns_ttl']))
ipv6_to_octal(i_host.ipv6), settings['dns_ttl']))
# PTR record
DNS.append("^%s:%s:%s" % (ipv6_to_arpa(i_host.ipv6),
reverse, models.settings['dns_ttl']))
reverse, settings['dns_ttl']))
# cname
for i_alias in i_host.alias_set.all():
DNS.append("C%s:%s:%s" % (i_alias.alias, hostname,
models.settings['dns_ttl']))
settings['dns_ttl']))
process = subprocess.Popen(['/usr/bin/ssh', 'tinydns@%s' %
models.settings['dns_hostname']], shell=False, stdin=subprocess.PIPE)
settings['dns_hostname']], shell=False, stdin=subprocess.PIPE)
process.communicate("\n".join(DNS)+"\n")
# print "\n".join(DNS)+"\n"
......@@ -493,7 +487,7 @@ def dhcp():
'domain': i_vlan.domain,
'router': i_vlan.ipv4,
'ntp': i_vlan.ipv4,
'dnsserver': models.settings['rdns_ip'],
'dnsserver': settings['rdns_ip'],
'extra': "range %s" % (i_vlan.dhcp_pool
if m else "deny unknown-clients"),
'interface': i_vlan.interface,
......
......@@ -7,14 +7,7 @@ from django.utils.translation import ugettext_lazy as _
from firewall.fields import *
from south.modelsinspector import add_introspection_rules
from django.core.validators import MinValueValidator, MaxValueValidator
from modeldict import ModelDict
class Setting(models.Model):
key = models.CharField(max_length=32)
value = models.CharField(max_length=200)
description = models.TextField(blank=True)
settings = ModelDict(Setting, key='key', value='value', instances=False)
from cloud.settings import firewall_settings as settings
class Rule(models.Model):
CHOICES_type = (('host', 'host'), ('firewall', 'firewall'), ('vlan', 'vlan'))
......@@ -120,6 +113,12 @@ class Alias(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
def clean(self):
# FIXME later: critical race condition
for h in Host.objects.all():
if h.get_fqdn() == self.alias:
raise ValidationError(_("Host name already used."))
class Meta:
verbose_name_plural = 'aliases'
......@@ -179,6 +178,17 @@ class Host(models.Model):
def del_rules(self):
self.rules.filter(owner=self.owner).delete()
def get_fqdn(self):
return self.hostname + u'.' + self.vlan.domain
def clean(self):
# FIXME later: critical race condition
for a in Alias.objects.all():
if self.get_fqdn() == a.alias:
raise ValidationError(_("Host name already used as alias."))
class Firewall(models.Model):
name = models.CharField(max_length=20, unique=True)
......
......@@ -3,7 +3,7 @@ from django.core.cache import cache
import os
import time
from firewall.fw import *
from firewall.models import settings
from cloud.settings import firewall_settings as settings
def reload_firewall_lock():
acquire_lock = lambda: cache.add("reload_lock1", "true", 9)
......
......@@ -5,4 +5,4 @@ stop on runlevel [!2345]
respawn
exec /opt/webadmin/cloud/miscellaneous/store-server/CloudStore.py
exec bash -c "LC_ALL=en_US.UTF-8 /opt/webadmin/cloud/miscellaneous/store-server/CloudStore.py >>/var/log/cloudstore.log 2>&1"
......@@ -44,70 +44,6 @@
}
},
{
"pk": 1,
"model": "store.setting",
"fields": {
"value": "True",
"key": "basic_auth"
}
},
{
"pk": 2,
"model": "store.setting",
"fields": {
"value": "False",
"key": "verify_ssl"
}
},
{
"pk": 3,
"model": "store.setting",
"fields": {
"value": "False",
"key": "ssl_auth"
}
},
{
"pk": 4,
"model": "store.setting",
"fields": {
"value": "IQu8Eice",
"key": "store_client_pass"
}
},
{
"pk": 5,
"model": "store.setting",
"fields": {
"value": "admin",
"key": "store_client_user"
}
},
{
"pk": 6,
"model": "store.setting",
"fields": {
"value": "/opt/webadmin/cloud/client.key",
"key": "store_client_key"
}
},
{
"pk": 7,
"model": "store.setting",
"fields": {
"value": "/opt/webadmin/cloud/client.crt",
"key": "store_client_cert"
}
},
{
"pk": 8,
"model": "store.setting",
"fields": {
"value": "http://localhost:9000",
"key": "store_url"
}
},
{
"pk": 2,
"model": "one.network",
"fields": {
......
......@@ -4,5 +4,6 @@ start on runlevel [2345]
stop on runlevel [!2345]
respawn
respawn limit 30 30
exec /opt/webadmin/cloud/manage.py runserver 0.0.0.0:8080
exec sudo -u cloud /opt/webadmin/cloud/manage.py runserver 0.0.0.0:8080
......@@ -2,7 +2,7 @@
for i in cloudstore toplist django
do
sudo stop $i
sudo stop $i || true
done
set -x
cd /opt/webadmin/cloud
......@@ -51,4 +51,8 @@ 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 color.ui true
git config --global core.editor vim
true
@font-face {
font-family: 'Metrophobic';
font-style: normal;
font-weight: 400;
src: local('Metrophobic'), url(http://themes.googleusercontent.com/static/fonts/metrophobic/v3/0IZPA9DbzKXnGZABsAivT4bN6UDyHWBl620a-IRfuBk.woff) format('woff');
}
<!DOCTYPE html>
<html lang="hu-hu"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>IK Cloud</title>
<link rel="icon" type="image/png" href="https://cloud.ik.bme.hu/static/favicon.png">
<link rel="icon" type="image/png" href="https://cloud.ik.bme.hu/one/static/favicon.png">
<link href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;subset=latin,latin-ext" rel="stylesheet" type="text/css">
<style type="text/css" id="less:static-style">
body {
word-spacing: 2px;
letter-spacing: 0.5px;
min-height: 100%;
font-family: 'Titillium Web', sans-serif;
font-size: 12pt;
background: #dadada url(https://cloud.ik.bme.hu/static/site_bgr.png) repeat-x;
background-position: 80px 0;
margin: 0;
padding: 0;
overflow: scroll;
}
#content {
width: 970px;
text-align: left;
margin: 0 auto;
}
.contentblock {
background-color: #ccc;
border-radius: 4px;
border: 1px solid #aaa;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);
margin: 20px;
}
.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);
}
.contentblock h2 {
background-color: #000;
background-image: url(https://cloud.ik.bme.hu/static/hexabar.png);
background-position: right center;
background-repeat: no-repeat;
border-radius: 4px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
color: #eee;
font-size: 1.5em;
margin-top: 0;
padding: 10px;
}
#header {
height: 80px;
background-color: #072c61;
background-image: url(https://cloud.ik.bme.hu/static/bme_feher2.png);
background-repeat: no-repeat;
background-position: 20px 18px;
border-bottom: 3px solid #0B4599;
box-shadow: 0 0 30px rgba(0, 0, 0, 0.4);
margin: 0;
padding: 0 0 0 200px;
}
#header h1 {
font-size: 2em;
line-height: 80px;
float: left;
margin: 0;
padding: 0 1em;
}
#header h1 a {
color: #fff;
}
.boxes {
width: 480px;
float: left;
}
* {
margin: 0;
padding: 0;
}
.clear {
clear: both;
}
a {
text-decoration: none;
}
abbr {
border-bottom: 1px dotted #666;
}
a:link,
a:visited {
color: black;
}
strong {
font-size: .9em;
}
</style>
</head>
<body>
<div id="header">
<h1>
<a href="http://cloud.ik.bme.hu/">IK Cloud</a>
</h1>
</div>
<div id="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="IK Cloud_files/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="IK Cloud_files/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="https://cloud.ik.bme.hu/">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>
<div class="clear"></div>
</div>
</body>
</html>
#!/bin/bash
exec >>/tmp/pclog 2>&1
date
id
read old new
old=$(git rev-parse "$old")
new=$(git rev-parse "$new")
for i in $(git rev-list $old..$new)
do
sudo -u www-data /usr/local/bin/trac-admin /srv/trac/cloud/ changeset added cloud "$i"
git log --decorate --date-order --format='%h %d - %an: %s' "$i~..$i" > /home/git/irc/irc.atw.hu/#ik/in
done
#!/bin/bash
rmtag () {
sed -e 's/<[^>]*>//g' -e 's/^[ \t]*//g' -e 's/[ \t]*$//g'
}
wget -q --user=ircbot --password=rahX5eir --no-check-certificate 'https://giccero.cloud.ik.bme.hu/trac/cloud/login?referer=%2Ftrac%2Fcloud%2Ftimeline%3Fmilestone%3Don%26ticket%3Don%26wiki%3Don%26max%3D50%26authors%3D%26daysback%3D1%26format%3Drss' -O-|grep -E '(<guid|<title|<link)' | sed -e '1,4d' |
while read title; read link ;read guid
do
guid=$(rmtag <<<"$guid")
title=$(rmtag <<<"$title")
link=$(rmtag <<<"$link")
if ! grep -qs "$guid" ~/tracrss/old
then
echo "$guid" >> ~/tracrss/old
echo "$title <$link>" >~/irc/irc.atw.hu/#ik/in
fi
done
#!/usr/bin/env python
import gtk
import webkit
import gobject
import base64
import subprocess
import os
def keygen(length=1024):
import os, base64
from datetime import date
from Crypto.PublicKey import RSA
key = RSA.generate(length, os.urandom)
try:
pub = key.exportKey('OpenSSH')
if not pub.startswith("ssh-"):
raise ValueError(pub)
except:
ssh_rsa = '00000007' + base64.b16encode('ssh-rsa')
exponent = '%x' % (key.e, )
if len(exponent) % 2:
exponent = '0' + exponent
ssh_rsa += '%08x' % (len(exponent) / 2, )
ssh_rsa += exponent
modulus = '%x' % (key.n, )
if len(modulus) % 2:
modulus = '0' + modulus
if modulus[0] in '89abcdef':
modulus = '00' + modulus
ssh_rsa += '%08x' % (len(modulus) / 2, )
ssh_rsa += modulus
pub = 'ssh-rsa %s' % (
base64.b64encode(base64.b16decode(ssh_rsa.upper())), )
return key.exportKey(), "%s %s" % (pub, "cloud-%s" % date.today())
### Settings ###
KEY_DIR = "/tmp/"
KEY_FILE = KEY_DIR+"/id_rsa"
#Initalize keypair
private_key, public_key = keygen(2048)
#Saver private_key
with open(KEY_FILE,'w') as f:
f.write(private_key)
pub_key_string = base64.b64encode(public_key)
class Browser:
neptun = ""
host = ""
def __init__(self):
#Init window components
gobject.threads_init()
self.window = gtk.Window()
self.window.connect("destroy", self.destroy)
self.window.set_title("IK CloudStore Login")
#Init toolbar
self.toolbar = gtk.Toolbar()
#Init browser
self.browser = webkit.WebView()
self.browser.connect('onload-event', self.load_committed_cb)
# self.browser.open("http://10.9.1.86:8080")
self.browser.open("https://cloud.ik.bme.hu/store/gui/")
self.browser.connect("navigation-requested", self.on_navigation_requested)
#self.browser.open("http://index.hu")
#Sample button
self.help_button = gtk.ToolButton(gtk.STOCK_HELP)
self.help_button.connect("clicked",self.hello)
self.store_button = gtk.ToolButton(gtk.STOCK_HOME)
self.store_button.connect("clicked",self.store)
#Connect things
self.toolbar.add(self.store_button)
self.toolbar.add(self.help_button)
self.vbox = gtk.VBox(False, 0)
self.vbox.pack_start(self.toolbar, False, True, 0)
self.vbox.add(self.browser)
self.window.add(self.vbox)
#self.window.add(self.browser)
self.window.show_all()
def destroy(self, dummy):
self.browser.execute_script("resetKey()")
gtk.main_quit()
def on_navigation_requested(self, view, frame, req, data=None):
uri = req.get_uri()
#print "On nav: " + uri
scheme, rest = uri.split(':', 1)
#print scheme
try:
self.neptun, rest = rest.split(':', 1)
#print "Nep: "+neptun
self.host, values = rest.split('?', 1)
#print "Host: "+host
#print "Values: "+values
except:
pass
if scheme == 'login':
self.browser.execute_script("postKey(\"%s\")" % pub_key_string)
self.browser.execute_script("document.getElementById(\"login_button\").hidden=true ;")
self.browser.execute_script("document.getElementById(\"logout_button\").hidden=false ;")
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=false ;")
return True
elif scheme == 'logout':
self.browser.execute_script("resetKey()")
self.browser.execute_script("document.getElementById(\"logout_button\").hidden=true ;")
self.browser.execute_script("document.getElementById(\"login_button\").hidden=false ;")
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=true ;")
return True
elif scheme == "mount":
self.mount_sshfs_folder(self.neptun,self.host)
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=true ;")
self.browser.execute_script("document.getElementById(\"umount_button\").hidden=false ;")
return True
elif scheme == "umount":
self.umount_sshfs_folder()
self.browser.execute_script("document.getElementById(\"mount_button\").hidden=false ;")
self.browser.execute_script("document.getElementById(\"umount_button\").hidden=true ;")
return True
else:
return False
def mount_sshfs_folder(self,neptun,host):
with open(os.devnull, "w") as fnull:
result = subprocess.call(['/usr/bin/sshfs', '-o', 'IdentityFile='+KEY_DIR+"/id_rsa", neptun+"@"+host+":home", "/home/tarokkk/sshfs"])
#print result
def umount_sshfs_folder(self):
with open(os.devnull, "w") as fnull:
result = subprocess.call(['/bin/fusermount', '-u', "/home/tarokkk/sshfs"])
def hello(self, widget):
self.browser.open("https://login.bme.hu/admin/")
def store(self, widget):
self.browser.open("https://cloud.ik.bme.hu/store/gui/")
def load_committed_cb(self,web_view, frame):
self.browser.execute_script('document.getElementsByTagName("a")[0].target="";')
#uri = frame.get_uri()
#print uri
#print web_view.get_title()
return
def main(self):
gtk.main()
if __name__ == "__main__":
browser = Browser()
browser.main()
......@@ -23,19 +23,43 @@ SITE_HOST = config.get('store', 'site_host')
SITE_PORT = config.get('store', 'site_port')
# Temporary dir for tar.gz
TEMP_DIR = config.get('store', 'temp_dir')
#Redirect
try:
REDIRECT_URL = config.get('store', 'redirect_url')
except:
REDIRECT_URL = "https://cloud.ik.bme.hu"
#ForceSSL
try:
FORCE_SSL = config.get('store', 'force_ssl') == "True"
except:
FORCE_SSL = False
def force_ssl(original_function):
def new_function(*args, **kwargs):
if FORCE_SSL:
ssl = request.environ.get('SSL_CLIENT_VERIFY', 'NONE')
if ssl != "SUCCESS":
abort(403, "Forbidden requests. This site need SSL verification! SSL status: "+ssl)
else:
return original_function(*args, **kwargs)
else:
return original_function(*args, **kwargs)
return new_function
@route('/')
@force_ssl
def index():
response = "NONE"
try:
response = request.environi.get('SSL_CLIENT_VERIFY', 'NONE')
response = request.environ.get('SSL_CLIENT_VERIFY', 'NONE')
except:
pass
return "It works! SSL: "+response
# @route('/<neptun:re:[a-zA-Z0-9]{6}>', method='GET')
@route('/<neptun>', method='GET')
@force_ssl
def neptun_GET(neptun):
home_path = '/home/'+neptun+'/home'
if os.path.exists(home_path) != True:
......@@ -47,6 +71,7 @@ def neptun_GET(neptun):
COMMANDS = {}
@route('/<neptun>', method='POST')
@force_ssl
def neptun_POST(neptun):
# Check if user avaiable (home folder ready)
home_path = '/home/'+neptun+'/home'
......@@ -180,6 +205,7 @@ def cmd_toplist(request, neptun, home_path):
COMMANDS['TOPLIST'] = cmd_toplist
@route('/set/<neptun>', method='POST')
@force_ssl
def set_keys(neptun):
key_list = []
smb_password = ''
......@@ -198,6 +224,7 @@ def set_keys(neptun):
@route('/new/<neptun>', method='POST')
@force_ssl
def new_user(neptun):
key_list = []
smbpasswd=''
......@@ -266,8 +293,12 @@ def upload(hash_num):
for chunk in fbuffer(file_data.file):
f.write(chunk)
datalength += len(chunk)
return 'Upload finished: '+file_name+' - '+str(datalength)+' Byte'
try:
redirect_address = request.headers.get('Referer')
except:
redirect_address = REDIRECT_URL
redirect(redirect_address)
#return 'Upload finished: '+file_name+' - '+str(datalength)+' Byte'
......@@ -328,7 +359,7 @@ def file_dict(path, home):
is_dir = 'F'
return {'NAME': basename,
'TYPE': is_dir,
'SIZE': os.path.getsize(path)/1024,
'SIZE': os.path.getsize(path),
'MTIME': os.path.getmtime(path),
'DIR': os.path.relpath(os.path.dirname(path), home)}
......
......@@ -12,7 +12,7 @@ mask = IN_CREATE | IN_MODIFY | IN_DONT_FOLLOW
Register given file to ~/../.top dir as a symbolic link.
"""
def update_new(name):
norm = os.path.normpath(name)
norm = os.path.realpath(name)
if norm != name:
return # link
name = norm
......@@ -24,7 +24,7 @@ def update_new(name):
if not name.startswith(home):
return # outside home
top_dir = os.path.normpath(os.path.join(home, "../.top"))
top_dir = os.path.realpath(os.path.join(home, "../.top"))
try:
os.mkdir(top_dir)
except OSError:
......
# django-one module
# Copyright (C) 2013 BME IK
# This file is distributed under the same license as the django-one package.
# Mate Ory <orymate@iit.bme.hu>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-05 00:17+0100\n"
"PO-Revision-Date: 2013-02-05 00:18+0100\n"
"Last-Translator: Mate Ory <orymate@iit.bme.hu>\n"
"Language-Team: LANGUAGE <cloud@ik.bme.hu>\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
#: admin.py:40
msgid "Update status"
msgstr "Állapot frissítése"
#: admin.py:45
msgid "Submit VM"
msgstr "VM beküldése"
#: models.py:33
msgid "user"
msgstr "felhasználó"
#: models.py:35
msgid "Samba password"
msgstr "Samba jelszó"
#: models.py:36
msgid "Generated password for accessing store from Windows."
msgstr "Generált jelszó az adattár eléréséhez Windows alól."
#: models.py:37
msgid "SSH key (public)"
msgstr "SSH kulcs (nyilvános)"
#: models.py:38
msgid "Generated SSH public key for accessing store from Linux."
msgstr "Generált SSH publikus kulcs az adattár eléréséhez Linux alól."
#: models.py:39
msgid "SSH key (private)"
msgstr "SSH kulcs (magán)"
#: models.py:40
msgid "Generated SSH private key for accessing store from Linux."
msgstr "Generált SSH privát kulcs az adattár eléréséhez Linux alól."
#: models.py:86
#, python-format
msgid "OpenSSH key type %s is not supported."
msgstr "A következő OpenSSH kulcstípus nincs támogatva: %s."
#: models.py:95
msgid "Invalid OpenSSH public key."
msgstr "Érvénytelen OpenSSH nyilvános kulcs."
#: models.py:102
msgid "SSH key"
msgstr "SSH kulcs"
#: models.py:103
msgid ""
"<a href=\"/info/ssh/\">SSH public key in OpenSSH format</a> used for shell "
"login (2048+ bit RSA preferred). Example: <code>ssh-rsa AAAAB...QtQ== john</"
"code>."
msgstr ""
"<a href=\"/info/ssh/\">SSH nyilvános kulcs OpenSSH formátumban</a> az SSH "
"bejelentkezéshez – ajánlás: 2048+ bites RSA. Példa: <code><code>ssh-rsa "
"AAAAB...QtQ== jozsi</a>."
#: models.py:111
msgid "unnamed"
msgstr "névtelen"
#: models.py:119 models.py:156 models.py:195 models.py:206 models.py:228
msgid "name"
msgstr "név"
#: models.py:157
msgid "NAT"
msgstr "NAT"
#: models.py:157
msgid "If network address translation is done."
msgstr "Hálózati címfordítás történik-e."
#: models.py:158
msgid "public"
msgstr "publikus"
#: models.py:158
msgid "If internet gateway is available."
msgstr "Van-e elérheti internetes útválasztás."
#: models.py:196
msgid "CPU cores."
msgstr "CPU magok száma."
#: models.py:197
msgid "Mebibytes of memory."
msgstr "Memória mérete mebibyte-ban."
#: models.py:209
msgid "access method"
msgstr "elérési mód"
#: models.py:210
msgid "disk"
msgstr "lemez"
#: models.py:211
msgid "instance type"
msgstr "példánytípus"
#: models.py:212
msgid "network"
msgstr "hálózat"
#: models.py:213 models.py:231
msgid "owner"
msgstr "tulajdonos"
#: models.py:214 models.py:232
msgid "created at"
msgstr "létrehozás ideje"
#: models.py:220 models.py:230
msgid "template"
msgstr "sablon"
#: models.py:221
msgid "templates"
msgstr "sablonok"
#: models.py:229
msgid "IP address"
msgstr "IP cím"
#: models.py:234
msgid "deployable"
msgstr "beküldhető"
#: models.py:235
msgid "pending"
msgstr "várakozó"
#: models.py:236
msgid "done"
msgstr "kész"
#: models.py:237
msgid "active"
msgstr "aktív"
#: models.py:238
msgid "unknown"
msgstr "ismeretlen"
#: models.py:239
msgid "suspended"
msgstr "felfüggesztett"
#: models.py:240
msgid "failed"
msgstr "hiba"
#: models.py:242
msgid "active since"
msgstr "aktívvá válás ideje"
#: models.py:243
msgid "Time stamp of successful boot report."
msgstr "A sikeres indulás jelentésének időpontja."
#: models.py:244
msgid "host in firewall"
msgstr "gép a tűzfalban"
#: models.py:245
msgid "password"
msgstr "jelszó"
#: models.py:245
msgid "Original password of instance"
msgstr "A példány eredeti jelszava."
#: models.py:246
msgid "OpenNebula ID"
msgstr "OpenNebula ID"
#: models.py:451
msgid "instance"
msgstr "példány"
#: models.py:452
msgid "instances"
msgstr "példányok"
#: views.py:92
msgid "Failed to create virtual machine."
msgstr "A virtuális gép indítása sikertelen."
#: views.py:128
msgid "Port number is in a restricted domain (22000 to 24000)."
msgstr "A megadott port foglalt tartományba esik (22000-től 24000-ig)."
#: views.py:132
#, python-format
msgid "Port %d successfully added."
msgstr "%d számú port hozzáadása sikeres."
#: views.py:134
msgid "Adding port failed."
msgstr "Port hozzáadása sikertelen."
#: views.py:151
#, python-format
msgid "Port %d successfully removed."
msgstr "%d számú port eltávolítása sikeres."
#: views.py:153
msgid "Removing port failed."
msgstr "Port eltávolítása sikertelen."
#: views.py:160
msgid "Virtual machine is successfully deleted."
msgstr "A virtuális gép törlése sikeres."
#: views.py:162
msgid "Failed to delete virtual machine."
msgstr "A virtuális gép törlése sikertelen."
#: views.py:177
msgid "Virtual machine is successfully stopped."
msgstr "A virtuális gép sikeresen leállt."
#: views.py:179
msgid "Failed to stop virtual machine."
msgstr "A virtuális gép leállítása sikertelen."
#: views.py:187
msgid "Virtual machine is successfully resumed."
msgstr "A virtuális gép sikeresen folytatva."
#: views.py:189
msgid "Failed to resume virtual machine."
msgstr "A virtuális gép visszatöltése sikertelen."
#: views.py:197
msgid "Virtual machine is successfully powered off."
msgstr "A virtuális gép kikapcsolása sikeres."
#: views.py:199
msgid "Failed to power off virtual machine."
msgstr "A virtuális gép kikapcsolása sikertelen."
#: views.py:207
msgid "Virtual machine is successfully restarted."
msgstr "A virtuális gép újraindítása sikeres."
#: views.py:209
msgid "Failed to restart virtual machine."
msgstr "A virtuális gép újraindítása sikertelen."
......@@ -12,7 +12,7 @@ from firewall.tasks import reload_firewall_lock
from one.util import keygen
from school.models import Person
import subprocess, tempfile, os, stat, re
import subprocess, tempfile, os, stat, re, base64, struct
pwgen = User.objects.make_random_password
......@@ -26,6 +26,7 @@ def create_user_profile(sender, instance, created, **kwargs):
d.save()
post_save.connect(create_user_profile, sender=User)
"""
Cloud related details of a user
"""
......@@ -36,7 +37,7 @@ class UserCloudDetails(models.Model):
help_text=_('Generated password for accessing store from Windows.'))
ssh_key = models.ForeignKey('SshKey', null=True, verbose_name=_('SSH key (public)'),
help_text=_('Generated SSH public key for accessing store from Linux.'))
ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'),
ssh_private_key = models.TextField(verbose_name=_('SSH key (private)'), null=True,
help_text=_('Generated SSH private key for accessing store from Linux.'))
"""
......@@ -51,6 +52,8 @@ class UserCloudDetails(models.Model):
except:
self.ssh_key = SshKey(user=self.user, key=pub)
self.ssh_key.save()
self.ssh_key_id = self.ssh_key.id
self.save()
"""
Generate new Samba password.
......@@ -58,15 +61,12 @@ class UserCloudDetails(models.Model):
def reset_smb(self):
self.smb_password = pwgen()
"""
Generate key pair and Samba password if needed.
"""
def clean(self):
super(UserCloudDetails, self).clean()
if not self.ssh_key:
self.reset_keys()
if not self.smb_password or len(self.smb_password) == 0:
self.reset_smb()
def reset_keys(sender, instance, created, **kwargs):
if created:
instance.reset_smb()
instance.reset_keys()
post_save.connect(reset_keys, sender=UserCloudDetails)
"""
Validate OpenSSH keys (length and type).
......@@ -100,7 +100,7 @@ SSH public key (in OpenSSH format).
class SshKey(models.Model):
user = models.ForeignKey(User, null=False, blank=False)
key = models.CharField(max_length=2000, verbose_name=_('SSH key'),
help_text=_('<a href="/info/ssh/">SSH public key in OpenSSH format</a> used for shell login '
help_text=_('<a href="/info/ssh/">SSH public key in OpenSSH format</a> used for shell and store login '
'(2048+ bit RSA preferred). Example: <code>ssh-rsa AAAAB...QtQ== '
'john</code>.'), validators=[OpenSshKeyValidator()])
......@@ -225,11 +225,11 @@ Virtual machine instance.
"""
class Instance(models.Model):
name = models.CharField(max_length=100, unique=True,
verbose_name=_('név'), null=True, blank=True)
verbose_name=_('name'), null=True, blank=True)
ip = models.IPAddressField(blank=True, null=True, verbose_name=_('IP address'))
template = models.ForeignKey(Template, verbose_name=_('template'))
owner = models.ForeignKey(User, verbose_name=_('owner'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created_at'))
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_('created at'))
state = models.CharField(max_length=20,
choices=[('DEPLOYABLE', _('deployable')),
('PENDING', _('pending')),
......@@ -268,6 +268,8 @@ class Instance(models.Model):
def get_connect_uri(self):
try:
proto = self.template.access_type
if proto == 'ssh':
proto = 'sshterm'
port = self.get_port()
host = self.get_connect_host()
pw = self.pw
......
body
{
min-height:100%;
font-family:'Metrophobic',sans-serif;
font-family: 'Titillium Web', sans-serif;
font-size:.9em;
background:#dadada url(site_bgr.png) repeat-x;
background-position:80px 0;
......@@ -47,3 +47,90 @@ body
.wm-list{
list-style: none;
}
ul.messagelist
{
text-align:left;
margin:0;
padding:0 0 5px;
}
ul.messagelist li
{
font-size:12px;
display:block;
border-bottom:1px solid #ddd;
color:#666;
background:#ffc url(admin/img/icon_success.gif) 5px .3em no-repeat;
margin:0 0 3px;
padding:4px 5px 4px 25px;
}
ul.messagelist li.warning
{
background-image:url(admin/img/icon_alert.gif);
}
ul.messagelist li.error
{
background-image:url(admin/img/icon_error.gif);
}
.errornote
{
font-size:12px!important;
display:block;
border:1px solid red;
color:red;
background:#ffc url(admin/img/icon_error.gif) 5px .3em no-repeat;
margin:0 0 3px;
padding:4px 5px 4px 25px;
}
.errorlist li
{
font-size:12px!important;
display:block;
border:1px solid red;
color:#FFF;
background:red url(admin/img/icon_alert.gif) 5px .3em no-repeat;
margin:0 0 3px;
padding:4px 5px 4px 25px;
}
.errorlist li a
{
color:#FFF;
text-decoration:underline;
}
td ul.errorlist li
{
margin:0!important;
}
.errors
{
background:#ffc;
}
.errors input,.errors select,.errors textarea
{
border:1px solid red;
}
div.system-message
{
background:#ffc;
font-size:.8em;
margin:10px;
padding:6px 8px;
}
div.system-message p.system-message-title
{
color:red;
background:#ffc url(admin/img/icon_error.gif) 5px .3em no-repeat;
margin:0;
padding:4px 5px 4px 25px;
}
......@@ -35,6 +35,7 @@
#new-wm-tooltip{
position: relative;
z-index: 1;
}
#new-wm-tooltip-container{
margin: 10px 10px 5px 150px;
......@@ -137,6 +138,16 @@
}
}
}
#new-folder-form {
float: right;
margin-left: 5px;
display: none;
z-index: 2;
position: relative;
}
}
&.opened #new-folder-form {
display: block;
}
.details{
border-top: 1px solid #888;
......@@ -205,9 +216,6 @@
}
}
}
&.opened .details{
display: block;
}
&.new .name{
background-image: url(icons/computer--plus.png);
}
......@@ -215,6 +223,7 @@
.file-list{
list-style: none;
overflow: hidden;
.name{
float: left;
}
......@@ -237,7 +246,7 @@
background-image: url(icons/folder-zipper.png);
}
.filetype-folder {
background-image: url(icons/folder-horizontal.png);
background-image: url(icons/folder.png);
}
.filetype-more {
background-image: url(icons/arrow-circle-double.png);
......@@ -245,6 +254,12 @@
.filetype-up {
background-image: url(icons/upload-cloud.png);
}
.filetype-new-folder {
background-image: url(icons/folder--plus.png);
}
.filetype-jump-out {
background-image: url(icons/arrow-curve-090.png);
}
.wm-on{
background-image: url(icons/computer-cloud.png);
}
......
var toggleDetails;
$(function() {
function getCookie(name) {
var cookieValue = null;
if(document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for(var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if(cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
return(/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
crossDomain: false,
beforeSend: function(xhr, settings) {
if(!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
toggleDetails = function() {
if($(this).parent('.wm').hasClass('opened')){
$(this).parent('.wm').removeClass('opened');
$(this).next('.details').slideUp(700);
} else {
console.log('addClass');
$(this).parent('.wm').addClass('opened');
$(this).next('.details').slideDown(700);
}
}
$('.wm .summary').unbind('click').click(toggleDetails);
$('#load-more-files').click(function() {
$('.actions', this).show();
var that = this;
setTimeout(function() {
$(that).prev('li').slideDown(500, function() {
$('.actions', that).hide();
});
}, 2000);
})
$('#new-wm-button').click(function() {
$('#modal').show();
$('#modal-container').html($('#new-wm').html());
$('#modal-container .wm .summary').each(function() {
this.originalHeight = parseInt($(this).next('.details').css('height'));
})
$('#modal-container .wm .summary').click(toggleDetails);
});
$('#new-template-button').click(function() {
$('#modal').show();
$('#modal-container').html($('#new-template').html());
});
$('#shadow').click(function() {
$('#modal').hide();
})
$('#new-template-button').click(function() {
$.get('/ajax/templateWizard', function(data) {
$('#modal-container').html(data);
})
$('#modal').show();
});
function Model() {
var self = this;
self.files = ko.observableArray();
self.allFiles = [];
self.notInRoot = ko.observable(false);
self.fileLimit = 5;
function throttle(f) {
var disabled = false;
return function() {
if(disabled) {
console.log('disabled');
return
};
disabled = true;
setTimeout(function() {
disabled = false;
}, 700);
f.apply(null, arguments);
}
}
self.jumpUp = function() {
var s = self.currentPath();
loadFolder(s.substr(0, s.substr(0, s.length - 1).lastIndexOf('/') + 1));
}
var loadFolder = throttle(function(path) {
self.currentPath(path);
self.fileLimit = 5;
$.ajax({
type: 'POST',
data: 'path=' + path,
url: '/ajax/store/list',
dataType: 'json',
success: function(data) {
$('.file-list .real').css({
left: 0,
position: 'relative'
}).animate({
left: '-100%'
}, 500).promise().done(function() {
loadFolderDone(data);
$('.file-list .real').css({
left: '-300%',
position: 'relative'
}).animate({
left: 0
}, 500);
});
},
})
})
function loadFolderDone(data) {
var viewData = [];
var added = 0;
self.notInRoot(self.currentPath().lastIndexOf('/') !== 0);
self.files([]);
self.allFiles = data;
for(var i in data) {
added++;
if(added < 6) addFile(data[i]);
}
}
function addFile(d) {
var viewData;
if(d.TYPE === 'D') {
viewData = {
originalName: d.NAME,
name: d.NAME.length > 30 ? (d.NAME.substr(0, 27) + '...') : d.NAME,
size: 'katalógus',
type: 'katalógus',
mTime: d.MTIME,
getTypeClass: 'name filetype-folder',
clickHandler: function(item) {
loadFolder(self.currentPath() + item.originalName + '/');
}
};
} else {
viewData = {
originalName: d.NAME,
name: d.NAME.length > 30 ? (d.NAME.substr(0, 27) + '...') : d.NAME,
size: d.SIZE + 'K',
type: 'fájl',
mTime: d.MTIME,
getTypeClass: 'name filetype-text',
clickHandler: function(item, event) {}
};
}
self.files.push(viewData);
}
self.fadeIn = function(e) {
$(e).hide().slideDown(500);
}
self.currentPath = ko.observable('/');
self.showMore = function() {
for(var i = self.fileLimit; i < self.fileLimit + 5; i++) {
if(self.allFiles[i] === undefined) break;
addFile(self.allFiles[i]);
}
self.fileLimit += 5;
}
self.download = function(item) {
$.ajax({
type: 'POST',
data: 'dl=' + self.currentPath() + item.originalName,
url: '/ajax/store/download',
dataType: 'json',
success: function(data) {
window.location.href = data.url;
}
})
}
self.delete = function(item) {
$.ajax({
type: 'POST',
data: 'rm=' + self.currentPath() + item.originalName,
url: '/ajax/store/delete',
dataType: 'json',
success: function(data) {
loadFolder(self.currentPath());
}
})
}
self.uploadURL=ko.observable('/');
self.getUploadURL=function(){
$.ajax({
type: 'POST',
data: 'ul='+self.currentPath()+'&next='+encodeURI(window.location.href),
url: '/ajax/store/upload',
dataType: 'json',
success: function(data){
self.uploadURL(data.url);
}
}).error(function(){ console.log('asd', arguments)})
}
self.newFolderName=ko.observable();
self.newFolder=throttle(function(i,e){
$(e.target).parent().parent().parent().removeClass('opened');
$.ajax({
type: 'POST',
data: 'new='+self.newFolderName()+'&path='+self.currentPath(),
url: '/ajax/store/newFolder',
dataType: 'json',
success: function(data){
loadFolder(self.currentPath());
}
})
});
loadFolder(self.currentPath());
}
var model = new Model();
ko.applyBindings(model);
document.addEventListener('dragenter', function(e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
return false;
});
document.addEventListener('dragover', function(e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
return false;
});
document.addEventListener('drop', function(e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
console.log(e.dataTransfer.files)
return false;
});
})
......@@ -4,72 +4,15 @@
<html lang="{{lang}}">
<head>
<title>{% block title %}IK Cloud{% endblock %}</title>
<link href='http://fonts.googleapis.com/css?family=Metrophobic' rel='stylesheet' type='text/css'>
<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="icon" type="image/png" href="one/static/favicon.png">
<link rel="stylesheet/less" href="/static/style.less" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="/static/jquery.min.js"></script>
<script src="/static/less.min.js"></script>
<script type="text/javascript">
var toggleDetails;
$(function(){
$('.wm .summary').each(function(){
this.originalHeight=parseInt($(this).next('.details').css('height'));
})
toggleDetails=function(){
if($(this).next('.details').is(':hidden')){
$(this).next('.details')
.show()
.css('height',0)
.css('padding','0px 5px')
.animate({height:this.originalHeight,paddingTop:15,paddingBottom:15},700);
$(this).parent('.wm').addClass('opened');
} else {
var that=this;
$(this).next('.details')
//2*15px paddingot le kell vonni, a jQuery szar
.css('height',this.originalHeight-30)
.css('padding','15px 5px')
.animate({height:0,paddingTop:0,paddingBottom:0},700,function(){
$(that).parent('.wm').removeClass('opened');
$(that).next('.details').hide();
});
}
}
$('.wm .summary').click(toggleDetails);
$('#load-more-files').click(function(){
$('.actions', this).show();
var that=this;
setTimeout(function(){
$(that).prev('li').slideDown(500,function(){
$('.actions', that).hide();
});
},2000);
})
$('#new-wm-button').click(function(){
$('#modal').show();
$('#modal-container').html($('#new-wm').html());
$('#modal-container .wm .summary').each(function(){
this.originalHeight=parseInt($(this).next('.details').css('height'));
})
$('#modal-container .wm .summary').click(toggleDetails);
});
$('#new-template-button').click(function(){
$('#modal').show();
$('#modal-container').html($('#new-template').html());
});
$('#shadow').click(function(){
$('#modal').hide();
})
$('#new-template-button').click(function(){
$.get('/ajax/templateWizard', function(data){
$('#modal-container').html(data);
})
$('#modal').show();
});
})
</script>
<script src="/static/knockout.min.js"></script>
<script type="text/javascript" src="/static/cloud.js"></script>
{{ form.media }}
{% block js %}{% endblock %}
......
<div class="boxes">
<div class="contentblock">
<h2>
Adattár
</h2>
<div class="content">
<ul class="file-list">
<li class="wm small">
<div class="summary">
<div class="name">Jelenlegi hely: <span data-bind="text: currentPath"></span></div>
<div class="clear"></div>
</div>
</li>
<li class="wm real" data-bind="visible: notInRoot, click: jumpUp">
<div class="summary">
<div class="name filetype-jump-out">
..
</div>
<div class="clear"></div>
</div>
</li>
<li class="wm small real" data-bind="visible: files().length == 0">
<div class="summary">
<div class="name">Nincs megjeleníthető fájl.</div>
<div class="clear"></div>
</div>
</li>
<!-- ko foreach: {data:files,afterAdd:fadeIn} -->
<li class="wm real">
<div class="summary" data-bind="click: clickHandler">
<div class="name" data-bind="text: name, attr: {class: getTypeClass}"></div>
<div class="info" data-bind="text: size"></div>
<div class="actions">
<a href="#">
<img src="/static/icons/pencil.png" alt="rename" />
</a>
<a href="#" data-bind="click: $parent.delete, clickBubble: false">
<img src="/static/icons/minus-circle.png" alt="delete" />
</a>
<a href="#" data-bind="click: $parent.download, clickBubble: false">
<img src="/static/icons/download-cloud.png" alt="download" />
</a>
</div>
<div class="clear"></div>
</div>
<div class="details">
<div class="details-container">
<ul>
<li>Módosítva: <span class="value" data-bind="text: mTime"></span></li>
<li>Típus: <span class="value" data-bind="text: type"></span></li>
</ul>
</div>
</div>
</li>
<!-- /ko -->
<li class="file-details wm" id="load-more-files" data-bind="visible: (files().length>0 && files().length != allFiles.length)">
<div class="summary" data-bind="click: showMore">
<div class="name filetype-more">
Mutass több fájlt!
</div>
<div class="clear"></div>
</div>
</li>
<li class="wm">
<div class="summary">
<div class="name filetype-new-folder">Új mappa</div>
<div id="new-folder-form">
<input type="text" placeholder="Új mappa neve" data-bind="value: newFolderName, click: function(m,e){console.log(arguments); e.preventDefault(); e.stopPropagation(); return false;}" />
<input type="submit" data-bind="click: newFolder, clickBubble: false" value="Létrehozás" />
</div>
<div class="clear"></div>
</div>
</li>
<li class="file-upload wm">
<div class="summary" data-bind="click: getUploadURL">
<div class="name filetype-up">Fájlfeltöltés</div>
<div class="clear"></div>
</div>
<div class="details">
<div class="container">
<form method="POST" data-bind="attr: {action: uploadURL}" enctype="multipart/form-data">
{% csrf_token %}
<input name="data" type="file" />
<input type="submit" value="Feltöltés"/>
</form>
</div>
</div>
</li>
<li class="wm small">
<div class="summary">
<div class="quota">
<div class="used" style="background-color: rgba(0,255,0,0.2); width: 2%"></div>
</div>
<div class="name">Kvóta: 20MB/2GB</div>
<div class="clear"></div>
</div>
</li>
</ul>
</div>
</div>
</div>
......@@ -11,34 +11,49 @@
</div>
<div class="actions">
{% if i.state == 'ACTIVE' %}
<a href="{{i.get_connect_uri}}" title="Csatlakozás"><img src="static/icons/plug.png" alt="connect" /></a>
<a href="/vm/suspend/{{i.id}}/" onclick="alert('Hamarosan a mozikban.'); return false" title="Felfüggesztés"><img src="/static/icons/control-pause.png" alt="pause" /></a>
<a href="/vm/delete/{{i.id}}/" onclick="return confirm('Biztosan törli a gépet?')" title="Törlés"><img src="/static/icons/minus-circle.png" alt="delete" /></a>
<a href="/vm/reset/{{i.id}}/" onclick="alert('Hamarosan a mozikban.'); return false" title="Újraindítás"><img src="/static/icons/arrow-circle-double.png" alt="↺" /></a>
<a href="{{i.get_connect_uri}}" title="Csatlakozás">
<img src="static/icons/plug.png" alt="connect" />
</a>
<a href="/vm/suspend/{{i.id}}/" onclick="alert('Hamarosan a mozikban.'); return false" title="Felfüggesztés">
<img src="/static/icons/control-pause.png" alt="pause" />
</a>
<a href="/vm/delete/{{i.id}}/" onclick="return confirm('Biztosan törli a gépet?')" title="Törlés">
<img src="/static/icons/minus-circle.png" alt="delete" />
</a>
<a href="/vm/reset/{{i.id}}/" onclick="alert('Hamarosan a mozikban.'); return false" title="Újraindítás">
<img src="/static/icons/arrow-circle-double.png" alt="↺" />
</a>
{% endif %}
{% if i.state == 'PENDING' %}
<img src="/static/load-2.gif" /> indítás...
{% endif %}
{% if i.state == 'SUSPENDED' %}
<a href="/vm/continue/{{i.id}}/" title="Folytatás"><img src="/static/icons/control.png" alt="resume" /></a>
<a href="/vm/delete/{{i.id}}/" onclick="return confirm('Biztosan törli a gépet?')" title="Törlés"><img src="/static/icons/minus-circle.png" alt="delete" /></a>
<a href="/vm/continue/{{i.id}}/" title="Folytatás">
<img src="/static/icons/control.png" alt="resume" />
</a>
<a href="/vm/delete/{{i.id}}/" onclick="return confirm('Biztosan törli a gépet?')" title="Törlés">
<img src="/static/icons/minus-circle.png" alt="delete" />
</a>
{% endif %}
{% if i.state == 'FAILED' %}
<a href="/vm/delete/{{i.id}}/" title="Törlés"><img src="/static/icons/minus-circle.png" alt="delete" /></a>
<a href="/vm/delete/{{i.id}}/" title="Törlés">
<img src="/static/icons/minus-circle.png" alt="delete" />
</a>
{% endif %}
</div>
<div class="clear"></div>
</div>
<div class="details">
<h3>Részletek</h3>
<ul>
<li class="name">Gép neve: <span class="value">{{i.name}}</span></li>
<li class="os-linux">Operációs rendszer: <span class="value">{{i.template.disk.name}}</span></li>
<li class="type">Instance típus: <span class="value">{{i.template.instance_type.name}}</span></li>
<li class="date">Létrehozás dátuma: <span class="value">{{i.created_at}}</span></li>
<li class="date">Lejáratig: <span class="value"><abbr title="1 nap, 5 óra, 34 perc">1 nap</abbr></span></li>
<li>&nbsp;<span class="value"><a href="/vm/show/{{i.id}}/" title="{{i.name}}">További részletek</a></span></li>
</ul>
<div class="details-container"><h3>Részletek</h3>
<ul>
<li class="name">Gép neve: <span class="value">{{i.name}}</span></li>
<li class="os-linux">Operációs rendszer: <span class="value">{{i.template.disk.name}}</span></li>
<li class="type">Instance típus: <span class="value">{{i.template.instance_type.name}}</span></li>
<li class="date">Létrehozás dátuma: <span class="value">{{i.created_at}}</span></li>
<li class="date">Lejáratig: <span class="value"><abbr title="1 nap, 5 óra, 34 perc">1 nap</abbr></span></li>
<li>&nbsp;<span class="value"><a href="/vm/show/{{i.id}}/" title="{{i.name}}">További részletek</a></span></li>
</ul>
</div>
</div>
</li>
{% endfor %}
......
<!DOCTYPE html>
{% load i18n %}
{% get_current_language as lang %}
<html lang="{{lang}}">
<head>
<title>{% block title %}Superman{% endblock %}</title>
<link rel="icon" type="image/png" href="/static/favicon.png" />
<link rel="stylesheet" href="/static/style.css" />
{{ form.media }}
{% block js %}{% endblock %}
</head>
<body>
<div id="header">
{% block login %}
<div id="loginblock"><p>
{% if user.is_authenticated %}
{% blocktrans with user.get_profile.name|default:user.username as name %}
Logged in: <a href="/me/">{{ name }}</a>.
{% endblocktrans %}
<a href="/logout/">{% trans "Log out" %}</a>.
<a href="{% url project_own %}">{% trans "My projects" %}</a>.
{% if user.is_staff %}
<a href="/admin/">Admin</a>.
{% endif %}
{% else %}
<a href="/secure/login/">{% trans "EduID login" %}</a>.
{% endif %}
{% if lang == 'hu' %}
<a href="/language/en-US/">In English</a>.
{% else %}
<a href="/language/hu/">Magyarul</a>.
{% if autolang %}
<p style="position: absolute; top: 40px; right: 1em;" class="triangle-border top">Böngészője kifejezetten angol tartalmat kért.<br/>A <a href="/language/hu/">magyar változat</a> részletesebb és frissebb!</p>
{% endif %}
{% endif %}
</p>
</div>
{% endblock %}
{% block header %}
{% block header_title %}
<h1><a href="/">{% trans "BME HPC Cluster" %}</a></h1>
{% endblock %}
{% endblock %}
</div>
{% block messages %}
{% if messages %}
<ul class="messagelist">{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}</ul>
{% endif %}
{% endblock messages %}
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
# -*- coding: utf8 -*-
# -*- coding: utf-8 -*-
from datetime import datetime
from django.conf import settings
from django.contrib.auth.decorators import login_required
......@@ -125,13 +125,13 @@ class VmPortAddView(View):
public = int(request.POST['public'])
if public >= 22000 and public < 24000:
raise ValidationError("a port nem lehet 22000 es 24000 kozott")
raise ValidationError(_("Port number is in a restricted domain (22000 to 24000)."))
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']))
reload_firewall_lock()
messages.success(request, _(u"A port hozzáadása sikerült."))
messages.success(request, _(u"Port %d successfully added.") % public)
except:
messages.error(request, _(u"Nem sikerült a kért művelet"))
messages.error(request, _(u"Adding port failed."))
# raise
return redirect('/vm/show/%d/' % int(iid))
......@@ -148,9 +148,9 @@ def vm_port_del(request, iid, proto, public):
try:
inst.firewall_host.del_port(proto=proto, public=public)
reload_firewall_lock()
messages.success(request, _(u"A port törlése sikerült."))
messages.success(request, _(u"Port %d successfully removed.") % public)
except:
messages.error(request, _(u"Nem sikerült a kért művelet"))
messages.error(request, _(u"Removing port failed."))
return redirect('/vm/show/%d/' % int(iid))
class VmDeleteView(View):
......
from django.contrib import messages
from django.core.exceptions import ValidationError
from django import contrib
from django.utils.translation import ugettext_lazy as _
from school import models
import string
class GroupInline(contrib.admin.TabularInline):
model = models.Group
extra = 3
class CourseAdmin(contrib.admin.ModelAdmin):
model = models.Course
inlines = (GroupInline, )
filter_horizontal = ('owners', )
list_display = ('code', 'name', 'short_name', 'owner_list')
list_editable = ('name', 'short_name')
class GroupAdmin(contrib.admin.ModelAdmin):
model = models.Group
filter_horizontal = ('owners', 'members', )
list_display = ('name', 'course', 'semester', 'owner_list', 'member_count')
list_filter = ('semester', 'course')
class SemesterAdmin(contrib.admin.ModelAdmin):
model = models.Semester
list_display = ('id', 'name', 'start', 'end')
list_editable = ('name', 'start', 'end')
contrib.admin.site.register(models.Course, CourseAdmin)
contrib.admin.site.register(models.Semester, SemesterAdmin)
contrib.admin.site.register(models.Group, GroupAdmin)
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting model 'Entity'
db.delete_table('school_entity')
# Deleting model 'LessonClass'
db.delete_table('school_lessonclass')
# Deleting model 'Lesson'
db.delete_table('school_lesson')
# Deleting model 'Person'
db.delete_table('school_person')
# Deleting model 'Mark'
db.delete_table('school_mark')
# Deleting model 'Course'
db.delete_table('school_course')
# Deleting model 'Semester'
db.delete_table('school_semester')
# Deleting model 'Event'
db.delete_table('school_event')
# Deleting model 'Attendance'
db.delete_table('school_attendance')
# Deleting model 'Group'
db.delete_table('school_group')
def backwards(self, orm):
# Adding model 'Entity'
db.create_table('school_entity', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('parent', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Group'])),
('name', self.gf('django.db.models.fields.CharField')(max_length=100)),
))
db.send_create_signal('school', ['Entity'])
# Adding model 'LessonClass'
db.create_table('school_lessonclass', (
('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Group'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
))
db.send_create_signal('school', ['LessonClass'])
# Adding model 'Lesson'
db.create_table('school_lesson', (
('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Group'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('lesson_class', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.LessonClass'])),
))
db.send_create_signal('school', ['Lesson'])
# Adding model 'Person'
db.create_table('school_person', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('language', self.gf('django.db.models.fields.CharField')(default='hu', max_length=6)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)),
))
db.send_create_signal('school', ['Person'])
# Adding model 'Mark'
db.create_table('school_mark', (
('modified_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='modified_marks', to=orm['school.Person'])),
('value', self.gf('django.db.models.fields.CharField')(max_length=100)),
('student', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Person'])),
('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
('modified_at', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
('event', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Event'])),
('created_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='created_marks', to=orm['school.Person'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
))
db.send_create_signal('school', ['Mark'])
# Adding model 'Course'
db.create_table('school_course', (
('entity_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['school.Entity'], unique=True, primary_key=True)),
))
db.send_create_signal('school', ['Course'])
# Adding model 'Semester'
db.create_table('school_semester', (
('entity_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['school.Entity'], unique=True, primary_key=True)),
('start', self.gf('django.db.models.fields.DateField')()),
('end', self.gf('django.db.models.fields.DateField')()),
))
db.send_create_signal('school', ['Semester'])
# Adding model 'Event'
db.create_table('school_event', (
('type', self.gf('django.db.models.fields.CharField')(max_length=5)),
('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Group'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=100)),
))
db.send_create_signal('school', ['Event'])
# Adding model 'Attendance'
db.create_table('school_attendance', (
('modified_by', self.gf('django.db.models.fields.related.ForeignKey')(related_name='modified_attendances', to=orm['school.Person'])),
('modified_at', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
('student', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Person'])),
('lesson', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Lesson'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('present', self.gf('django.db.models.fields.NullBooleanField')(null=True, blank=True)),
))
db.send_create_signal('school', ['Attendance'])
# Adding model 'Group'
db.create_table('school_group', (
('entity_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['school.Entity'], unique=True, primary_key=True)),
('recursive_unique', self.gf('django.db.models.fields.BooleanField')(default=False)),
))
db.send_create_signal('school', ['Group'])
models = {
}
complete_apps = ['school']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Course'
db.create_table('school_course', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('code', self.gf('django.db.models.fields.CharField')(unique=True, max_length=10)),
('name', self.gf('django.db.models.fields.CharField')(max_length=80, null=True, blank=True)),
('default_group', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='default_group_of', null=True, to=orm['school.Group'])),
))
db.send_create_signal('school', ['Course'])
# Adding M2M table for field owners on 'Course'
db.create_table('school_course_owners', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('course', models.ForeignKey(orm['school.course'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('school_course_owners', ['course_id', 'user_id'])
# Adding model 'Semester'
db.create_table('school_semester', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('start', self.gf('django.db.models.fields.DateField')()),
('end', self.gf('django.db.models.fields.DateField')()),
))
db.send_create_signal('school', ['Semester'])
# Adding model 'Person'
db.create_table('school_person', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)),
))
db.send_create_signal('school', ['Person'])
# Adding model 'Group'
db.create_table('school_group', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=80)),
('course', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Course'], null=True, blank=True)),
('semester', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['school.Semester'])),
))
db.send_create_signal('school', ['Group'])
# Adding M2M table for field owners on 'Group'
db.create_table('school_group_owners', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('group', models.ForeignKey(orm['school.group'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('school_group_owners', ['group_id', 'user_id'])
# Adding M2M table for field members on 'Group'
db.create_table('school_group_members', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('group', models.ForeignKey(orm['school.group'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('school_group_members', ['group_id', 'user_id'])
# Adding unique constraint on 'Group', fields ['name', 'course', 'semester']
db.create_unique('school_group', ['name', 'course_id', 'semester_id'])
def backwards(self, orm):
# Removing unique constraint on 'Group', fields ['name', 'course', 'semester']
db.delete_unique('school_group', ['name', 'course_id', 'semester_id'])
# Deleting model 'Course'
db.delete_table('school_course')
# Removing M2M table for field owners on 'Course'
db.delete_table('school_course_owners')
# Deleting model 'Semester'
db.delete_table('school_semester')
# Deleting model 'Person'
db.delete_table('school_person')
# Deleting model 'Group'
db.delete_table('school_group')
# Removing M2M table for field owners on 'Group'
db.delete_table('school_group_owners')
# Removing M2M table for field members on 'Group'
db.delete_table('school_group_members')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'school.course': {
'Meta': {'object_name': 'Course'},
'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}),
'default_group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_group_of'", 'null': 'True', 'to': "orm['school.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'})
},
'school.group': {
'Meta': {'unique_together': "(('name', 'course', 'semester'),)", 'object_name': 'Group'},
'course': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Course']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'members': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'course_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'owned_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'semester': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Semester']"})
},
'school.person': {
'Meta': {'object_name': 'Person'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'school.semester': {
'Meta': {'object_name': 'Semester'},
'end': ('django.db.models.fields.DateField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'start': ('django.db.models.fields.DateField', [], {})
}
}
complete_apps = ['school']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Course.short_name'
db.add_column('school_course', 'short_name',
self.gf('django.db.models.fields.CharField')(max_length=10, null=True, blank=True),
keep_default=False)
# Adding field 'Semester.name'
db.add_column('school_semester', 'name',
self.gf('django.db.models.fields.CharField')(default="semester", unique=True, max_length=20),
keep_default=False)
def backwards(self, orm):
# Deleting field 'Course.short_name'
db.delete_column('school_course', 'short_name')
# Deleting field 'Semester.name'
db.delete_column('school_semester', 'name')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'school.course': {
'Meta': {'object_name': 'Course'},
'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}),
'default_group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_group_of'", 'null': 'True', 'to': "orm['school.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
'short_name': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'})
},
'school.group': {
'Meta': {'unique_together': "(('name', 'course', 'semester'),)", 'object_name': 'Group'},
'course': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Course']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'members': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'course_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'owned_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['auth.User']"}),
'semester': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Semester']"})
},
'school.person': {
'Meta': {'object_name': 'Person'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'school.semester': {
'Meta': {'object_name': 'Semester'},
'end': ('django.db.models.fields.DateField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
'start': ('django.db.models.fields.DateField', [], {})
}
}
complete_apps = ['school']
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing M2M table for field owners on 'Group'
db.delete_table('school_group_owners')
# Removing M2M table for field members on 'Group'
db.delete_table('school_group_members')
# Removing M2M table for field owners on 'Course'
db.delete_table('school_course_owners')
def backwards(self, orm):
# Adding M2M table for field owners on 'Group'
db.create_table('school_group_owners', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('group', models.ForeignKey(orm['school.group'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('school_group_owners', ['group_id', 'user_id'])
# Adding M2M table for field members on 'Group'
db.create_table('school_group_members', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('group', models.ForeignKey(orm['school.group'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('school_group_members', ['group_id', 'user_id'])
# Adding M2M table for field owners on 'Course'
db.create_table('school_course_owners', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('course', models.ForeignKey(orm['school.course'], null=False)),
('user', models.ForeignKey(orm['auth.user'], null=False))
))
db.create_unique('school_course_owners', ['course_id', 'user_id'])
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'school.course': {
'Meta': {'object_name': 'Course'},
'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}),
'default_group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_group_of'", 'null': 'True', 'to': "orm['school.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'short_name': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'})
},
'school.group': {
'Meta': {'unique_together': "(('name', 'course', 'semester'),)", 'object_name': 'Group'},
'course': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Course']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'semester': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Semester']"})
},
'school.person': {
'Meta': {'object_name': 'Person'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'school.semester': {
'Meta': {'object_name': 'Semester'},
'end': ('django.db.models.fields.DateField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
'start': ('django.db.models.fields.DateField', [], {})
}
}
complete_apps = ['school']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding M2M table for field owners on 'Group'
db.create_table('school_group_owners', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('group', models.ForeignKey(orm['school.group'], null=False)),
('person', models.ForeignKey(orm['school.person'], null=False))
))
db.create_unique('school_group_owners', ['group_id', 'person_id'])
# Adding M2M table for field members on 'Group'
db.create_table('school_group_members', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('group', models.ForeignKey(orm['school.group'], null=False)),
('person', models.ForeignKey(orm['school.person'], null=False))
))
db.create_unique('school_group_members', ['group_id', 'person_id'])
# Adding M2M table for field owners on 'Course'
db.create_table('school_course_owners', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('course', models.ForeignKey(orm['school.course'], null=False)),
('person', models.ForeignKey(orm['school.person'], null=False))
))
db.create_unique('school_course_owners', ['course_id', 'person_id'])
def backwards(self, orm):
# Removing M2M table for field owners on 'Group'
db.delete_table('school_group_owners')
# Removing M2M table for field members on 'Group'
db.delete_table('school_group_members')
# Removing M2M table for field owners on 'Course'
db.delete_table('school_course_owners')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'school.course': {
'Meta': {'object_name': 'Course'},
'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'}),
'default_group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_group_of'", 'null': 'True', 'to': "orm['school.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['school.Person']", 'null': 'True', 'blank': 'True'}),
'short_name': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'})
},
'school.group': {
'Meta': {'unique_together': "(('name', 'course', 'semester'),)", 'object_name': 'Group'},
'course': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Course']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'members': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'course_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['school.Person']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'owned_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['school.Person']"}),
'semester': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Semester']"})
},
'school.person': {
'Meta': {'object_name': 'Person'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'school.semester': {
'Meta': {'object_name': 'Semester'},
'end': ('django.db.models.fields.DateField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
'start': ('django.db.models.fields.DateField', [], {})
}
}
complete_apps = ['school']
\ No newline at end of file
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'Course.code'
db.alter_column('school_course', 'code', self.gf('django.db.models.fields.CharField')(unique=True, max_length=20))
def backwards(self, orm):
# Changing field 'Course.code'
db.alter_column('school_course', 'code', self.gf('django.db.models.fields.CharField')(max_length=10, unique=True))
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'school.course': {
'Meta': {'object_name': 'Course'},
'code': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
'default_group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'default_group_of'", 'null': 'True', 'to': "orm['school.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['school.Person']", 'null': 'True', 'blank': 'True'}),
'short_name': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'})
},
'school.group': {
'Meta': {'unique_together': "(('name', 'course', 'semester'),)", 'object_name': 'Group'},
'course': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Course']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'members': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'course_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['school.Person']"}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'owners': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'owned_groups'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['school.Person']"}),
'semester': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['school.Semester']"})
},
'school.person': {
'Meta': {'object_name': 'Person'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
},
'school.semester': {
'Meta': {'object_name': 'Semester'},
'end': ('django.db.models.fields.DateField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20'}),
'start': ('django.db.models.fields.DateField', [], {})
}
}
complete_apps = ['school']
\ No newline at end of file
......@@ -2,63 +2,121 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.core.exceptions import ValidationError
from datetime import datetime
def create_user_profile(sender, instance, created, **kwargs):
if created:
try:
Person.objects.create(user=instance)
except:
pass
post_save.connect(create_user_profile, sender=User)
LANGS = [('hu', _('Hungarian')), ('en_US', _('US English'))]
class Person(models.Model):
user = models.ForeignKey(User, null=False, blank=False, unique=True)
language = models.CharField(max_length=6, choices=LANGS, default='hu',
verbose_name=_('Preferred language'))
def __unicode__(self):
return self.user.__unicode__()
class Entity(models.Model):
parent = models.ForeignKey('school.Group')
name = models.CharField(max_length=100)
def short_name(self):
if self.user.last_name:
return self.user.last_name
else:
return self.user.username
def __unicode__(self):
u = self.user
if not u:
return unicode(_("(none)"))
if u.last_name and u.first_name:
return _("%(first)s %(last)s") % {'first': u.first_name,
'last': u.last_name}
else:
return u.username
class Course(models.Model):
code = models.CharField(max_length=20, unique=True)
name = models.CharField(max_length=80, null=True, blank=True)
short_name = models.CharField(max_length=10, null=True, blank=True)
default_group = models.ForeignKey('Group', null=True, blank=True,
related_name='default_group_of')
owners = models.ManyToManyField(Person, blank=True, null=True)
def get_or_create_default_group(self):
if self.default_group:
return self.default_group
else:
default_group = Group(name=_("%s (auto)") % self.short(),
semester=Semester.get_current(), course=self)
default_group.save()
self.default_group_id = default_group.id
self.save()
return default_group
def save(self, *args, **kwargs):
if self.default_group:
self.default_group.course = self
self.default_group.save()
self.full_clean()
super(Course, self).save(*args, **kwargs)
class Group(Entity):
recursive_unique = models.BooleanField()
def __unicode__(self):
if self.short_name:
return u"%s (%s)" % (self.code, self.name)
else:
return self.code
def short(self):
if self.short_name:
return self.short_name
else:
return self.code
def owner_list(self):
if self.owners:
return ", ".join([p.short_name() for p in self.owners.all()])
else:
return _("n/a")
class Course(Entity):
pass
class Semester(Entity):
class Semester(models.Model):
name = models.CharField(max_length=20, unique=True, null=False)
start = models.DateField()
end = models.DateField()
EVENT_CHOICES = [('free', _('free text')), ('num', _('number')), ('int', _('integer'))]
class Event(models.Model):
title = models.CharField(max_length=100)
group = models.ForeignKey('school.Group')
type = models.CharField(max_length=5, choices=EVENT_CHOICES)
class Mark(models.Model):
value = models.CharField(max_length=100)
student = models.ForeignKey('Person')
event = models.ForeignKey('school.Event')
created_by = models.ForeignKey('Person', related_name='created_marks')
created_at = models.DateTimeField(auto_now_add=True)
modified_by = models.ForeignKey('Person', related_name='modified_marks')
modified_at = models.DateTimeField(auto_now=True)
class Attendance(models.Model):
present = models.NullBooleanField()
student = models.ForeignKey('Person')
lesson = models.ForeignKey('school.Lesson')
modified_by = models.ForeignKey('Person',
related_name='modified_attendances')
modified_at = models.DateTimeField(auto_now=True)
class LessonClass(models.Model):
group = models.ForeignKey('school.Group')
class Lesson(models.Model):
lesson_class = models.ForeignKey('school.LessonClass')
group = models.ForeignKey('school.Group')
def is_on(self, time):
return self.start <= time.date() and self.end >= time.date()
@classmethod
def get_current(cls):
n = datetime.now()
current = [s for s in Semester.objects.all() if s.is_on(n)]
try:
return current[0]
except:
raise ValidationError(_('There is no current semester.'))
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=80, unique=True)
course = models.ForeignKey('Course', null=True, blank=True)
semester = models.ForeignKey('Semester', null=False, blank=False)
owners = models.ManyToManyField(Person, blank=True, null=True, related_name='owned_groups')
members = models.ManyToManyField(Person, blank=True, null=True, related_name='course_groups')
class Meta:
unique_together = (('name', 'course', 'semester', ), )
def owner_list(self):
if self.owners:
return ", ".join([p.short_name() for p in self.owners.all()])
else:
return _("n/a")
def member_count(self):
return self.members.count()
def __unicode__(self):
if self.course:
return "%s (%s)" % (self.name, self.course.short())
else:
return "%s (%s)" % (self.name, self.owner_list())
from datetime import datetime
from django.core.exceptions import ValidationError
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.auth.models import User, Group as AGroup
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.core import signing
......@@ -9,74 +10,105 @@ from django.core.mail import mail_managers, send_mail
from django.db import transaction
from django.forms import ModelForm, Textarea
from django.http import Http404
#from django_shibboleth.forms import BaseRegisterForm
from django.shortcuts import render, render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.decorators import method_decorator
from django.utils.http import is_safe_url
from django.utils.translation import get_language as lang
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import *
from django.views.generic import *
from one.models import *
from school.models import *
import django.contrib.auth as auth
import logging
from django.views.decorators.csrf import ensure_csrf_cookie
logger = logging.getLogger(__name__)
def logout(request):
auth.logout(request)
return redirect('/Shibboleth.sso/Logout?return=https%3a%2f%2fcloud.ik.bme.hu%2f')
SHIB_ATTRIBUTE_MAP = {
"HTTP_SHIB_IDENTITY_PROVIDER": (True, "idp"),
"email": (True, "email"),
"sn": (True, "sn"),
"givenName": (True, "givenName"),
"niifPersonOrgID": (True, "niifPersonOrgID"),
}
@ensure_csrf_cookie
def login(request):
try:
user = User.objects.get(username=request.META['niifPersonOrgID'])
except KeyError:
messages.error(request, _('EduID is not available.'))
return redirect('/admin')
except User.DoesNotExist:
user = User(username=request.META['niifPersonOrgID'])
user.set_unusable_password()
user.first_name = request.META['givenName']
user.last_name = request.META['sn']
user.email = request.META['email']
user.save()
p, created = Person.objects.get_or_create(user=user)
p.save()
try:
sem = Semester.get_current()
def parse_attributes(META):
shib_attrs = {}
error = False
for header, attr in SHIB_ATTRIBUTE_MAP.items():
required, name = attr
values = META.get(header, None)
value = None
if values:
# If multiple attributes releases just care about the 1st one
attended = request.META['HTTP_NIIFEDUPERSONATTENDEDCOURSE']
if attended == '':
attended = []
else:
attended = attended.split(';')
for c in attended:
try:
value = values.split(';')[0]
co = Course.objects.get(code=c)
except:
value = values
shib_attrs[name] = value
if not value or value == '':
if required:
error = True
return shib_attrs, error
continue
g = co.get_or_create_default_group()
if p.course_groups.filter(semester=sem, course=co).count() == 0:
try:
g.members.add(p)
g.save()
messages.info(request, _('Course "%s" added.') % g.course)
except Exception as e:
logger.warning("Django ex %s" % e)
except ValidationError as e:
logger.warning("Django ex4 %s" % e)
def logout(request):
auth.logout(request)
return redirect('/Shibboleth.sso/Logout?return=https%3a%2f%2fcloud.ik.bme.hu%2f')
held = request.META['HTTP_NIIFEDUPERSONHELDCOURSE']
if held == '':
held = []
else:
held = held.split(';')
for c in held:
co, created = Course.objects.get_or_create(code=c)
if created:
logger.warning("django Course %s created" % c)
g = co.get_or_create_default_group()
try:
co.owners.add(p)
g.owners.add(p)
messages.info(request, _('Course "%s" ownership added.') % g.course)
except Exception as e:
logger.warning("Django ex %s" % e)
co.save()
g.save()
def login(request):
attr, error = parse_attributes(request.META)
if not attr['niifPersonOrgID']:
messages.error(request, _('EduID is not available.'))
return redirect('/admin')
try:
user = User.objects.get(username=attr['niifPersonOrgID'])
except User.DoesNotExist:
user = User(username=attr['niifPersonOrgID'])
user.set_unusable_password()
user.first_name = attr['givenName']
user.last_name = attr['sn']
user.email = attr['email']
affiliation = request.META['affiliation']
if affiliation == '':
affiliation = []
else:
affiliation = affiliation.split(';')
for a in affiliation:
g, created = AGroup.objects.get_or_create(name=a)
user.groups.add(g)
user.save()
p.save()
user.backend = 'django.contrib.auth.backends.ModelBackend'
auth.login(request, user)
logger.warning("Shib login with %s" % request.META)
return redirect('/')
redirect_to = request.REQUEST.get(auth.REDIRECT_FIELD_NAME, '')
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = settings.LOGIN_REDIRECT_URL
return redirect(redirect_to)
from django.contrib import admin
from store.models import *
class SettingAdmin(admin.ModelAdmin):
list_display = ('key', 'value')
admin.site.register(Setting, SettingAdmin)
from django.db import models
from django.http import Http404
import json, requests, time
from modeldict import ModelDict
from store.models import settings
from cloud.settings import store_settings as settings
# Create your models here.
#TODO Handle exceptions locally
......@@ -16,6 +15,9 @@ class StoreApi:
# ssl_auth = True
# verify_ssl = False
@staticmethod
def get_host():
return settings['store_host']
@staticmethod
def post_request(url, payload):
headers = {'content-type': 'application/json'}
if settings['ssl_auth'] == 'True' and settings['basic_auth'] == 'True':
......@@ -126,6 +128,14 @@ class StoreApi:
else:
return False
@staticmethod
def requestquota(neptun):
url = settings['store_url']+'/'+neptun
r = StoreApi.get_request(url)
if r.status_code == requests.codes.ok:
return json.loads(r.content)
else:
return False
@staticmethod
def userexist(neptun):
url = settings['store_url']+'/'+neptun
r = StoreApi.get_request(url)
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting model 'Setting'
db.delete_table('store_setting')
def backwards(self, orm):
# Adding model 'Setting'
db.create_table('store_setting', (
('value', self.gf('django.db.models.fields.CharField')(max_length=200)),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('key', self.gf('django.db.models.fields.CharField')(max_length=32)),
))
db.send_create_signal('store', ['Setting'])
models = {
}
complete_apps = ['store']
\ No newline at end of file
from django.db import models
from modeldict import ModelDict
class Setting(models.Model):
key = models.CharField(max_length=32)
value = models.CharField(max_length=200)
settings = ModelDict(Setting, key='key', value='value', instances=False)
pass
// using jQuery
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function postKey(key) {
$.post("/store/gui/", { "KEY" : key },
function (respond) {
alert(respond);
}
)
.error(function (respond) { alert(JSON.stringify(respond)); });
}
function resetKey() {
$.post("/store/gui/", "",
function (respond) {
alert(respond);
}
);
}
$.ajaxSetup({
crossDomain: false, // obviates need for sameOrigin test
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
<!DOCTYPE html>
<html>
<head>
<title>Store Gui</title>
<script src="/static/jquery.min.js"></script>
<script type="text/javascript" src="/static/store/gui.js"></script>
</head>
<body>
EZ LESZ A GUI JOL!
<form action="login:{{ username }}:{{ host }}">
<input type=submit name="login_button" id="login_button" value="login"/>
</form>
<form action="mount:true">
<input type=submit name="mount_button" id="mount_button" value="mount" hidden="true"/>
</form>
<form action="umount:true">
<input type=submit name="umount_button" id="umount_button" value="umount" hidden="true"/>
</form>
<form action="logout:{{ username }}:{{ host }}">
<input type=submit name="logout_button" id="logout_button" value="logout" hidden="true"/>
</form>
</body>
</html>
......@@ -8,7 +8,11 @@
<input type="hidden" name="auth" value="True">
</form>
</td>
<td></td>
<td>
{% for k,v in quota.items %}
{{ k }} : {{ v }}
{% endfor %}
</td>
<td></td>
<td>
<form action="/store/" method="POST"
......
# Create your views here.
from django.core.context_processors import csrf
from django.http import HttpResponse
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from store.api import StoreApi
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.views.decorators.csrf import csrf_exempt
import os
import json
import base64
@login_required
def index(request):
user = request.user.username
def estabilish_store_user(user):
try:
details = request.user.userclouddetails_set.all()[0]
password = details.smb_password
......@@ -17,14 +19,27 @@ def index(request):
for key in request.user.sshkey_set.all():
key_list.append(key.key)
except:
return HttpResponse('Can not acces to django database!')
if StoreApi.userexist(user) != True:
return HttpResponse('Can not acces to django database!', status_code=404)
#Create user
if not StoreApi.createuser(user,password,key_list):
return HttpResponse('User does not exist on store! And could not create!')
@login_required
def index(request):
user = request.user.username
if StoreApi.userexist(user) != True:
estabilish_store_user(user)
#UpdateAuthorizationInfo
try:
auth=request.POST['auth']
try:
details = request.user.userclouddetails_set.all()[0]
password = details.smb_password
key_list = []
for key in request.user.sshkey_set.all():
key_list.append(key.key)
except:
return HttpResponse('Can not acces to django database!', status_code=404)
if not StoreApi.updateauthorizationinfo(user,password,key_list):
return HttpResponse('Can not update authorization information!')
except:
......@@ -64,7 +79,66 @@ def index(request):
#Normalize path (Need double dirname /folder/ -> /folder -> /
backpath = os.path.normpath(os.path.dirname(os.path.dirname(path)))
file_list = StoreApi.listfolder(user,path)
return render_to_response('store/list.html', RequestContext(request, {'file_list': file_list, 'path' : path, 'backpath' : backpath, 'username' : user}))
quota = StoreApi.requestquota(user)
return render_to_response('store/list.html', RequestContext(request, {'file_list': file_list, 'path' : path, 'backpath' : backpath, 'username' : user, 'quota' : quota}))
@login_required
def ajax_listfolder(request):
user = request.user.username
if StoreApi.userexist(user) != True:
estabilish_store_user(user)
path = '/'
try:
path = request.POST['path']
except:
pass
#Normalize path (Need double dirname /folder/ -> /folder -> /
backpath = os.path.normpath(os.path.dirname(os.path.dirname(path)))
file_list = StoreApi.listfolder(user,path)
return HttpResponse(json.dumps(file_list))
@login_required
def ajax_download(request):
user = request.user.username
try:
dl = request.POST['dl']
return HttpResponse(json.dumps({'url':StoreApi.requestdownload(user,dl)}))
except:
pass
return HttpResponse('File not found!', status_code=404)
@login_required
def ajax_upload(request):
user = request.user.username
try:
ul = request.POST['ul']
url = StoreApi.requestupload(user,ul)
return HttpResponse(json.dumps({'url':url}))
except:
pass
return HttpResponse('Error!', status_code=404)
@login_required
def ajax_delete(request):
user = request.user.username
try:
rm = request.POST['rm']
return HttpResponse(json.dumps({'success':StoreApi.requestremove(user,rm)}))
except:
pass
return HttpResponse('File not found!', status_code=404)
@login_required
def ajax_new_folder(request):
user = request.user.username
try:
path = request.POST['path']
new = request.POST['new']
success = StoreApi.requestnewfolder(user,path+'/'+new)
return HttpResponse(json.dumps({'success':success}))
except:
pass
return HttpResponse('Error!', status_code=404)
@login_required
def toplist(request):
......@@ -73,6 +147,32 @@ def toplist(request):
file_list = StoreApi.toplist(user)
return render_to_response('store/list.html', RequestContext(request, {'file_list': file_list, 'path' : path, 'backpath' : backpath, 'username' : user}))
@login_required
def gui(request):
user = request.user.username
if request.method == 'GET':
return render_to_response('store/gui.html', RequestContext(request, {'username' : user, 'host' : StoreApi.get_host()}))
elif request.method == 'POST':
try:
details = request.user.userclouddetails_set.all()[0]
password = details.smb_password
key_list = []
for key in request.user.sshkey_set.all():
key_list.append(key.key)
except:
return HttpResponse('Can not acces to django database!', status_code=404)
try:
lab_key_decoded = base64.b64decode(request.POST['KEY'])
key_list.append(lab_key_decoded)
except:
pass
if not StoreApi.updateauthorizationinfo(user, password, key_list):
return HttpResponse('Can not update authorization information!')
else:
return HttpResponse('Updated key information!')
else:
return HttpResponse('Method not found!', status_code=404)
def logout(request):
auth.logout(request)
return redirect('/')
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