Commit 8f212d3c by Guba Sándor

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

parents 3232dcc5 e51fd4a8
......@@ -25,6 +25,12 @@ urlpatterns = patterns('',
url(r'^reload/$', 'firewall.views.reload_firewall', name='reload_firewall'),
url(r'^fwapi/$', 'firewall.views.firewall_api', name='firewall_api'),
url(r'^store/$', 'store.views.index', name='store_index'),
url(r'^store/gui/$', 'store.views.gui', name='store_gui'),
url(r'^store/top/$', 'store.views.toplist', name='store_top'),
url(r'^ajax/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'),
)
......@@ -360,16 +360,16 @@ def dns():
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
hostname = i_host.get_fqdn()
# ipv4
if i_host.ipv4:
# A record
DNS.append("+%s:%s:%s" % (hostname, ipv4, models.settings['dns_ttl']))
# PTR record 4.3.2.1.in-addr.arpa
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(i_host.ipv4), reverse, models.settings['dns_ttl']))
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(ipv4), reverse, models.settings['dns_ttl']))
# PTR record 4.dns1.3.2.1.in-addr.arpa
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(i_host.ipv4, cname=True), reverse, models.settings['dns_ttl']))
DNS.append("^%s:%s:%s" % (ipv4_to_arpa(ipv4, cname=True), reverse, models.settings['dns_ttl']))
# ipv6
if i_host.ipv6:
......
......@@ -120,6 +120,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 +185,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)
......
......@@ -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
......@@ -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
......@@ -37,15 +37,15 @@ except:
def force_ssl(original_function):
def new_function(*args, **kwargs):
ssl = request.environ.get('SSL_CLIENT_VERIFY', 'NONE')
if ssl != "SUCCESS":
abort(403, "Forbidden requests. This site need SSL verification! SSL status: "+ssl)
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)
if FORCE_SSL:
return new_function
else:
return original_function(*args, **kwargs)
return new_function
@route('/')
@force_ssl
......
......@@ -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:
......
......@@ -7,7 +7,7 @@ from django.db import transaction
from django.db.models.signals import post_save
from django import forms
from django.utils.translation import ugettext_lazy as _
from firewall.models import Host, Rule, Vlan
from firewall.models import Host, Rule, Vlan, settings
from firewall.tasks import reload_firewall_lock
from one.util import keygen
from school.models import Person
......
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 %}
......
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 -- default") % 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)
......@@ -16,6 +16,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 +129,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)
......
// 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