Skip to content

Commit

Permalink
Partial permissions code refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
dcramer committed Sep 4, 2012
1 parent ba5178c commit 65b6df9
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 172 deletions.
9 changes: 9 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
Version 5.0.0
-------------

- Variable versions of Django are no longer supported. Django 1.4.x must now be used.
- Public projects are restricted to viewing without being authenticated.
- The default behavior of Sentry is to now use timezone-aware datetimes everywhere.
- Permissions have been refactored to be more precise.


Version 4.10.0
--------------

Expand Down
26 changes: 26 additions & 0 deletions src/sentry/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
"""
sentry.constants
~~~~~~~~~~~~~~~~
These settings act as the default (base) settings for the Sentry-provided web-server
:copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""

from django.utils.datastructures import SortedDict
from django.utils.translation import ugettext_lazy as _

Expand Down Expand Up @@ -34,3 +44,19 @@
('date', _('Last Seen')),
('new', _('First Seen')),
))

STATUS_UNRESOLVED = 0
STATUS_RESOLVED = 1
STATUS_LEVELS = (
(STATUS_UNRESOLVED, _('unresolved')),
(STATUS_RESOLVED, _('resolved')),
)

MEMBER_OWNER = 0
MEMBER_USER = 50
MEMBER_SYSTEM = 100
MEMBER_TYPES = (
(0, _('owner')),
(50, _('user')),
(100, _('system agent')),
)
2 changes: 0 additions & 2 deletions src/sentry/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,6 @@ def from_kwargs(self, project, **kwargs):
elif timezone.is_aware(date):
date = date.replace(tzinfo=None)

print date

data = kwargs

kwargs = {
Expand Down
50 changes: 11 additions & 39 deletions src/sentry/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
from hashlib import md5
from indexer.models import BaseIndex
from picklefield.fields import PickledObjectField
from south.modelsinspector import add_introspection_rules

from django.contrib.auth.models import User
from django.contrib.auth.signals import user_logged_in
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import F
Expand All @@ -31,6 +33,8 @@
from django.utils.translation import ugettext_lazy as _

from sentry.conf import settings
from sentry.constants import STATUS_LEVELS, STATUS_RESOLVED, STATUS_UNRESOLVED, \
MEMBER_TYPES, MEMBER_OWNER, MEMBER_USER, MEMBER_SYSTEM # NOQA
from sentry.manager import GroupManager, ProjectManager, \
MetaManager, InstanceMetaManager, SearchDocumentManager, BaseManager, \
UserOptionManager, FilterKeyManager
Expand All @@ -41,29 +45,6 @@

__all__ = ('Event', 'Group', 'Project', 'SearchDocument')

STATUS_UNRESOLVED = 0
STATUS_RESOLVED = 1
STATUS_LEVELS = (
(STATUS_UNRESOLVED, _('unresolved')),
(STATUS_RESOLVED, _('resolved')),
)

# These are predefined builtin's
FILTER_KEYS = (
('server_name', _('server name')),
('logger', _('logger')),
('site', _('site')),
)

MEMBER_OWNER = 0
MEMBER_USER = 50
MEMBER_SYSTEM = 100
MEMBER_TYPES = (
(0, _('owner')),
(50, _('user')),
(100, _('system agent')),
)


class Option(Model):
"""
Expand Down Expand Up @@ -588,7 +569,7 @@ class FilterKey(Model):
Stores references to available filters keys.
"""
project = models.ForeignKey(Project)
key = models.CharField(choices=FILTER_KEYS, max_length=32)
key = models.CharField(max_length=32)

objects = FilterKeyManager()

Expand All @@ -604,7 +585,7 @@ class FilterValue(Model):
Stores references to available filters.
"""
project = models.ForeignKey(Project, null=True)
key = models.CharField(choices=FILTER_KEYS, max_length=32)
key = models.CharField(max_length=32)
value = models.CharField(max_length=200)

objects = BaseManager()
Expand All @@ -624,7 +605,7 @@ class MessageFilterValue(Model):
project = models.ForeignKey(Project, null=True)
group = models.ForeignKey(Group)
times_seen = models.PositiveIntegerField(default=0)
key = models.CharField(choices=FILTER_KEYS, max_length=32)
key = models.CharField(max_length=32)
value = models.CharField(max_length=200)
last_seen = models.DateTimeField(default=timezone.now, db_index=True, null=True)
first_seen = models.DateTimeField(default=timezone.now, db_index=True, null=True)
Expand Down Expand Up @@ -847,6 +828,7 @@ def remove_key_for_team_member(instance, **kwargs):
user=instance.user,
).delete()


# Set user language if set
def set_language_on_logon(request, user, **kwargs):
language = UserOption.objects.get_value(
Expand Down Expand Up @@ -894,16 +876,6 @@ def set_language_on_logon(request, user, **kwargs):
dispatch_uid="remove_key_for_team_member",
weak=False,
)
# Only available in Django >= 1.3
try:
from django.contrib.auth.signals import user_logged_in
user_logged_in.connect(set_language_on_logon)
except:
pass

try:
import south
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^social_auth\.fields\.JSONField"])
except:
pass
user_logged_in.connect(set_language_on_logon)

add_introspection_rules([], ["^social_auth\.fields\.JSONField"])
119 changes: 98 additions & 21 deletions src/sentry/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,88 +5,165 @@
:copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from functools import wraps
from sentry.conf import settings
from sentry.constants import MEMBER_OWNER
from sentry.plugins import plugins


def perm_override(perm):
def inner(func):
@wraps(func)
def wrapped(user, *args, **kwargs):
# permissions always take precedence
if user.has_perm('sentry.%s' % (perm,)):
return True

return func(user, *args, **kwargs)
return wrapped
return inner


def requires_login(func):
@wraps(func)
def wrapped(user, *args, **kwargs):
if not (user and user.is_authenticated()):
return False

return func(user, *args, **kwargs)
return wrapped


@requires_login
@perm_override('can_add_project')
def can_create_projects(user, team=None):
"""
Returns a boolean describing whether a user has the ability to
create new projects.
"""
if not (user and user.is_authenticated()):
# must be an owner of team
if team and not team.member_set.filter(user=user, type=MEMBER_OWNER).exists():
return False

if user.has_perm('sentry.can_add_project'):
return True

result = plugins.first('has_perm', user, 'add_project', team)
if result is None:
result = settings.ALLOW_PROJECT_CREATION

if result is False:
return result

return True


@requires_login
@perm_override('can_add_team')
def can_create_teams(user):
"""
Returns a boolean describing whether a user has the ability to
create new projects.
"""
if not (user and user.is_authenticated()):
return False

if user.has_perm('sentry.can_add_team'):
return True

result = plugins.first('has_perm', user, 'add_team')
if result is None:
result = settings.ALLOW_TEAM_CREATION

if result is False:
return result

return True


@requires_login
@perm_override('can_change_project')
def can_set_public_projects(user):
"""
Returns a boolean describing whether a user has the ability to
change the ``public`` attribute of projects.
"""
if not (user and user.is_authenticated()):
return False

if user.has_perm('sentry.can_change_project'):
return True

result = plugins.first('has_perm', user, 'set_project_public')
if result is None:
result = settings.ALLOW_PUBLIC_PROJECTS

if result is False:
return result

return True


@requires_login
@perm_override('can_add_teammember')
def can_add_team_member(user, team):
# must be an owner of the team
if not team.member_set.filter(user=user, type=MEMBER_OWNER).exists():
return False

result = plugins.first('has_perm', user, 'add_team_member', team)
if result is False and not user.has_perm('sentry.can_add_teammember'):
if result is False:
return False

return True


@requires_login
def can_manage_team_member(user, member, django_perm, perm):
# permissions always take precedence
if user.has_perm(django_perm):
return True

# must be an owner of the team
if not member.team.member_set.filter(user=user, type=MEMBER_OWNER).exists():
return False

result = plugins.first('has_perm', user, perm, member)
if result is False:
return False

return True


def can_edit_team_member(user, member):
return can_manage_team_member(user, member, 'sentry.can_change_teammember', 'edit_team_member')


def can_remove_team_member(user, member):
return can_manage_team_member(user, member, 'sentry.can_remove_teammember', 'remove_team_member')


@requires_login
def can_remove_team(user, team):
# projects with teams can never be removed
if team.project_set.exists():
return False

# permissions always take precedence
if user.has_perm('sentry.can_remove_team'):
return True

# must be an owner of the team
if not team.member_set.filter(user=user, type=MEMBER_OWNER).exists():
return False

result = plugins.first('has_perm', user, 'remove_team', team)
if result is False and not user.has_perm('sentry.can_remove_team'):
if result is False:
return False

return True


def can_remove_project(user, team):
result = plugins.first('has_perm', user, 'remove_project', team)
if result is False and not user.has_perm('sentry.can_remove_project'):
@requires_login
def can_remove_project(user, project):
if project.is_default_project():
return False

# permissions always take precedence
if user.has_perm('sentry.can_remove_project'):
return True

# must be an owner of the team
if not project.team.member_set.filter(user=user, type=MEMBER_OWNER).exists():
return False

result = plugins.first('has_perm', user, 'remove_project', project)
if result is True:
return True

return True
Loading

0 comments on commit 65b6df9

Please sign in to comment.