Commit 2e952ddb by Szeberényi Imre

Initial version, Python 2.7

parents
# Python bytecode:
*.py[co]
# Packaging files:
*.egg*
# Editor temp files:
*.swp
*.swo
*~
.vscode
.idea
# Sphinx docs:
build
_build
# SQLite3 database files:
*.db
# Logs:
*.log
.ropeproject
celerybeat-schedule
.coverage
*,cover
coverage.xml
.noseids
# Gettext object file:
*.mo
# saml
circle/attribute-maps
circle/remote_metadata.xml
circle/*.key
circle/*.pem
# collected static files:
circle/static_collected
circle/bower_components
# jsi18n files
jsi18n
scripts.rc
# less
*.css
Adam Dudas
Bence Danyi
Daniel Bach
Gergo Nagy
Imre Szeberenyi
Mate Ory
Sandor Guba
Viktor Kalman
This diff is collapsed. Click to expand it.
Copyright (c) 2012--2013 Budapest University of Technology
and Economics (BME-IK), and contributors.
[SOME OPEN SOURCE LICENSE HERE]
============
circle-cloud
============
This is the Django based controller and web portal of the CIRCLE Cloud.
License
=======
Copyright 2014 Budapest University of Technology and Economics (BME IK_).
CIRCLE is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
Foobar. If not, see <http://www.gnu.org/licenses/>.
.. _IK: http://ik.bme.hu/
"""
Creates Levels for all installed apps that have levels.
"""
from django.db.models import signals
from django.apps import apps
from django.db import DEFAULT_DB_ALIAS
from django.core.exceptions import ImproperlyConfigured
from ..models import Level, AclBase
def create_levels(app_config, verbosity=False, using=DEFAULT_DB_ALIAS,
**kwargs):
"""Create and set the weights of the configured Levels.
Based on django.contrib.auth.management.__init__.create_permissions"""
# if not router.allow_migrate(using, auth_app.Permission):
# return
from django.contrib.contenttypes.models import ContentType
app_models = [k for k in apps.get_models(app_config)
if AclBase in k.__bases__]
print "Creating levels for models: %s." % ", ".join(
[m.__name__ for m in app_models])
# This will hold the levels we're looking for as
# (content_type, (codename, name))
searched_levels = list()
level_weights = list()
# The codenames and ctypes that should exist.
ctypes = set()
for klass in app_models:
# Force looking up the content types in the current database
# before creating foreign keys to them.
ctype1 = ContentType.objects.db_manager(using).get_for_model(klass)
ctypes.add(ctype1)
weight = 0
try:
for codename, name in klass.ACL_LEVELS:
searched_levels.append((ctype1, (codename, name)))
level_weights.append((ctype1, codename, weight))
weight += 1
except AttributeError:
raise ImproperlyConfigured(
"Class %s doesn't have ACL_LEVELS attribute." % klass)
# Find all the Levels that have a content_type for a model we're
# looking for. We don't need to check for codenames since we already have
# a list of the ones we're going to create.
all_levels = set(Level.objects.using(using).filter(
content_type__in=ctypes,
).values_list(
"content_type", "codename"
))
levels = [
Level(codename=codename, name=name, content_type=ctype)
for ctype, (codename, name) in searched_levels
if (ctype.pk, codename) not in all_levels
]
Level.objects.using(using).bulk_create(levels)
if verbosity >= 2:
print("Adding levels [%s]." % ", ".join(unicode(l) for l in levels))
print("Searched: [%s]." % ", ".join(
unicode(l) for l in searched_levels))
print("All: [%s]." % ", ".join(unicode(l) for l in all_levels))
# set weights
for ctype, codename, weight in level_weights:
Level.objects.filter(codename=codename,
content_type=ctype).update(weight=weight)
signals.post_migrate.connect(
create_levels, dispatch_uid="circle.acl.management.create_levels")
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django.core.management.base import BaseCommand
from .. import create_levels
class Command(BaseCommand):
args = ''
help = 'Regenerates Levels'
def handle(self, *args, **options):
create_levels(None, None, 3)
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('auth', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('contenttypes', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Level',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=50, verbose_name=b'name')),
('codename', models.CharField(max_length=100, verbose_name=b'codename')),
('weight', models.IntegerField(null=True, verbose_name=b'weight')),
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
],
options={
},
bases=(models.Model,),
),
migrations.CreateModel(
name='ObjectLevel',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('object_id', models.IntegerField()),
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
('groups', models.ManyToManyField(to='auth.Group')),
('level', models.ForeignKey(to='acl.Level')),
('users', models.ManyToManyField(to=settings.AUTH_USER_MODEL)),
],
options={
},
bases=(models.Model,),
),
migrations.AlterUniqueTogether(
name='objectlevel',
unique_together=set([('content_type', 'object_id', 'level')]),
),
migrations.AlterUniqueTogether(
name='level',
unique_together=set([('content_type', 'codename')]),
),
]
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
import logging
from django.contrib.auth.models import User, Group
from django.contrib.contenttypes.fields import (
GenericForeignKey, GenericRelation
)
from django.contrib.contenttypes.models import ContentType
from django.db.models import (
ManyToManyField, ForeignKey, CharField, Model, IntegerField, Q
)
logger = logging.getLogger(__name__)
class Level(Model):
"""Definition of a permission level.
Instances are automatically populated based on AclBase."""
name = CharField('name', max_length=50)
content_type = ForeignKey(ContentType)
codename = CharField('codename', max_length=100)
weight = IntegerField('weight', null=True)
def __unicode__(self):
return "<%s/%s>" % (unicode(self.content_type), self.name)
class Meta:
app_label = 'acl'
unique_together = (('content_type', 'codename'),
# ('content_type', 'weight'),
# TODO find a way of temp. disabling this constr.
)
class ObjectLevel(Model):
"""Permission level for a specific object."""
level = ForeignKey(Level)
content_type = ForeignKey(ContentType)
object_id = IntegerField()
content_object = GenericForeignKey()
users = ManyToManyField(User)
groups = ManyToManyField(Group)
def __unicode__(self):
return "<%s: %s>" % (unicode(self.content_object), unicode(self.level))
class Meta:
app_label = 'acl'
unique_together = (('content_type', 'object_id', 'level'),)
class AclBase(Model):
"""Define permission levels for Users/Groups per object."""
object_level_set = GenericRelation(ObjectLevel)
def clone_acl(self, other):
"""Clone full ACL from other object."""
assert self.id != other.id or type(self) != type(other)
self.object_level_set.clear()
for i in other.object_level_set.all():
ol = self.object_level_set.create(level=i.level)
for j in i.users.all():
ol.users.add(j)
for j in i.groups.all():
ol.groups.add(j)
@classmethod
def get_level_object(cls, level):
"""Get Level object for this model by codename."""
ct = ContentType.objects.get_for_model(cls)
return Level.objects.get(codename=level, content_type=ct)
def set_level(self, whom, level):
"""Set level of object for a user or group.
:param whom: user or group the level is set for
:type whom: User or Group
:param level: codename of level to set, or None
:type level: Level or str or unicode or NoneType
"""
if isinstance(whom, User):
self.set_user_level(whom, level)
elif isinstance(whom, Group):
self.set_group_level(whom, level)
else:
raise AttributeError('"whom" must be a User or Group object.')
def set_user_level(self, user, level):
"""Set level of object for a user.
:param whom: user the level is set for
:type whom: User
:param level: codename of level to set, or None
:type level: Level or str or unicode or NoneType
"""
logger.info('%s.set_user_level(%s, %s) called',
*[unicode(p) for p in [self, user, level]])
if level is None:
pk = None
else:
if isinstance(level, basestring):
level = self.get_level_object(level)
if not self.object_level_set.filter(level_id=level.pk).exists():
self.object_level_set.create(level=level)
pk = level.pk
for i in self.object_level_set.all():
if i.level_id != pk:
i.users.remove(user)
else:
i.users.add(user)
i.save()
def set_group_level(self, group, level):
"""Set level of object for a user.
:param whom: user the level is set for
:type whom: User or unicode or str
:param level: codename of level to set
:type level: str or unicode
"""
logger.info('%s.set_group_level(%s, %s) called',
*[unicode(p) for p in [self, group, level]])
if level is None:
pk = None
else:
if isinstance(level, basestring):
level = self.get_level_object(level)
if not self.object_level_set.filter(level_id=level.pk).exists():
self.object_level_set.create(level=level)
pk = level.pk
for i in self.object_level_set.all():
if i.level_id != pk:
i.groups.remove(group)
else:
i.groups.add(group)
i.save()
def has_level(self, user, level, group_also=True):
logger.debug('%s.has_level(%s, %s, %s) called',
*[unicode(p) for p in [self, user, level, group_also]])
if user is None or not user.is_authenticated():
return False
if getattr(user, 'is_superuser', False):
logger.debug('- superuser granted')
return True
if isinstance(level, basestring):
level = self.get_level_object(level)
logger.debug("- level set by str: %s", unicode(level))
object_levels = self.object_level_set.filter(
level__weight__gte=level.weight).all()
groups = user.groups.values_list('id', flat=True) if group_also else []
for i in object_levels:
if i.users.filter(pk=user.pk).exists():
return True
if group_also and i.groups.filter(pk__in=groups).exists():
return True
return False
def get_users_with_level(self, **kwargs):
logger.debug('%s.get_users_with_level() called', unicode(self))
object_levels = (self.object_level_set.filter(**kwargs).select_related(
'level').prefetch_related('users').all())
users = []
for object_level in object_levels:
name = object_level.level.codename
olusers = object_level.users.all()
users.extend([(u, name) for u in olusers])
logger.debug('- %s: %s' % (name, [u.username for u in olusers]))
return users
def get_groups_with_level(self):
logger.debug('%s.get_groups_with_level() called', unicode(self))
object_levels = (self.object_level_set.select_related(
'level').prefetch_related('groups').all())
groups = []
for object_level in object_levels:
name = object_level.level.codename
olgroups = object_level.groups.all()
groups.extend([(g, name) for g in olgroups])
logger.debug('- %s: %s' % (name, [g.name for g in olgroups]))
return groups
@classmethod
def get_objects_with_level(cls, level, user,
group_also=True, owner_also=False,
disregard_superuser=False):
logger.debug('%s.get_objects_with_level(%s,%s) called',
unicode(cls), unicode(level), unicode(user))
if user is None or not user.is_authenticated():
return cls.objects.none()
if getattr(user, 'is_superuser', False) and not disregard_superuser:
logger.debug('- superuser granted')
return cls.objects.all()
if isinstance(level, basestring):
level = cls.get_level_object(level)
logger.debug("- level set by str: %s", unicode(level))
ct = ContentType.objects.get_for_model(cls)
levelfilter = Q(users=user)
if group_also:
levelfilter |= Q(groups__in=user.groups.all())
ols = ObjectLevel.objects.filter(
levelfilter,
content_type=ct, level__weight__gte=level.weight).distinct()
clsfilter = Q(object_level_set__in=ols.all())
if owner_also:
clsfilter |= Q(owner=user)
return cls.objects.filter(clsfilter).distinct()
@classmethod
def get_objects_with_group_level(cls, level, group):
if isinstance(level, basestring):
level = cls.get_level_object(level)
ct = ContentType.objects.get_for_model(cls)
levelfilter = Q(groups=group)
ols = ObjectLevel.objects.filter(
levelfilter,
content_type=ct, level__weight__gte=level.weight).distinct()
clsfilter = Q(object_level_set__in=ols.all())
return cls.objects.filter(clsfilter).distinct()
def save(self, *args, **kwargs):
super(AclBase, self).save(*args, **kwargs)
if 'owner' in dict(self.ACL_LEVELS) and (hasattr(self, 'owner') and
self.owner):
self.set_user_level(self.owner, 'owner')
class Meta:
abstract = True
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django.conf import settings
# https://code.djangoproject.com/ticket/7835
if settings.SETTINGS_MODULE == 'circle.settings.test':
from .test_acl import TestModel, Test2Model # noqa
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
# Create your views here.
{
"name": "circle",
"version": "0.0.0",
"license": "GPL",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "~3.2.0",
"fontawesome": "~4.3.0",
"jquery": "~2.1.1",
"no-vnc": "0.5.1",
"jquery-knob": "~1.2.9",
"jquery-simple-slider": "https://github.com/BME-IK/jquery-simple-slider.git",
"bootbox": "~4.3.0",
"intro.js": "0.9.0",
"favico.js": "~0.3.5",
"datatables": "~1.10.4",
"chart.js": "2.3.0",
"clipboard": "~1.6.1"
}
}
# register a signal do update permissions every migration.
# This is based on app django_extensions update_permissions command
from django.db.models.signals import post_migrate
def update_permissions_after_migration(sender, **kwargs):
"""
Update app permission just after every migration.
This is based on app django_extensions update_permissions
management command.
"""
from django.conf import settings
from django.apps import apps
from django.contrib.auth.management import create_permissions
create_permissions(sender, apps.get_models(), 2 if settings.DEBUG else 0)
post_migrate.connect(update_permissions_after_migration)
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more