Commit 58f6b8dc authored by Jérome Perrin's avatar Jérome Perrin

AlarmTool: handle automatic solve with alarms owned by system user

Business templates are installed by system user, which is a special
user not returned by getWrappedOwner. Because of this, the "fixing
problems or activating a disabled alarm is not allowed" error was
raised when checking if the owner of the alarm has manage portal
permission on the alarm.

This switches the implementation to explicit creation of the user
when user id is the system user, so that we have a user with the
permission to solve the alarm.
parent 69a8acfe
Pipeline #21767 failed with stage
in 0 seconds
...@@ -26,30 +26,17 @@ ...@@ -26,30 +26,17 @@
# #
############################################################################## ##############################################################################
import unittest
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import DummyMailHost from Products.ERP5Type.tests.utils import DummyMailHost
from Products.ERP5Type.UnrestrictedMethod import super_user
from AccessControl.SecurityManagement import newSecurityManager, \ from AccessControl.SecurityManagement import newSecurityManager, \
getSecurityManager, setSecurityManager getSecurityManager, setSecurityManager
from AccessControl.User import nobody
from AccessControl import Unauthorized from AccessControl import Unauthorized
from DateTime import DateTime from DateTime import DateTime
from erp5.component.module.DateUtils import addToDate from erp5.component.module.DateUtils import addToDate
class TestAlarm(ERP5TypeTestCase): class TestAlarm(ERP5TypeTestCase):
"""
This is the list of test
test setNextStartDate :
- every hour
- at 6, 10, 15, 21 every day
- every day at 10
- every 3 days at 14 and 15 and 17
- every monday and friday, at 6 and 15
- every 1st and 15th every month, at 12 and 14
- every 1st day of every 2 month, at 6
"""
# year/month/day hour:minute:second # year/month/day hour:minute:second
date_format = '%i/%i/%i %i:%i:%d GMT+0100' date_format = '%i/%i/%i %i:%i:%d GMT+0100'
...@@ -72,10 +59,17 @@ class TestAlarm(ERP5TypeTestCase): ...@@ -72,10 +59,17 @@ class TestAlarm(ERP5TypeTestCase):
def newAlarm(self, **kw): def newAlarm(self, **kw):
""" """
Create an empty alarm Create an empty alarm, owned by system user, like when the alarm is
installed from a business template.
""" """
a_tool = self.getAlarmTool() sm = getSecurityManager()
return a_tool.newContent(**kw) newSecurityManager(None, nobody)
try:
with super_user():
return self.getAlarmTool().newContent(**kw)
finally:
setSecurityManager(sm)
def test_01_HasEverything(self): def test_01_HasEverything(self):
# Test if portal_alarms was created # Test if portal_alarms was created
...@@ -608,9 +602,3 @@ class TestAlarm(ERP5TypeTestCase): ...@@ -608,9 +602,3 @@ class TestAlarm(ERP5TypeTestCase):
self.tic() self.tic()
alarm_list = alarm.Alarm_zGetAlarmDate(uid=alarm.getUid()) alarm_list = alarm.Alarm_zGetAlarmDate(uid=alarm.getUid())
self.assertEqual(date.toZone('UTC'), alarm_list[0].alarm_date) self.assertEqual(date.toZone('UTC'), alarm_list[0].alarm_date)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAlarm))
return suite
...@@ -112,7 +112,7 @@ class Alarm(XMLObject, PeriodicityMixin): ...@@ -112,7 +112,7 @@ class Alarm(XMLObject, PeriodicityMixin):
if (fixit or not self.getEnabled()) and not self.getPortalObject().portal_membership.checkPermission(Permissions.ManagePortal, self): if (fixit or not self.getEnabled()) and not self.getPortalObject().portal_membership.checkPermission(Permissions.ManagePortal, self):
raise Unauthorized('fixing problems or activating a disabled alarm is not allowed') raise Unauthorized('fixing problems or activating a disabled alarm is not allowed')
# Use UnrestrictedMethod, so that the behaviour would not # Use UnrestrictedMethod, so that the behavior would not
# change even if this method is invoked by random users. # change even if this method is invoked by random users.
@UnrestrictedMethod @UnrestrictedMethod
def _activeSense(): def _activeSense():
...@@ -150,7 +150,7 @@ class Alarm(XMLObject, PeriodicityMixin): ...@@ -150,7 +150,7 @@ class Alarm(XMLObject, PeriodicityMixin):
# administrator attention should already be attracted to the issue. # administrator attention should already be attracted to the issue.
# - and overall, alarm concurrency should be low enough that # - and overall, alarm concurrency should be low enough that
# collision should stay extremely low: it should be extremely rare # collision should stay extremely low: it should be extremely rare
# for a notification-neabled alarm to run even 10 times in parallel # for a notification-enabled alarm to run even 10 times in parallel
# (as alarms can at most be spawned every minute), and even in such # (as alarms can at most be spawned every minute), and even in such
# case the probability of a collision is about 2e-9 (10 / 2**32). # case the probability of a collision is about 2e-9 (10 / 2**32).
# Assuming 10 alarms spawned every second with a one-second duration # Assuming 10 alarms spawned every second with a one-second duration
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
import time import time
import threading import threading
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo, SpecialUsers
from AccessControl.SecurityManagement import getSecurityManager, \ from AccessControl.SecurityManagement import getSecurityManager, \
newSecurityManager, setSecurityManager newSecurityManager, setSecurityManager
from Products.CMFActivity.ActivityTool import getCurrentNode from Products.CMFActivity.ActivityTool import getCurrentNode
...@@ -50,7 +50,7 @@ class AlarmTool(TimerServiceMixin, BaseTool): ...@@ -50,7 +50,7 @@ class AlarmTool(TimerServiceMixin, BaseTool):
""" """
This tool manages alarms. This tool manages alarms.
It is used as a central managment point for all alarms. It is used as a central management point for all alarms.
Inside this tool we have a way to retrieve all reports coming Inside this tool we have a way to retrieve all reports coming
from Alarms,... from Alarms,...
...@@ -133,10 +133,19 @@ class AlarmTool(TimerServiceMixin, BaseTool): ...@@ -133,10 +133,19 @@ class AlarmTool(TimerServiceMixin, BaseTool):
if so then we will activate them. if so then we will activate them.
""" """
security_manager = getSecurityManager() security_manager = getSecurityManager()
system_user = None
try: try:
for alarm in self.getAlarmList(to_active=1): for alarm in self.getAlarmList(to_active=1):
if alarm is not None: if alarm is not None:
user = alarm.getWrappedOwner() udb, owner_user_id = alarm.getOwnerTuple()
if owner_user_id == SpecialUsers.system.getUserName():
if system_user is None:
# build this wrapped system user only once per tic
system_user = SpecialUsers.system.__of__(
self.getPhysicalRoot().unrestrictedTraverse(udb, None))
user = system_user
else:
user = alarm.getWrappedOwner()
newSecurityManager(self.REQUEST, user) newSecurityManager(self.REQUEST, user)
if alarm.isActive() or not alarm.isEnabled(): if alarm.isActive() or not alarm.isEnabled():
# do nothing if already active, or not enabled # do nothing if already active, or not enabled
......
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 to comment