Beispiel #1
0
class WhoV2AuthenticationPolicy(object):
    implements(IAuthenticationPolicy)

    def __init__(self, config_file, identifier_id, callback=_null_callback):
        config_file = self._config_file = os.path.abspath(
            os.path.normpath(
                os.path.expandvars(os.path.expanduser(config_file))))
        conf_dir, _ = os.path.split(config_file)
        global_conf = {'here': conf_dir}
        self._api_factory = APIFactory(global_conf, config_file)
        self._identifier_id = identifier_id
        self._callback = callback

    def unauthenticated_userid(self, request):
        return self._get_identity(request)

    def authenticated_userid(self, request):
        """ See IAuthenticationPolicy.
        """
        identity = self._get_identity(request)

        if identity is not None:
            groups = self._callback(identity, request)
            if groups is not None:
                return identity['repoze.who.userid']

    def effective_principals(self, request):
        """ See IAuthenticationPolicy.
        """
        identity = self._get_identity(request)
        groups = self._get_groups(identity, request)
        if len(groups) > 1:
            groups.insert(0, identity['repoze.who.userid'])
        return groups

    def remember(self, request, principal, **kw):
        """ See IAuthenticationPolicy.
        """
        api = self._getAPI(request)
        identity = {
            'repoze.who.userid': principal,
            'identifier': self._identifier_id,
        }
        return api.remember(identity)

    def forget(self, request):
        """ See IAuthenticationPolicy.
        """
        api = self._getAPI(request)
        identity = self._get_identity(request)
        return api.forget(identity)

    def _getAPI(self, request):
        return self._api_factory(request.environ)

    def _get_identity(self, request):
        identity = request.environ.get('repoze.who.identity')
        if identity is None:
            api = self._getAPI(request)
            identity = api.authenticate()
        return identity

    def _get_groups(self, identity, request):
        if identity is not None:
            dynamic = self._callback(identity, request)
            if dynamic is not None:
                groups = list(dynamic)
                groups.append(Authenticated)
                groups.append(Everyone)
                return groups
        return [Everyone]
class SauropodAuthenticationPolicy(object):
    """Custom authentication policy for Sauropod.

    This policy identifies the request primarily by the userid associated
    with the session, but it also provides an extra principal to identify
    the requesting application.

    Requests are currently authenticated using a simple bearer-token scheme,
    with each request embedding the sessionid under which it wants to operate.
    Eventually we'll implement something like 2-legged OAuth signing.
    """
    implements(IAuthenticationPolicy)

    def authenticated_userid(self, request):
        """Get the userid associated with this request.

        This method checks the embedded request signature and, if it contains
        a valid session, returns the associated userid.
        """
        session = self._get_session_data(request)
        if session is None:
            return None
        return session[1]

    def unauthenticated_userid(self, request):
        """Get the userid associated with this request.

        For Sauropod this method is exactly equivalent to the authenticated
        version - since loading data from the session means consulting the
        ISesssionManager, there's no point in trying to shortcut any validation
        of the signature.
        """
        return self.authenticated_userid(request)

    def effective_principals(self, request):
        """Get the effective principals active for this request.

        For authenticated requests, the effective principals will always
        include the application if in the form "app:APPID".  If the request
        has a valid session then it will also include the associated userid.
        """
        principals = [Everyone]
        session = self._get_session_data(request)
        if session is not None:
            appid, userid = session
            principals.append(Authenticated)
            principals.append(userid)
            principals.append("app:" + appid)
        return principals

    def remember(self, request, principal):
        """Remember the authenticated user.

        This is a no-op for Sauropod; clients must remember their credentials
        and include a valid signature on every request.
        """
        return []

    def forget(self, request):
        """Forget the authenticated user.

        This is a no-op for Sauropod; clients must remember their credentials
        and include a valid signature on every request.
        """
        return []

    def _get_session_data(self, request):
        """Get the session data from the request.

        This method checks the session identifier included in the request.
        If invalid then None is returned; if valid then the (appid, userid)
        tuple is returned.
        """
        # Try to use cached version.
        if "sauropod.session_data" in request.environ:
            return request.environ["sauropod.session_data"]
        # Grab the sessionid from the "signature" heaer.
        sessionid = request.environ.get("HTTP_SIGNATURE")
        if sessionid is None:
            return None
        session_manager = request.registry.getUtility(ISessionManager)
        session = session_manager.get_session_data(sessionid)
        request.environ["sauropod.session_data"] = session
        return session
Beispiel #3
0
class ActionInfo(UserDict):
    """ A lazy dictionary for Action infos.
    """

    implements(IActionInfo)
    __implements__ = z2IActionInfo

    __allow_access_to_unprotected_subobjects__ = 1

    def __init__(self, action, ec):

        if isinstance(action, dict):
            lazy_keys = []
            UserDict.__init__(self, action)
            if 'name' in self.data:
                self.data.setdefault('id', self.data['name'].lower())
                self.data.setdefault('title', self.data['name'])
                del self.data['name']
            self.data.setdefault('url', '')
            self.data.setdefault('category', 'object')
            self.data.setdefault('visible', True)
            self.data['available'] = True
        else:
            # if action isn't a dict, it has to implement IAction
            (lazy_map, lazy_keys) = action.getInfoData()
            UserDict.__init__(self, lazy_map)

        self.data['allowed'] = True
        permissions = self.data.pop('permissions', ())
        if permissions:
            self.data['allowed'] = self._checkPermissions
            lazy_keys.append('allowed')

        self._ec = ec
        self._lazy_keys = lazy_keys
        self._permissions = permissions

    def __getitem__(self, key):
        value = UserDict.__getitem__(self, key)
        if key in self._lazy_keys:
            value = self.data[key] = value(self._ec)
            self._lazy_keys.remove(key)
        return value

    def __eq__(self, other):
        # this is expensive, use it with care
        [self.__getitem__(key) for key in self._lazy_keys]

        if isinstance(other, self.__class__):
            [other[key] for key in other._lazy_keys]
            return self.data == other.data
        elif isinstance(other, UserDict):
            return self.data == other.data
        else:
            return self.data == other

    def copy(self):
        c = UserDict.copy(self)
        c._lazy_keys = self._lazy_keys[:]
        return c

    def _checkPermissions(self, ec):
        """ Check permissions in the current context.
        """
        category = self['category']
        object = ec.contexts['object']
        if object is not None and (category.startswith('object')
                                   or category.startswith('workflow')
                                   or category.startswith('document')):
            context = object
        else:
            folder = ec.contexts['folder']
            if folder is not None and category.startswith('folder'):
                context = folder
            else:
                context = ec.contexts['portal']

        for permission in self._permissions:
            if _checkPermission(permission, context):
                return True
        return False
Beispiel #4
0
class Action(PropertyManager, SimpleItem):
    """ Reference to an action.
    """

    implements(IAction)

    i18n_domain = 'cmf_default'

    security = ClassSecurityInfo()

    _properties = (
        {
            'id': 'title',
            'type': 'string',
            'mode': 'w',
            'label': 'Title'
        },
        {
            'id': 'description',
            'type': 'text',
            'mode': 'w',
            'label': 'Description'
        },
        {
            'id': 'i18n_domain',
            'type': 'string',
            'mode': 'w',
            'label': 'I18n Domain'
        },
        {
            'id': 'url_expr',
            'type': 'string',
            'mode': 'w',
            'label': 'URL (Expression)'
        },
        {
            'id': 'icon_expr',
            'type': 'string',
            'mode': 'w',
            'label': 'Icon (Expression)'
        },
        {
            'id': 'available_expr',
            'type': 'string',
            'mode': 'w',
            'label': 'Condition (Expression)'
        },
        {
            'id': 'permissions',
            'type': 'multiple selection',
            'mode': 'w',
            'label': 'Permissions',
            'select_variable': 'possible_permissions'
        },
        {
            'id': 'visible',
            'type': 'boolean',
            'mode': 'w',
            'label': 'Visible?'
        },
    )

    manage_options = (PropertyManager.manage_options +
                      SimpleItem.manage_options)

    def __init__(self, id, **kw):
        self.id = id
        self._setPropValue('title', kw.get('title', ''))
        self._setPropValue('description', kw.get('description', ''))
        self._setPropValue('i18n_domain', kw.get('i18n_domain', ''))
        self._setPropValue('url_expr', kw.get('url_expr', ''))
        self._setPropValue('icon_expr', kw.get('icon_expr', ''))
        self._setPropValue('available_expr', kw.get('available_expr', ''))
        self._setPropValue('permissions', kw.get('permissions', ()))
        self._setPropValue('visible', kw.get('visible', True))

    def _setPropValue(self, id, value):
        self._wrapperCheck(value)
        if isinstance(value, list):
            value = tuple(value)
        setattr(self, id, value)
        if value and id.endswith('_expr'):
            setattr(self, '%s_object' % id, Expression(value))

    security.declarePrivate('getInfoData')

    def getInfoData(self):
        """ Get the data needed to create an ActionInfo.
        """
        category_path = []
        lazy_keys = []
        lazy_map = {}

        lazy_map['id'] = self.getId()

        parent = aq_parent(self)
        while parent is not None and parent.getId() != 'portal_actions':
            category_path.append(parent.getId())
            parent = aq_parent(parent)
        lazy_map['category'] = '/'.join(category_path[::-1])

        for id, val in self.propertyItems():
            if id.endswith('_expr'):
                id = id[:-5]
                if val:
                    val = getattr(self, '%s_expr_object' % id)
                    lazy_keys.append(id)
                elif id == 'available':
                    val = True
            elif id == 'i18n_domain':
                continue
            elif self.i18n_domain and id in ('title', 'description'):
                val = Message(val, self.i18n_domain)
            lazy_map[id] = val

        return (lazy_map, lazy_keys)
class BuildRequest:
    """I represent a request to a specific Builder to run a single build.

    I have a SourceStamp which specifies what sources I will build. This may
    specify a specific revision of the source tree (so source.branch,
    source.revision, and source.patch are used). The .patch attribute is
    either None or a tuple of (patchlevel, diff), consisting of a number to
    use in 'patch -pN', and a unified-format context diff.

    Alternatively, the SourceStamp may specify a set of Changes to be built,
    contained in source.changes. In this case, I may be mergeable with other
    BuildRequests on the same branch.

    I may be part of a BuildSet, in which case I will report status results
    to it.

    I am paired with a BuildRequestStatus object, to which I feed status
    information.

    @type source: a L{buildbot.sourcestamp.SourceStamp} instance.   
    @ivar source: the source code that this BuildRequest use

    @type reason: string
    @ivar reason: the reason this Build is being requested. Schedulers
                  provide this, but for forced builds the user requesting the
                  build will provide a string.

    @type properties: Properties object
    @ivar properties: properties that should be applied to this build

    @ivar status: the IBuildStatus object which tracks our status

    @ivar submittedAt: a timestamp (seconds since epoch) when this request
                       was submitted to the Builder. This is used by the CVS
                       step to compute a checkout timestamp, as well as the
                       master to prioritize build requests from oldest to
                       newest.
    """

    source = None
    builder = None
    startCount = 0  # how many times we have tried to start this build
    submittedAt = None

    implements(interfaces.IBuildRequestControl)

    def __init__(self, reason, source, builderName=None, properties=None):
        # TODO: remove the =None on builderName, it is there so I don't have
        # to change a lot of tests that create BuildRequest objects
        assert interfaces.ISourceStamp(source, None)
        self.reason = reason
        self.source = source

        self.properties = Properties()
        if properties:
            self.properties.updateFromProperties(properties)

        self.start_watchers = []
        self.finish_watchers = []
        self.status = BuildRequestStatus(source, builderName)

    def canBeMergedWith(self, other):
        return self.source.canBeMergedWith(other.source)

    def mergeWith(self, others):
        return self.source.mergeWith([o.source for o in others])

    def mergeReasons(self, others):
        """Return a reason for the merged build request."""
        reasons = []
        for req in [self] + others:
            if req.reason and req.reason not in reasons:
                reasons.append(req.reason)
        return ", ".join(reasons)

    def waitUntilFinished(self):
        """Get a Deferred that will fire (with a
        L{buildbot.interfaces.IBuildStatus} instance when the build
        finishes."""
        d = defer.Deferred()
        self.finish_watchers.append(d)
        return d

    # these are called by the Builder

    def requestSubmitted(self, builder):
        # the request has been placed on the queue
        self.builder = builder

    def buildStarted(self, build, buildstatus):
        """This is called by the Builder when a Build has been started in the
        hopes of satifying this BuildRequest. It may be called multiple
        times, since interrupted builds and lost buildslaves may force
        multiple Builds to be run until the fate of the BuildRequest is known
        for certain."""
        for o in self.start_watchers[:]:
            # these observers get the IBuildControl
            o(build)
        # while these get the IBuildStatus
        self.status.buildStarted(buildstatus)

    def finished(self, buildstatus):
        """This is called by the Builder when the BuildRequest has been
        retired. This happens when its Build has either succeeded (yay!) or
        failed (boo!). TODO: If it is halted due to an exception (oops!), or
        some other retryable error, C{finished} will not be called yet."""

        for w in self.finish_watchers:
            w.callback(buildstatus)
        self.finish_watchers = []

    # IBuildRequestControl

    def subscribe(self, observer):
        self.start_watchers.append(observer)

    def unsubscribe(self, observer):
        self.start_watchers.remove(observer)

    def cancel(self):
        """Cancel this request. This can only be successful if the Build has
        not yet been started.

        @return: a boolean indicating if the cancel was successful."""
        if self.builder:
            return self.builder.cancelBuildRequest(self)
        return False
Beispiel #6
0
class WebSocketFactory(ClientFactory):
    """
    Implements device factory over websocket protocol.
    """

    implements(IWebSocketProtocolCallback, IProtoFactory)

    url = 'ws://localhost'
    host = 'localhost'
    port = 80
    proto = None
    handler = None
    callbacks = dict()

    def __init__(self, handler):
        """
        @type handler: C{object}
        @param handler: handler has to implement C{IProtoHandler} interface
        """
        self.handler = handler
        if IProtoHandler.implementedBy(self.handler.__class__):
            self.handler.factory = self
        else:
            raise TypeError(
                'handler should implements IProtoHandler interface')
        self.devices = {}

    def buildProtocol(self, addr):
        self.proto = WebSocketDeviceHiveProtocol(self, 'device')
        if not IWebSocketMessanger.implementedBy(self.proto.__class__):
            raise TypeError(
                'Protocol has to implement IWebSocketMessanger interface.')
        return self.proto

    def clientConnectionFailed(self, connector, reason):
        """
        TODO: rename on_connection_failed method
        """
        LOG_ERR('Failed to connect to {0}, host: {1}, port: {2}. Reason: {3}.'.
                format(self.url, self.host, self.port, reason))
        self.handler.on_connection_failed(reason)

    def clientConnectionLost(self, connector, reason):
        """
        TODO: notify handler about disconnection.
        """
        pass

    def send_message(self, message):
        return self.proto.send_message(message)

    # begin IWebSocketProtocolCallback implementation
    def failure(self, reason, connector):
        LOG_ERR('Critial error. Reason: {0}.'.format(reason))
        self.handler.on_failure(None, reason)

    def connected(self):
        LOG_MSG('WebSocketFactory: Connection with {0} has been established.'.
                format(self.url))
        self.handler.on_connected()

    def closing_connection(self):
        self.handler.on_closing_connection()

    def frame_received(self, message):
        if ('action' in message) and (message['action'] == 'command/insert'):
            if not 'deviceGuid' in message:
                LOG_ERR(
                    'Malformed command/insert message {0}.'.format(message))
            else:
                device_id = str(message['deviceGuid']).lower() if (
                    'deviceGuid' in message) and (message['deviceGuid']
                                                  is not None) else None
                if device_id in self.devices:
                    self.on_command_insert(WsCommand.create(message),
                                           self.devices[device_id])
                else:
                    LOG_ERR(
                        'Unable to process command {0}. Device {1} is not registered.'
                        .format(message, device_id))

    # End of IWebSocketProtocolCallback interface implementation

    def on_command_insert(self, cmd, info):
        """
        @type cmd: C{object}
        @param cmd: object which implements C{ICommand}
        
        @type info: C{object}
        @param info: C{IDeviceInfo} object which is receiving the command
        """
        LOG_MSG('Command {0} has been received for device {1}.'.format(
            cmd, info))

        def on_ok(result):
            LOG_MSG('The command "{0}" successfully processed. Result: {1}.'.
                    format(cmd, result))
            if isinstance(result, CommandResult):
                cmd.status = result.status
                cmd.result = result.result
            else:
                cmd.status = 'Success'
                cmd.result = result
            self.update_command(cmd, device_id=info.id, device_key=info.key)

        #
        def on_err(reason):
            LOG_ERR('Failed to process command "{0}". Reason: {1}.'.format(
                cmd, reason))
            if isinstance(reason, Exception):
                cmd.status = 'Failed'
                cmd.result = reason.message
            elif hasattr(reason, 'value'):
                if isinstance(reason.value, CommandResult):
                    cmd.status = reason.value.status
                    cmd.result = reason.value.result
                elif isinstance(reason.value, Exception):
                    cmd.status = 'Failed'
                    cmd.result = reason.value.message
                else:
                    cmd.status = 'Failed'
                    cmd.result = reason.value
            else:
                cmd.status = 'Failed'
                cmd.result = 'Unhandled Exception'
            self.update_command(cmd, device_id=info.id, device_key=info.key)

        #
        finished = Deferred()
        finished.addCallbacks(on_ok, on_err)
        try:
            self.handler.on_command(info.id, cmd, finished)
        except Exception as ex:
            err = DhError('Failed to invoke command {0}. Reason: {1}.'.format(
                cmd, ex.message))
            LOG_ERR(err.message)
            on_err(err)

    def update_command(self, command, device_id=None, device_key=None):
        if not ICommand.implementedBy(command.__class__):
            raise DhError('{0}.update_command expects ICommand'.format(
                self.__class__.__name__))
        request = {
            'action': 'command/update',
            'commandId': command.id,
            'command': command.to_dict()
        }
        if device_id is not None:
            request['deviceId'] = device_id
        if device_key is not None:
            request['deviceKey'] = device_key
        return self.send_message(request)

    # begin IProtoFactory implementation
    def authenticate(self, device_id, device_key):
        request = {
            'action': 'authenticate',
            'deviceId': device_id,
            'deviceKey': device_key
        }
        return self.send_message(request)

    def notify(self, notification, params, device_id=None, device_key=None):
        request = {
            'action': 'notification/insert',
            'notification': {
                'notification': notification,
                'parameters': params
            }
        }
        if (device_id is not None):
            request['deviceId'] = device_id
        if (device_key is not None):
            request['deviceKey'] = device_key
        return self.send_message(request)

    def subscribe(self, device_id=None, device_key=None):
        LOG_MSG('Subscribe device {0}.'.format(device_id))
        request = {'action': 'command/subscribe'}
        if device_id is not None:
            request['deviceId'] = device_id
        if device_key is not None:
            request['deviceKey'] = device_key
        return self.send_message(request)

    def unsubscribe(self, device_id=None, device_key=None):
        request = {'action': 'command/unsubscribe'}
        if device_id is not None:
            request['deviceId'] = device_id
        if device_key is not None:
            request['deviceKey'] = device_key
        return self.send_message(request)

    def device_save(self, info):
        LOG_MSG('device_save {0}'.format(info))
        if not IDeviceInfo.implementedBy(info.__class__):
            raise WebSocketError(
                'info parameter has to implement IDeviceInfo interface')
        dev = {
            'key': info.key,
            'name': info.name,
            'equipment': [e.to_dict() for e in info.equipment]
        }
        if info.status is not None:
            dev['status'] = info.status
        if info.network is not None:
            dev['network'] = info.network.to_dict() if INetwork.implementedBy(
                info.network.__class__) else info.network
        if info.data is not None:
            dev['data'] = info.data
        if info.device_class is not None:
            dev['deviceClass'] = info.device_class.to_dict(
            ) if IDeviceClass.implementedBy(
                info.device_class.__class__) else info.device_class
        request = {
            'action': 'device/save',
            'deviceId': info.id,
            'deviceKey': info.key,
            'device': dev
        }

        def on_ok(result):
            key = str(info.id).lower()
            self.devices[key] = info

        return self.send_message(request).addCallback(on_ok)

    def connect(self, url):
        reactor.connectDeviceHive(url, self)
Beispiel #7
0
class PingCRActionExecutor(object):
    """ Ping action executor
    """
    implements(IExecutable)
    adapts(Interface, IPingCRAction, Interface)

    def __init__(self, context, element, event):
        self.context = context
        self.element = element
        self.event = event
        self._rabbit_config = None

    @property
    def rabbit_config(self):
        """ RabbitMQ Config
        """
        if self._rabbit_config is not None:
            return self._rabbit_config

        try:
            self._rabbit_config = get_rabbitmq_client_settings()
        except Exception:
            self._rabbit_config = {}
        return self._rabbit_config

    def __call__(self):
        event = self.event
        service_to_ping = self.element.service_to_ping
        obj = self.event.object
        container = obj.getParentNode()
        noasync_msg = 'No instance for async operations was defined.'

        def pingCRSDS(service_to_ping, obj_url, create):
            """ Ping the CR/SDS service
            """
            options = {}
            options['service_to_ping'] = service_to_ping
            options['obj_url'] = self.sanitize_url(obj_url)
            options['create'] = create

            # Use RabbitMQ if available
            if self.rabbit_config:
                options['create'] = 'create' if options.get(
                    'create', False) else 'update'
                return ping_RabbitMQ(options)

            # Use zc.async if available
            if async_service is None:
                logger.warn("Can't pingCRSDS, plone.app.async not installed!")
                return

            queue = async_service.getQueues()['']
            try:
                async_service.queueJobInQueue(queue, ('rdf', ), ping_CRSDS,
                                              self.context, options)
            except ComponentLookupError:
                logger.info(noasync_msg)

        def pingCRSDS_backrel(service_to_ping, obj, create):
            """ Ping backward relations
            """
            if hasattr(obj, 'getBRefs'):
                back_relations = obj.getBRefs('relatesTo')
            else:
                back_relations = [
                    o.to_object for o in getattr(obj, 'relatedItems')
                ]

            for rel in back_relations:
                if rel is not None:
                    obj_url = "%s/@@rdf" % rel.absolute_url()
                    pingCRSDS(service_to_ping, obj_url, create)

        def pingCRSDS_children(service_to_ping, obj, create):
            """ Ping all sub-objects
            """
            if obj.portal_type == "Discussion Item":
                # 22047 skip object if it's of type Discussion Item
                return
            for child in obj.objectIds():
                child_obj = obj.get(child)
                if not child_obj:
                    logger.info("Couldn't retrieve child id %s for %s", child,
                                obj.absolute_url())
                    continue
                obj_url = "%s/@@rdf" % child_obj.absolute_url()
                pingCRSDS(service_to_ping, obj_url, create)
                pingCRSDS_children(service_to_ping, child_obj, create)

        # When no request the task is called from a async task, see #19830
        request = getattr(obj, 'REQUEST', None)

        # Detect special object used to force acquisition, see #18904
        if isinstance(request, str):
            request = None

        create = IObjectAddedEvent.providedBy(event)

        if service_to_ping == "":
            return

        if hasVersionsInstalled and IVersionEnhanced.providedBy(obj) \
                and request:
            obj_versions = IGetVersions(obj).versions()
        else:
            obj_versions = [obj]

        async_service = queryUtility(IAsyncService)

        # If object has translations
        if hasLinguaPloneInstalled and ITranslatable.providedBy(obj):
            if obj.isCanonical():
                # Ping all translations
                for trans in obj.getTranslations().items():
                    if trans[0] != 'en':
                        trans_obj = trans[1][0]
                        obj_url = trans_obj.absolute_url()
                        pingCRSDS(service_to_ping, obj_url, create)
            else:
                # Ping only canonical
                can_obj = obj.getCanonical()
                obj_url = can_obj.absolute_url()
                pingCRSDS(service_to_ping, obj_url, create)

        # If object was deleted
        if IObjectRemovedEvent.providedBy(event):
            # Ping backward relations
            pingCRSDS_backrel(service_to_ping, obj, create)

            # Ping all sub-objects
            pingCRSDS_children(service_to_ping, obj, create)

        # If object was moved/renamed first ping with the old object's URL
        if IObjectMovedOrRenamedEvent.providedBy(event):
            obj_url = "%s/%s/@@rdf" % (event.oldParent.absolute_url(),
                                       event.oldName)
            pingCRSDS(service_to_ping, obj_url, False)

            # then ping with the container of the old object
            obj_url = "%s/@@rdf" % event.oldParent.absolute_url()
            pingCRSDS(service_to_ping, obj_url, False)

            # Ping backward relations
            pingCRSDS_backrel(service_to_ping, obj, create)

            # Ping all sub-objects
            pingCRSDS_children(service_to_ping, obj, create)

        # Ping each version
        for obj in obj_versions:
            obj_url = "%s/@@rdf" % obj.absolute_url()
            pingCRSDS(service_to_ping, obj_url, create)

        # If no Aquisition there is no container, see #18904
        if container:
            obj_url = "%s/@@rdf" % container.absolute_url()
            pingCRSDS(service_to_ping, obj_url, False)

        return True

    def sanitize_url(self, url):
        """ Replace object's portal_url value with the one defined as an
            environment value if any
        """
        portal_url_tool = getToolByName(self.context, 'portal_url')
        portal_url = portal_url_tool()
        conf = getConfiguration()

        if not hasattr(conf, 'environment'):
            return  # this happens during unit tests, we skip this procedure

        default_url = conf.environment.get('portal_url', portal_url)

        # Force ping_cr on HTTP to fit Virtuoso triples
        default_url = default_url.replace('https://', 'http://', 1)

        if default_url != portal_url:
            url = url.replace(unicode(portal_url), unicode(default_url))
            url = url.replace('SITE/', '')

        return url
Beispiel #8
0
class Dispatcher(service.AsyncService):
    implements(portal.IRealm, checkers.ICredentialsChecker)

    credentialInterfaces = [credentials.IUsernamePassword,
                            credentials.IUsernameHashedPassword]

    def __init__(self, portstr):
        self.portstr = portstr
        self.users = {}

        # there's lots of stuff to set up for a PB connection!
        self.portal = portal.Portal(self)
        self.portal.registerChecker(self)
        self.serverFactory = pb.PBServerFactory(self.portal)
        self.serverFactory.unsafeTracebacks = True
        self.port = None

    def __repr__(self):
        return "<pbmanager.Dispatcher for %s on %s>" % \
            (", ".join(self.users.keys()), self.portstr)

    def startService(self):
        assert not self.port
        self.port = strports.listen(self.portstr, self.serverFactory)
        return service.AsyncService.startService(self)

    def stopService(self):
        # stop listening on the port when shut down
        assert self.port
        port, self.port = self.port, None
        d = defer.maybeDeferred(port.stopListening)
        d.addCallback(lambda _: service.AsyncService.stopService(self))
        return d

    def register(self, username, password, pfactory):
        if debug:
            log.msg("registering username '%s' on pb port %s: %s"
                    % (username, self.portstr, pfactory))
        if username in self.users:
            raise KeyError("username '%s' is already registered on PB port %s"
                           % (username, self.portstr))
        self.users[username] = (password, pfactory)

    def unregister(self, username):
        if debug:
            log.msg("unregistering username '%s' on pb port %s"
                    % (username, self.portstr))
        del self.users[username]

    # IRealm

    def requestAvatar(self, username, mind, interface):
        assert interface == pb.IPerspective
        if username not in self.users:
            d = defer.succeed(None)  # no perspective
        else:
            _, afactory = self.users.get(username)
            d = defer.maybeDeferred(afactory, mind, username)

        # check that we got a perspective
        @d.addCallback
        def check(persp):
            if not persp:
                raise ValueError("no perspective for '%s'" % username)
            return persp

        # call the perspective's attached(mind)
        @d.addCallback
        def call_attached(persp):
            d = defer.maybeDeferred(persp.attached, mind)
            d.addCallback(lambda _: persp)  # keep returning the perspective
            return d

        # return the tuple requestAvatar is expected to return
        @d.addCallback
        def done(persp):
            return (pb.IPerspective, persp, lambda: persp.detached(mind))

        return d

    # ICredentialsChecker

    def requestAvatarId(self, creds):
        if creds.username in self.users:
            password, _ = self.users[creds.username]
            d = defer.maybeDeferred(creds.checkPassword, password)

            @d.addCallback
            def check(matched):
                if not matched:
                    log.msg("invalid login from user '%s'" % creds.username)
                    return failure.Failure(error.UnauthorizedLogin())
                return creds.username
            return d
        else:
            log.msg("invalid login from unknown user '%s'" % creds.username)
            return defer.fail(error.UnauthorizedLogin())
class Criterion(object):
    """ Search criteria
    """
    interface.implements(ICriterion)

    widget = None
    title = ''
    index = ''
    vocabulary = ''
    position = 'right'
    catalog = None
    _hidden = False
    default = None
    section = 'default'

    def hidden(self=None):
        """ Hidden property
        """
        def fget(self):
            """ Getter
            """
            hidden = getattr(self, '_hidden', None)
            if not hidden:
                return False

            if hidden in ('0', 'False', 'false', 'none', 'None'):
                return False
            return True

        def fset(self, value):
            """ Setter
            """
            if value in ('0', 'False', 'false', 'none', 'None'):
                value = False
            self._hidden = value and True or False
        return property(fget, fset, doc='Hidden property')
    hidden = hidden()

    def __init__(self, **kwargs):
        taken_ids = set(kwargs.pop('_taken_ids_', []))
        cid = kwargs.pop('_cid_', None)
        if not cid:
            free_ids = set('c%d' % uid for uid in range(len(taken_ids)+1))
            cid = free_ids.difference(taken_ids)
            cid = cid.pop()
        elif cid in taken_ids:
            raise KeyError('Id is already in use')
        self.__name__ = cid
        self.update(**kwargs)

    def update(self, **kwargs):
        """ Update criterion properties
        """
        for key, value in kwargs.items():
            if isinstance(value, str):
                value = value.decode('utf-8', 'replace')

            if value == u'0':
                value = u""

            setattr(self, key, value)

    def getId(self):
        """ Get criterion id
        """
        return self.__name__

    def get(self, key, default=None):
        """ Get attribute by given key
        """
        return getattr(self, key, default)
class DummyEvent(object):
    implements(IObjectEvent)

    def __init__(self, obj):
        self.object = obj
Beispiel #11
0
class SupplyOrder(BaseFolder):

    implements(ISupplyOrder, IConstrainTypes)

    security = ClassSecurityInfo()
    displayContentsTab = False
    schema = schema

    _at_rename_after_creation = True
    supplyorder_lineitems = []

    def _renameAfterCreation(self, check_auto_id=False):
        from bika.lims.idserver import renameAfterCreation
        renameAfterCreation(self)

    def getInvoiced(self):
        if self.getInvoice():
            return True
        else:
            return False

    def Title(self):
        """ Return the OrderNumber as title """
        return safe_unicode(self.getOrderNumber()).encode('utf-8')

    def getOrderNumber(self):
        return safe_unicode(self.getId()).encode('utf-8')

    def getContacts(self):
        adapter = getAdapter(self.aq_parent, name='getContacts')
        return adapter()

    security.declarePublic('getContactUIDForUser')

    def getContactUIDForUser(self):
        """ get the UID of the contact associated with the authenticated
            user
        """
        user = self.REQUEST.AUTHENTICATED_USER
        user_id = user.getUserName()
        r = self.portal_catalog(portal_type='Contact', getUsername=user_id)
        if len(r) == 1:
            return r[0].UID

    security.declareProtected(View, 'getTotalQty')

    def getTotalQty(self):
        """ Compute total qty """
        if self.supplyorder_lineitems:
            return sum([obj['Quantity'] for obj in self.supplyorder_lineitems])
        return 0

    security.declareProtected(View, 'getSubtotal')

    def getSubtotal(self):
        """ Compute Subtotal """
        if self.supplyorder_lineitems:
            return sum([(Decimal(obj['Quantity']) * Decimal(obj['Price']))
                        for obj in self.supplyorder_lineitems])
        return 0

    security.declareProtected(View, 'getVATAmount')

    def getVATAmount(self):
        """ Compute VAT """
        return Decimal(self.getTotal()) - Decimal(self.getSubtotal())

    security.declareProtected(View, 'getTotal')

    def getTotal(self):
        """ Compute TotalPrice """
        total = 0
        for lineitem in self.supplyorder_lineitems:
            total += Decimal(lineitem['Quantity']) * \
                     Decimal(lineitem['Price']) *  \
                     ((Decimal(lineitem['VAT']) /100) + 1)
        return total

    def workflow_script_dispatch(self):
        """ dispatch order """
        self.setDateDispatched(DateTime())
        self.reindexObject()

    security.declareProtected(View, 'getProductUIDs')

    def getProductUIDs(self):
        """ return the uids of the products referenced by order items
        """
        uids = []
        for orderitem in self.objectValues('XupplyOrderItem'):
            product = orderitem.getProduct()
            if product is not None:
                uids.append(orderitem.getProduct().UID())
        return uids

    security.declarePublic('current_date')

    def current_date(self):
        """ return current date """
        return DateTime()
class ProductRelease(SQLBase):
    """A release of a product."""
    implements(IProductRelease)
    _table = 'ProductRelease'
    _defaultOrder = ['-datereleased']

    datereleased = UtcDateTimeCol(notNull=True)
    release_notes = StringCol(notNull=False, default=None)
    changelog = StringCol(notNull=False, default=None)
    datecreated = UtcDateTimeCol(dbName='datecreated',
                                 notNull=True,
                                 default=UTC_NOW)
    owner = ForeignKey(dbName="owner",
                       foreignKey="Person",
                       storm_validator=validate_person,
                       notNull=True)
    milestone = ForeignKey(dbName='milestone', foreignKey='Milestone')

    _files = SQLMultipleJoin('ProductReleaseFile',
                             joinColumn='productrelease',
                             orderBy='-date_uploaded',
                             prejoins=['productrelease'])

    @cachedproperty
    def files(self):
        return self._files

    @property
    def version(self):
        """See `IProductRelease`."""
        return self.milestone.name

    @property
    def productseries(self):
        """See `IProductRelease`."""
        return self.milestone.productseries

    @property
    def product(self):
        """See `IProductRelease`."""
        return self.milestone.productseries.product

    @property
    def displayname(self):
        """See `IProductRelease`."""
        return self.milestone.displayname

    @property
    def title(self):
        """See `IProductRelease`."""
        return self.milestone.title

    @property
    def can_have_release_files(self):
        """See `IProductRelease`."""
        return self.product.information_type == InformationType.PUBLIC

    @staticmethod
    def normalizeFilename(filename):
        # Replace slashes in the filename with less problematic dashes.
        return filename.replace('/', '-')

    def destroySelf(self):
        """See `IProductRelease`."""
        assert self._files.count() == 0, (
            "You can't delete a product release which has files associated "
            "with it.")
        SQLBase.destroySelf(self)

    def _getFileObjectAndSize(self, file_or_data):
        """Return an object and length for file_or_data.

        :param file_or_data: A string or a file object or StringIO object.
        :return: file object or StringIO object and size.
        """
        if isinstance(file_or_data, basestring):
            file_size = len(file_or_data)
            file_obj = StringIO(file_or_data)
        else:
            assert isinstance(
                file_or_data,
                (file, StringIO)), ("file_or_data is not an expected type")
            file_obj = file_or_data
            start = file_obj.tell()
            file_obj.seek(0, os.SEEK_END)
            file_size = file_obj.tell()
            file_obj.seek(start)
        return file_obj, file_size

    def addReleaseFile(self,
                       filename,
                       file_content,
                       content_type,
                       uploader,
                       signature_filename=None,
                       signature_content=None,
                       file_type=UpstreamFileType.CODETARBALL,
                       description=None,
                       from_api=False):
        """See `IProductRelease`."""
        if not self.can_have_release_files:
            raise ProprietaryProduct(
                "Only public projects can have download files.")
        if self.hasReleaseFile(filename):
            raise InvalidFilename
        # Create the alias for the file.
        filename = self.normalizeFilename(filename)
        # XXX: StevenK 2013-02-06 bug=1116954: We should not need to refetch
        # the file content from the request, since the passed in one has been
        # wrongly encoded.
        if from_api:
            file_content = get_raw_form_value_from_current_request(
                'file_content')
        file_obj, file_size = self._getFileObjectAndSize(file_content)

        alias = getUtility(ILibraryFileAliasSet).create(
            name=filename,
            size=file_size,
            file=file_obj,
            contentType=content_type)
        if signature_filename is not None and signature_content is not None:
            # XXX: StevenK 2013-02-06 bug=1116954: We should not need to
            # refetch the file content from the request, since the passed in
            # one has been wrongly encoded.
            if from_api:
                signature_content = get_raw_form_value_from_current_request(
                    'signature_content')
            signature_obj, signature_size = self._getFileObjectAndSize(
                signature_content)
            signature_filename = self.normalizeFilename(signature_filename)
            signature_alias = getUtility(ILibraryFileAliasSet).create(
                name=signature_filename,
                size=signature_size,
                file=signature_obj,
                contentType='application/pgp-signature')
        else:
            signature_alias = None
        return ProductReleaseFile(productrelease=self,
                                  libraryfile=alias,
                                  signature=signature_alias,
                                  filetype=file_type,
                                  description=description,
                                  uploader=uploader)

    def getFileAliasByName(self, name):
        """See `IProductRelease`."""
        for file_ in self.files:
            if file_.libraryfile.filename == name:
                return file_.libraryfile
            elif file_.signature and file_.signature.filename == name:
                return file_.signature
        raise NotFoundError(name)

    def getProductReleaseFileByName(self, name):
        """See `IProductRelease`."""
        for file_ in self.files:
            if file_.libraryfile.filename == name:
                return file_
        raise NotFoundError(name)

    def hasReleaseFile(self, name):
        """See `IProductRelease`."""
        try:
            self.getProductReleaseFileByName(name)
            return True
        except NotFoundError:
            return False
Beispiel #13
0
class TranslationsOverview:
    implements(ITranslationsOverview)

    # Project weights will be scaled into [MINIMUM_SIZE, MAXIMUM_SIZE] range.
    MINIMUM_SIZE = 10
    MAXIMUM_SIZE = 18

    def _normalizeSizes(self, pillars, minimum, maximum):
        """Normalize pillar sizes into range [MINIMUM_SIZE, MAXIMUM_SIZE]."""
        if maximum == minimum:
            multiplier = 0
            offset = 0
            real_minimum = (self.MAXIMUM_SIZE + self.MINIMUM_SIZE) / 2.0
        else:
            offset = minimum - self.MINIMUM_SIZE
            multiplier = (float(self.MAXIMUM_SIZE - self.MINIMUM_SIZE) /
                          (maximum - minimum))
            real_minimum = self.MINIMUM_SIZE

        normalized_sizes = []
        for (pillar, size) in pillars:
            new_size = int(
                round(real_minimum +
                      (size - offset - real_minimum) * multiplier))
            normalized_sizes.append({'pillar': pillar, 'weight': new_size})
        return normalized_sizes

    def getMostTranslatedPillars(self, limit=50):
        """See `ITranslationsOverview`."""

        # XXX Abel Deuring 2012-10-26 bug=1071751
        # The expression product.information_type IS NULL can be
        # removed once we have the DB constraint
        # "Product.information_type IS NULL".
        query = """
        SELECT LOWER(COALESCE(product_name, distro_name)) AS name,
               product_id,
               distro_id,
               LN(total_karma)/LN(2) AS karma
          FROM (
            SELECT
                product.displayname AS product_name,
                product.id AS product_id,
                distribution.displayname AS distro_name,
                distribution.id AS distro_id,
                SUM(karmavalue) AS total_karma
              FROM karmacache
                   LEFT JOIN product ON
                     product=product.id
                   LEFT JOIN distribution ON
                     distribution=distribution.id
              WHERE category=3 AND
                    (product IS NOT NULL OR distribution IS NOT NULL) AND
                    (product.translations_usage = %s AND
                     (product.information_type = %s OR
                      product.information_type IS NULL) OR
                    distribution.translations_usage = %s)
              GROUP BY product.displayname, product.id,
                       distribution.displayname, distribution.id
              HAVING SUM(karmavalue) > 0
              ORDER BY total_karma DESC
              LIMIT %s) AS something
          ORDER BY name""" % sqlvalues(ServiceUsage.LAUNCHPAD,
                                       InformationType.PUBLIC,
                                       ServiceUsage.LAUNCHPAD, limit)
        cur = cursor()
        cur.execute(query)

        all_pillars = []

        # Get minimum and maximum relative karma value to be able to normalize
        # them to appropriate font size values.
        minimum = None
        maximum = None
        for (name, product_id, distro_id, relative_karma) in cur.fetchall():
            if minimum is None or relative_karma < minimum:
                minimum = relative_karma
            if maximum is None or relative_karma > maximum:
                maximum = relative_karma
            if product_id is not None:
                pillar = Product.get(product_id)
            elif distro_id is not None:
                pillar = Distribution.get(distro_id)
            else:
                raise MalformedKarmaCacheData(
                    "Lots of karma for non-existing product or distribution.")
            all_pillars.append((pillar, relative_karma))

        # Normalize the relative karma values between MINIMUM_SIZE and
        # MAXIMUM_SIZE.
        return self._normalizeSizes(all_pillars, minimum, maximum)
Beispiel #14
0
                e_type, e_value, trace, TB_LIMIT))

            self.send_reply(Message.reply(msg.name, "fail", reason), msg)

    def handle_reply(self, msg):
        if not self.queries:
            raise NoQuerriesProcessed()
        name, d, queue = self.queries[0]
        if name != msg.name:
            d.errback("Wrong request order")
            return
        self.queries.pop(0)  # hopefully it's not large
        d.callback((queue, msg))

    # IPushProducer interface
    implements(IPushProducer)

    def pauseProducing(self):
        self.producing = False
    stopProducing = pauseProducing

    def resumeProducing(self):
        for msg in self.queue:
            self.transport.write(str(msg) + self.delimiter)
        self.queue = []
        self.producing = True

    def send_reply(self, reply, orig_req):
        """Send a reply, setting the message id from the original request."""
        assert (reply.mtype == Message.REPLY)
        reply.mid = orig_req.mid
class TaskTemplate(Item):
    implements(ITaskTemplate)
Beispiel #16
0
class ReferenceValuesValidator:
    """Min value must be below max value
       Percentage value must be between 0 and 100
       Values must be numbers
       Expected values must be between min and max values
    """

    implements(IValidator)
    name = "referencevalues_validator"

    def __call__(self, value, *args, **kwargs):

        instance = kwargs['instance']
        # fieldname = kwargs['field'].getName()
        request = kwargs.get('REQUEST', {})

        translate = getToolByName(instance, 'translation_service').translate

        ress = request.get('result', {})[0]
        mins = request.get('min', {})[0]
        maxs = request.get('max', {})[0]
        errs = request.get('error', {})[0]

        # Retrieve all AS uids
        uids = ress.keys()
        for uid in uids:

            # Foreach AS, check spec. input values
            res = ress[uid] if ress[uid] else '0'
            min = mins[uid] if mins[uid] else '0'
            max = maxs[uid] if maxs[uid] else '0'
            err = errs[uid] if errs[uid] else '0'

            # Values must be numbers
            try:
                res = float(res)
            except ValueError:
                return to_utf8(
                    translate(
                        _("Validation failed: Expected values must be numeric")
                    ))
            try:
                min = float(min)
            except ValueError:
                return to_utf8(
                    translate(
                        _("Validation failed: Min values must be numeric")))
            try:
                max = float(max)
            except ValueError:
                return to_utf8(
                    translate(
                        _("Validation failed: Max values must be numeric")))
            try:
                err = float(err)
            except ValueError:
                return to_utf8(
                    translate(
                        _("Validation failed: Percentage error values must be "
                          "numeric")))

            # Min value must be < max
            if min > max:
                return to_utf8(
                    translate(
                        _("Validation failed: Max values must be greater than Min "
                          "values")))

            # Expected result must be between min and max
            if res < min or res > max:
                return to_utf8(
                    translate(
                        _("Validation failed: Expected values must be between Min "
                          "and Max values")))

            # Error percentage must be between 0 and 100
            if err < 0 or err > 100:
                return to_utf8(
                    translate(
                        _("Validation failed: Percentage error values must be "
                          "between 0 and 100")))

        return True
Beispiel #17
0
class DummyContent(PortalContent, Item):
    """
    A Dummy piece of PortalContent
    """
    implements(IContentish)

    meta_type = 'Dummy'
    portal_type = 'Dummy Content'
    url = 'foo_url'
    after_add_called = before_delete_called = 0

    def __init__(self, id='dummy', *args, **kw):
        self.id = id
        self._args = args
        self._kw = {}
        self._kw.update(kw)

        self.reset()
        self.catalog = kw.get('catalog', 0)
        self.url = kw.get('url', None)
        self.view_id = kw.get('view_id', None)

    def manage_afterAdd(self, item, container):
        self.after_add_called = 1

    def manage_beforeDelete(self, item, container):
        self.before_delete_called = 1

    def absolute_url(self):
        return self.url

    def reset(self):
        self.after_add_called = self.before_delete_called = 0

    # Make sure normal Database export/import stuff doesn't trip us up.
    def _getCopy(self, container):
        return DummyContent(self.id, catalog=self.catalog)

    def _safe_get(self, attr):
        if self.catalog:
            return getattr(self, attr, '')
        else:
            return getattr(self, attr)

    def Title(self):
        return self.title

    def listCreators(self):
        return self._safe_get('creators')

    def Subject(self):
        return self._safe_get('subject')

    def Description(self):
        return self._safe_get('description')

    def created(self):
        return self._safe_get('created_date')

    def modified(self):
        return self._safe_get('modified_date')

    def Type(self):
        return 'Dummy Content Title'

    def __call__(self):
        if self.view_id is None:
            return DummyContent.inheritedAttribute('__call__')(self)
        else:
            # view_id control for testing
            template = getattr(self, self.view_id)
            if getattr(aq_base(template), 'isDocTemp', 0):
                return template(self, self.REQUEST, self.REQUEST['RESPONSE'])
            else:
                return template()
class Build:
    """I represent a single build by a single slave. Specialized Builders can
    use subclasses of Build to hold status information unique to those build
    processes.

    I control B{how} the build proceeds. The actual build is broken up into a
    series of steps, saved in the .buildSteps[] array as a list of
    L{buildbot.process.step.BuildStep} objects. Each step is a single remote
    command, possibly a shell command.

    During the build, I put status information into my C{BuildStatus}
    gatherer.

    After the build, I go away.

    I can be used by a factory by setting buildClass on
    L{buildbot.process.factory.BuildFactory}

    @ivar requests: the list of L{BuildRequest}s that triggered me
    @ivar build_status: the L{buildbot.status.builder.BuildStatus} that
                        collects our status
    """

    implements(interfaces.IBuildControl)

    workdir = "build"
    build_status = None
    reason = "changes"
    finished = False
    results = None

    def __init__(self, requests):
        self.requests = requests
        for req in self.requests:
            req.startCount += 1
        self.locks = []
        # build a source stamp
        self.source = requests[0].mergeWith(requests[1:])
        self.reason = requests[0].mergeReasons(requests[1:])

        self.progress = None
        self.currentStep = None
        self.slaveEnvironment = {}

        self.terminate = False

    def setBuilder(self, builder):
        """
        Set the given builder as our builder.

        @type  builder: L{buildbot.process.builder.Builder}
        """
        self.builder = builder

    def setLocks(self, locks):
        self.locks = locks

    def getSourceStamp(self):
        return self.source

    def setProperty(self, propname, value, source):
        """Set a property on this build. This may only be called after the
        build has started, so that it has a BuildStatus object where the
        properties can live."""
        self.build_status.setProperty(propname, value, source)

    def getProperties(self):
        return self.build_status.getProperties()

    def getProperty(self, propname):
        return self.build_status.getProperty(propname)

    def allChanges(self):
        return self.source.changes

    def allFiles(self):
        # return a list of all source files that were changed
        files = []
        havedirs = 0
        for c in self.allChanges():
            for f in c.files:
                files.append(f)
            if c.isdir:
                havedirs = 1
        return files

    def __repr__(self):
        return "<Build %s>" % (self.builder.name, )

    def __getstate__(self):
        d = self.__dict__.copy()
        if d.has_key('remote'):
            del d['remote']
        return d

    def blamelist(self):
        blamelist = []
        for c in self.allChanges():
            if c.who not in blamelist:
                blamelist.append(c.who)
        blamelist.sort()
        return blamelist

    def changesText(self):
        changetext = ""
        for c in self.allChanges():
            changetext += "-" * 60 + "\n\n" + c.asText() + "\n"
        # consider sorting these by number
        return changetext

    def setStepFactories(self, step_factories):
        """Set a list of 'step factories', which are tuples of (class,
        kwargs), where 'class' is generally a subclass of step.BuildStep .
        These are used to create the Steps themselves when the Build starts
        (as opposed to when it is first created). By creating the steps
        later, their __init__ method will have access to things like
        build.allFiles() ."""
        self.stepFactories = list(step_factories)

    useProgress = True

    def getSlaveCommandVersion(self, command, oldversion=None):
        return self.slavebuilder.getSlaveCommandVersion(command, oldversion)

    def getSlaveName(self):
        return self.slavebuilder.slave.slavename

    def setupProperties(self):
        props = self.getProperties()

        # start with global properties from the configuration
        buildmaster = self.builder.botmaster.parent
        props.updateFromProperties(buildmaster.properties)

        # get any properties from requests (this is the path through
        # which schedulers will send us properties)
        for rq in self.requests:
            props.updateFromProperties(rq.properties)

        # now set some properties of our own, corresponding to the
        # build itself
        props.setProperty("buildername", self.builder.name, "Build")
        props.setProperty("buildnumber", self.build_status.number, "Build")
        props.setProperty("branch", self.source.branch, "Build")
        props.setProperty("revision", self.source.revision, "Build")

    def setupSlaveBuilder(self, slavebuilder):
        self.slavebuilder = slavebuilder

        # navigate our way back to the L{buildbot.buildslave.BuildSlave}
        # object that came from the config, and get its properties
        buildslave_properties = slavebuilder.slave.properties
        self.getProperties().updateFromProperties(buildslave_properties)

        self.slavename = slavebuilder.slave.slavename
        self.build_status.setSlavename(self.slavename)

    def startBuild(self, build_status, expectations, slavebuilder):
        """This method sets up the build, then starts it by invoking the
        first Step. It returns a Deferred which will fire when the build
        finishes. This Deferred is guaranteed to never errback."""

        # we are taking responsibility for watching the connection to the
        # remote. This responsibility was held by the Builder until our
        # startBuild was called, and will not return to them until we fire
        # the Deferred returned by this method.

        log.msg("%s.startBuild" % self)
        self.build_status = build_status
        # now that we have a build_status, we can set properties
        self.setupProperties()
        self.setupSlaveBuilder(slavebuilder)
        slavebuilder.slave.updateSlaveStatus(buildStarted=build_status)

        # convert all locks into their real forms
        lock_list = []
        for access in self.locks:
            if not isinstance(access, locks.LockAccess):
                # Buildbot 0.7.7 compability: user did not specify access
                access = access.defaultAccess()
            lock = self.builder.botmaster.getLockByID(access.lockid)
            lock_list.append((lock, access))
        self.locks = lock_list
        # then narrow SlaveLocks down to the right slave
        self.locks = [(l.getLock(self.slavebuilder), la)
                      for l, la in self.locks]
        self.remote = slavebuilder.remote
        self.remote.notifyOnDisconnect(self.lostRemote)
        d = self.deferred = defer.Deferred()

        def _release_slave(res, slave, bs):
            self.slavebuilder.buildFinished()
            slave.updateSlaveStatus(buildFinished=bs)
            return res

        d.addCallback(_release_slave, self.slavebuilder.slave, build_status)

        try:
            self.setupBuild(expectations)  # create .steps
        except:
            # the build hasn't started yet, so log the exception as a point
            # event instead of flunking the build. TODO: associate this
            # failure with the build instead. this involves doing
            # self.build_status.buildStarted() from within the exception
            # handler
            log.msg("Build.setupBuild failed")
            log.err(Failure())
            self.builder.builder_status.addPointEvent(
                ["setupBuild", "exception"], color="purple")
            self.finished = True
            self.results = FAILURE
            self.deferred = None
            d.callback(self)
            return d

        self.acquireLocks().addCallback(self._startBuild_2)
        return d

    def acquireLocks(self, res=None):
        log.msg("acquireLocks(step %s, locks %s)" % (self, self.locks))
        if not self.locks:
            return defer.succeed(None)
        for lock, access in self.locks:
            if not lock.isAvailable(access):
                log.msg("Build %s waiting for lock %s" % (self, lock))
                d = lock.waitUntilMaybeAvailable(self, access)
                d.addCallback(self.acquireLocks)
                return d
        # all locks are available, claim them all
        for lock, access in self.locks:
            lock.claim(self, access)
        return defer.succeed(None)

    def _startBuild_2(self, res):
        self.build_status.buildStarted(self)
        self.startNextStep()

    def setupBuild(self, expectations):
        # create the actual BuildSteps. If there are any name collisions, we
        # add a count to the loser until it is unique.
        self.steps = []
        self.stepStatuses = {}
        stepnames = []
        sps = []

        for factory, args in self.stepFactories:
            args = args.copy()
            try:
                step = factory(**args)
            except:
                log.msg("error while creating step, factory=%s, args=%s" %
                        (factory, args))
                raise
            step.setBuild(self)
            step.setBuildSlave(self.slavebuilder.slave)
            step.setDefaultWorkdir(self.workdir)
            name = step.name
            count = 1
            # LOCAL MOZILLA PATCH:
            # buildbotcustom.process.factory.ReleaseTaggingFactory uses
            # more than 100 ShellCommands when it runs - this has been bumped up
            # to support that. upstream buildbot bug here:
            # http://buildbot.net/trac/ticket/366
            while name in stepnames and count < 1000:
                count += 1
                name = step.name + "_%d" % count
            if name in stepnames:
                raise RuntimeError("duplicate step '%s'" % step.name)
            step.name = name
            stepnames.append(name)
            self.steps.append(step)

            # tell the BuildStatus about the step. This will create a
            # BuildStepStatus and bind it to the Step.
            step_status = self.build_status.addStepWithName(name)
            step.setStepStatus(step_status)

            sp = None
            if self.useProgress:
                # XXX: maybe bail if step.progressMetrics is empty? or skip
                # progress for that one step (i.e. "it is fast"), or have a
                # separate "variable" flag that makes us bail on progress
                # tracking
                sp = step.setupProgress()
            if sp:
                sps.append(sp)

        # Create a buildbot.status.progress.BuildProgress object. This is
        # called once at startup to figure out how to build the long-term
        # Expectations object, and again at the start of each build to get a
        # fresh BuildProgress object to track progress for that individual
        # build. TODO: revisit at-startup call

        if self.useProgress:
            self.progress = BuildProgress(sps)
            if self.progress and expectations:
                self.progress.setExpectationsFrom(expectations)

        # we are now ready to set up our BuildStatus.
        self.build_status.setSourceStamp(self.source)
        self.build_status.setReason(self.reason)
        self.build_status.setBlamelist(self.blamelist())
        self.build_status.setProgress(self.progress)

        self.results = []  # list of FAILURE, SUCCESS, WARNINGS, SKIPPED
        self.result = SUCCESS  # overall result, may downgrade after each step
        self.text = []  # list of text string lists (text2)

    def getNextStep(self):
        """This method is called to obtain the next BuildStep for this build.
        When it returns None (or raises a StopIteration exception), the build
        is complete."""
        if not self.steps:
            return None
        if self.terminate:
            while True:
                s = self.steps.pop(0)
                if s.alwaysRun:
                    return s
                if not self.steps:
                    return None
        else:
            return self.steps.pop(0)

    def startNextStep(self):
        try:
            s = self.getNextStep()
        except StopIteration:
            s = None
        if not s:
            return self.allStepsDone()
        self.currentStep = s
        d = defer.maybeDeferred(s.startStep, self.remote)
        d.addCallback(self._stepDone, s)
        d.addErrback(self.buildException)

    def _stepDone(self, results, step):
        self.currentStep = None
        if self.finished:
            return  # build was interrupted, don't keep building
        terminate = self.stepDone(results, step)  # interpret/merge results
        if terminate:
            self.terminate = True
        return self.startNextStep()

    def stepDone(self, result, step):
        """This method is called when the BuildStep completes. It is passed a
        status object from the BuildStep and is responsible for merging the
        Step's results into those of the overall Build."""

        terminate = False
        text = None
        if type(result) == types.TupleType:
            result, text = result
        assert type(result) == type(SUCCESS)
        log.msg(" step '%s' complete: %s" % (step.name, Results[result]))
        self.results.append(result)
        if text:
            self.text.extend(text)
        if not self.remote:
            terminate = True
        if result == FAILURE:
            if step.warnOnFailure:
                if self.result != FAILURE:
                    self.result = WARNINGS
            if step.flunkOnFailure:
                self.result = FAILURE
            if step.haltOnFailure:
                self.result = FAILURE
                terminate = True
        elif result == WARNINGS:
            if step.warnOnWarnings:
                if self.result != FAILURE:
                    self.result = WARNINGS
            if step.flunkOnWarnings:
                self.result = FAILURE
        elif result == EXCEPTION:
            self.result = EXCEPTION
            terminate = True
        return terminate

    def lostRemote(self, remote=None):
        # the slave went away. There are several possible reasons for this,
        # and they aren't necessarily fatal. For now, kill the build, but
        # TODO: see if we can resume the build when it reconnects.
        log.msg("%s.lostRemote" % self)
        self.remote = None
        if self.currentStep:
            # this should cause the step to finish.
            log.msg(" stopping currentStep", self.currentStep)
            self.currentStep.interrupt(Failure(error.ConnectionLost()))

    def stopBuild(self, reason="<no reason given>"):
        # the idea here is to let the user cancel a build because, e.g.,
        # they realized they committed a bug and they don't want to waste
        # the time building something that they know will fail. Another
        # reason might be to abandon a stuck build. We want to mark the
        # build as failed quickly rather than waiting for the slave's
        # timeout to kill it on its own.

        log.msg(" %s: stopping build: %s" % (self, reason))
        if self.finished:
            return
        # TODO: include 'reason' in this point event
        self.builder.builder_status.addPointEvent(['interrupt'])
        self.currentStep.interrupt(reason)
        if 0:
            # TODO: maybe let its deferred do buildFinished
            if self.currentStep and self.currentStep.progress:
                # XXX: really .fail or something
                self.currentStep.progress.finish()
            text = ["stopped", reason]
            self.buildFinished(text, "red", FAILURE)

    def allStepsDone(self):
        if self.result == FAILURE:
            color = "red"
            text = ["failed"]
        elif self.result == WARNINGS:
            color = "orange"
            text = ["warnings"]
        elif self.result == EXCEPTION:
            color = "purple"
            text = ["exception"]
        else:
            color = "green"
            text = ["build", "successful"]
        text.extend(self.text)
        return self.buildFinished(text, color, self.result)

    def buildException(self, why):
        log.msg("%s.buildException" % self)
        log.err(why)
        self.buildFinished(["build", "exception"], "purple", FAILURE)

    def buildFinished(self, text, color, results):
        """This method must be called when the last Step has completed. It
        marks the Build as complete and returns the Builder to the 'idle'
        state.

        It takes three arguments which describe the overall build status:
        text, color, results. 'results' is one of SUCCESS, WARNINGS, or
        FAILURE.

        If 'results' is SUCCESS or WARNINGS, we will permit any dependant
        builds to start. If it is 'FAILURE', those builds will be
        abandoned."""

        self.finished = True
        if self.remote:
            self.remote.dontNotifyOnDisconnect(self.lostRemote)
        self.results = results

        log.msg(" %s: build finished" % self)
        self.build_status.setText(text)
        self.build_status.setColor(color)
        self.build_status.setResults(results)
        self.build_status.buildFinished()
        if self.progress:
            # XXX: also test a 'timing consistent' flag?
            log.msg(" setting expectations for next time")
            self.builder.setExpectations(self.progress)
        reactor.callLater(0, self.releaseLocks)
        self.deferred.callback(self)
        self.deferred = None

    def releaseLocks(self):
        log.msg("releaseLocks(%s): %s" % (self, self.locks))
        for lock, access in self.locks:
            lock.release(self, access)

    # IBuildControl

    def getStatus(self):
        return self.build_status
Beispiel #19
0
class DummyFolder(DummyObject):
    """Dummy Container for testing.
    """
    implements(IObjectManager)

    def __init__(self, id='dummy', fake_product=0, prefix=''):
        self._prefix = prefix
        self._id = id

        if fake_product:
            self.manage_addProduct = {
                'FooProduct': DummyFactoryDispatcher(self)
            }

    def _setOb(self, id, object):
        setattr(self, id, object)

    def _delOb(self, id):
        delattr(self, id)

    def _getOb(self, id):
        return getattr(self, id)

    def _setObject(self, id, object):
        notify(ObjectWillBeAddedEvent(object, self, id))
        self._setOb(id, object)
        object = self._getOb(id)
        if hasattr(aq_base(object), 'manage_afterAdd'):
            object.manage_afterAdd(object, self)
        notify(ObjectAddedEvent(object, self, id))
        notifyContainerModified(self)
        return object

    def _delObject(self, id):
        object = self._getOb(id)
        notify(ObjectWillBeRemovedEvent(object, self, id))
        if hasattr(aq_base(object), 'manage_beforeDelete'):
            object.manage_beforeDelete(object, self)
        self._delOb(id)
        notify(ObjectRemovedEvent(object, self, id))
        notifyContainerModified(self)

    def getPhysicalPath(self):
        p = aq_parent(aq_inner(self))
        path = (self._id, )
        if p is not None:
            path = p.getPhysicalPath() + path
        return path

    def getId(self):
        return self._id

    def reindexObjectSecurity(self):
        pass

    def contentIds(self):
        return ('user_bar', )

    def all_meta_types(self):
        return ({'name': 'Dummy', 'permission': 'addFoo'}, )

    def getTypeInfo(self):
        return self.portal_types.getTypeInfo(self)  # Can return None.
Beispiel #20
0
class BaseReportableFactory(ETLBaseReportableFactory):
    implements(IReportableFactory)
    adapts(ZenModelRM)

    class_context = None

    def set_class_context(self, class_):
        self.class_context = class_

    def exports(self):
        context_reportable = IReportable(self.context)
        if self.class_context and hasattr(context_reportable,
                                          'set_class_context'):
            context_reportable.set_class_context(self.class_context)

        yield context_reportable

        if hasattr(context_reportable, 'export_as_bases'):
            # The idea here is to give the abiliity to export something both as
            # itself, but also as a more generic type (one of its base classes).
            # For example, an OpenStack Endpoint is both an openstack endpoint
            # and a Device.  Therefore I would like it to end up in both
            # dim_openstack_endpoint and dim_device.

            for class_ in context_reportable.export_as_bases:
                if class_ == self.class_context:
                    # no need to re-export as ourself..
                    continue

                reportable_factory_class = adapter_for_class(
                    class_, IReportableFactory)
                reportable_class = adapter_for_class(class_, IReportable)

                # The problem is that normally, a Reportable or ReportableFactory
                # does not know what class it is adapting.  It therefore tends
                # to rely on the model object to tell it what to export, and
                # most of the reportables export all properties and relationships
                # of the supplied object.
                #
                # In this situation, though, we want to export, say, an Endpoint
                # as if it was a Device, and therefore to only export the
                # properties and relationships defined in the Device class.
                #
                # The only way to make this work is to introduce the idea of
                # class-context to Reportable (and ReportableFactory).
                #
                # A class-context-aware Reportable or ReportableFactory has
                # an additional method, set_class_context(), which is passed
                # a class object.
                #
                # The default behavior is still the same- if set_class_context
                # has not been used, the reportable should behave as it does
                # today.
                #
                # However, in this specific situation (export_as_bases), if a
                # class-context-aware ReportableFactory is available, I will
                # use it (and expect it to pass that class context on to the
                # reportables it generates).
                #
                # Otherwise, I will create the single reportable directly, not
                # using any reportablefactory, because I can't trust the
                # an existing factory that doesn't realize that it's dealing
                # with a base class, not the actual object class, to not
                # duplicate all the exports I have already done.
                factory = reportable_factory_class(self.context)

                if hasattr(reportable_factory_class, 'set_class_context'):
                    factory.set_class_context(class_)
                    for export in factory.exports():
                        yield export
                else:
                    yield reportable_class(self.context)

        relations = getattr(self.context, '_relations', tuple())
        for relName, relation in relations:
            if isinstance(relation, ToMany) and \
               issubclass(relation.remoteType, ToMany):

                # For a many-many relationship, we need to implement a
                # reportable to represent the relationship, if we're
                # on the proper end of it.  Really, either end will work,
                # but we need something deterministic, so just go with
                # whichever end has the alphabetically earliest relname.
                if min(relation.remoteName, relName) == relName:
                    related = getattr(self.context, relName, None)
                    if related:
                        related = related()

                    entity_class_name = "%s_to_%s" % (
                        IReportable(self.context).entity_class_name,
                        un_camel(
                            importClass(relation.remoteClass, None).meta_type))

                    for remoteObject in related:
                        yield BaseManyToManyReportable(
                            fromObject=self.context,
                            toObject=remoteObject,
                            entity_class_name=entity_class_name)
        if hasattr(self.context, 'os') \
                and hasattr(self.context.os, 'software') \
                and isinstance(self.context, Device):
            for sw in chain((self.context.os, ), self.context.os.software()):
                yield IReportable(sw)
Beispiel #21
0
class PressReleaseListing(ListingView):
    implements(IFullWidth)

    def __init__(self, context, request):
        super(PressReleaseListing, self).__init__(context, request)
        properties = api.portal.get_tool('portal_properties')
        self.osha_json_url = getattr(
            properties.site_properties,
            'osha_json_url',
            'https://osha.europa.eu/'
        )
        self.remote_press_release_query_tags = getattr(
            properties.site_properties,
            'remote_press_release_query_tags',
            'Campaign%202012-13'
        )

    def results(self, collection, batch=True, b_start=0, b_size=None,
                sort_on=None, limit=None, brains=False):
        # XXX This code is from plone.app.contenttypes.content.py, we need this
        # here until my pull request is merged.
        # https://github.com/plone/plone.app.contenttypes/pull/87
        querybuilder = QueryBuilder(collection, self.request)
        sort_order = 'reverse' if collection.sort_reversed else 'ascending'
        if not b_size:
            b_size = collection.item_count
        if not sort_on:
            sort_on = collection.sort_on
        if not limit:
            limit = collection.limit
        return querybuilder(
            query=collection.query, batch=batch, b_start=b_start, b_size=b_size,
            sort_on=sort_on, sort_order=sort_order,
            limit=limit, brains=brains
        )

    @ram.cache(ListingView.cache_for_minutes(10, 'pressrelease'))
    def get_remote_press_releases(self):
        """ Queries the OSHA corporate site for press releases.
            Items returned in JSON format.
        """
        params = {
            "base_url": self.osha_json_url,
            "lang": api.portal.get_tool("portal_languages").getPreferredLanguage(),
            "query_tags": self.remote_press_release_query_tags,
        }
        qurl = "{base_url}/{lang}/services/hw/pr/{query_tags}".format(**params)
        print qurl
        result = urlopen(qurl)
        items = []
        if result.code == 200:
            json = load(result)
            for node in json.get("nodes"):
                item = node.get("node")
                pd = item.get('publication_date', '')
                items.append({
                    'remote_item': True,
                    'Title': item['title'],
                    'Date': (
                        pd and DateTime(pd, datefmt="international").strftime(
                            "%Y/%m/%d %H:%M") or ""),
                    'getURL': item.get('path'),
                    'Description': item.get('summary', ''),
                    'text': self.make_intro(item.get('body')),
                    'remote_image': item.get('image', ''),
                    'node_id': item.get('nid'),
                })
        return items

    @ram.cache(ListingView.cache_for_minutes(10, 'pressrelease'))
    def get_local_press_releases(self):
        """ Looks in the current folder for Collection objects and then queries
            them for items.
        """
        items = []
        for child in self.context.values():
            if ICollection.providedBy(child):
                items = self.results(
                    child,
                    batch=False,
                    sort_on='Date',
                    brains=True)
        return items

    def get_all_press_releases(self):
        items = self.get_remote_press_releases() + \
            list(self.get_local_press_releases())
        return sorted(
            items,
            key=lambda item: item.__getitem__('Date'),
            reverse=True
        )

    def get_batched_press_releases(self):
        b_size = int(self.request.get('b_size', 20))
        b_start = int(self.request.get('b_start', 0))
        items = self.get_all_press_releases()
        for i in range(b_start, b_size):
            if i >= len(items):
                break
            if ICatalogBrain.providedBy(items[i]):
                item = items[i]
                obj = item.getObject()
                blob = getattr(obj.image, '_blob', None)
                plain_text = obj.restrictedTraverse('@@text-transform/text/text/plain')
                items[i] = {
                    'Title': item.Title,
                    'Date': DateTime(item.Date).utcdatetime(),
                    'getURL': item.getURL(),
                    'Description': item.Description,
                    'image': blob and base64.encodestring(blob.open().read()) or None,
                    'obj': obj,
                    'text': self.make_intro(plain_text),
                }
            else:
                items[i]['Date'] = DateTime(items[i]['Date']).utcdatetime()
        return Batch(items, b_size, b_start, orphan=1)

    def make_plain_text(self, item):
        text = item.get('text')
        if not text:
            return ''

        transformer = ITransformer(self.context)
        value = RichTextValue(text, mimeType=item.get('_text_mime_type', 'text/html'))
        return transformer(value, 'text/plain')

    def make_intro(self, text):
        if len(text) < 200:
            return text

        text = text[:200].rsplit(None, 1)[0]
        return text + u'...'
Beispiel #22
0
class Document(PortalContent, DefaultDublinCoreImpl):
    """A Document - Handles both StructuredText and HTML.
    """

    implements(IMutableDocument, IDocument, IDAVAware)

    effective_date = expiration_date = None
    cooked_text = text = text_format = ''
    _size = 0

    _stx_level = 1  # Structured text level
    _rest_level = getConfiguration().rest_header_level  # comes from zope.conf
    rest_available = REST_AVAILABLE

    _last_safety_belt_editor = ''
    _last_safety_belt = ''
    _safety_belt = ''

    security = ClassSecurityInfo()

    def __init__(self, id, title='', description='', text_format='', text=''):
        DefaultDublinCoreImpl.__init__(self)
        self.id = id
        self.title = title
        self.description = description
        self.setFormat(text_format)
        self._edit(text)

    security.declareProtected(ModifyPortalContent, 'manage_edit')
    manage_edit = DTMLFile('zmi_editDocument', _dtmldir)

    security.declareProtected(ModifyPortalContent, 'manage_editDocument')

    def manage_editDocument(self, text, text_format, file='', REQUEST=None):
        """ A ZMI (Zope Management Interface) level editing method """
        Document.edit(self, text_format=text_format, text=text, file=file)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(
                self.absolute_url() + '/manage_edit' +
                '?manage_tabs_message=Document+updated')

    def _edit(self, text):
        """ Edit the Document and cook the body.
        """
        self._size = len(text)

        text_format = self.text_format
        if not text_format:
            text_format = self.text_format

        if text_format != 'html':
            normalizer = queryUtility(ILinebreakNormalizer)

            if normalizer is not None:
                self.text = normalizer.normalizeIncoming(self, text)
            else:
                self.text = text
        else:
            self.text = text

        if text_format == 'html':
            self.cooked_text = text
        elif text_format == 'plain':
            self.cooked_text = html_quote(text).replace('\n', '<br />')
        elif text_format == 'restructured-text':
            self.cooked_text = ReST(text,
                                    initial_header_level=self._rest_level)
        else:
            self.cooked_text = stx2html(text, level=self._stx_level, header=0)

    #
    #   IMutableDocument method
    #

    security.declareProtected(ModifyPortalContent, 'edit')

    def edit(self, text_format, text, file='', safety_belt=''):
        """ Update the document.

        To add webDav support, we need to check if the content is locked, and if
        so return ResourceLockedError if not, call _edit.

        Note that this method expects to be called from a web form, and so
        disables header processing
        """
        self.failIfLocked()
        if not self._safety_belt_update(safety_belt=safety_belt):
            msg = _(u'Intervening changes from elsewhere detected. '
                    u'Please refetch the document and reapply your changes. '
                    u'(You may be able to recover your version using the '
                    u"browser 'back' button, but will have to apply them to "
                    u'a freshly fetched copy.)')
            raise EditingConflict(msg)
        if file and (type(file) is not type('')):
            contents = file.read()
            if contents:
                text = contents
        if html_headcheck(text) and text_format.lower() != 'plain':
            text = bodyfinder(text)
        self.setFormat(text_format)
        self._edit(text)
        self.reindexObject()

    security.declareProtected(ModifyPortalContent, 'setMetadata')

    def setMetadata(self, headers):
        headers['Format'] = self.Format()
        new_subject = keywordsplitter(headers)
        headers['Subject'] = new_subject or self.Subject()
        new_contrib = contributorsplitter(headers)
        headers['Contributors'] = new_contrib or self.Contributors()
        for key, value in self.getMetadataHeaders():
            if not key in headers:
                headers[key] = value
        self._editMetadata(
            title=headers['Title'],
            subject=headers['Subject'],
            description=headers['Description'],
            contributors=headers['Contributors'],
            effective_date=headers['Effective_date'],
            expiration_date=headers['Expiration_date'],
            format=headers['Format'],
            language=headers['Language'],
            rights=headers['Rights'],
        )

    security.declarePrivate('guessFormat')

    def guessFormat(self, text):
        """ Simple stab at guessing the inner format of the text """
        if html_headcheck(text): return 'html'
        else: return 'structured-text'

    security.declarePrivate('handleText')

    def handleText(self, text, format=None, stx_level=None):
        """ Handles the raw text, returning headers, body, format """
        headers = {}
        if not format:
            format = self.guessFormat(text)
        if format == 'html':
            parser = SimpleHTMLParser()
            parser.feed(text)
            headers.update(parser.metatags)
            if parser.title:
                headers['Title'] = parser.title
            body = bodyfinder(text)
        else:
            headers, body = parseHeadersBody(text, headers)
            if stx_level:
                self._stx_level = stx_level
        return headers, body, format

    security.declarePublic('getMetadataHeaders')

    def getMetadataHeaders(self):
        """Return RFC-822-style header spec."""
        hdrlist = DefaultDublinCoreImpl.getMetadataHeaders(self)
        hdrlist.append(('SafetyBelt', self._safety_belt))
        return hdrlist

    security.declarePublic('SafetyBelt')

    def SafetyBelt(self):
        """Return the current safety belt setting.
        For web form hidden button."""
        return self._safety_belt

    security.declarePrivate('isValidSafetyBelt')

    def isValidSafetyBelt(self, safety_belt):
        """Check validity of safety belt.
        """
        if not safety_belt:
            # we have no safety belt value
            return True
        if self._safety_belt is None:
            # the current object has no safety belt (ie - freshly made)
            return True
        if safety_belt == self._safety_belt:
            # the safety belt does match the current one
            return True
        this_user = getSecurityManager().getUser().getId()
        if ((safety_belt == self._last_safety_belt)
                and (this_user == self._last_safety_belt_editor)):
            # safety belt and user match last safety belt and user
            return True
        return False

    security.declarePrivate('updateSafetyBelt')

    def updateSafetyBelt(self, safety_belt):
        """Update safety belt tracking.
        """
        this_user = getSecurityManager().getUser().getId()
        self._last_safety_belt_editor = this_user
        self._last_safety_belt = safety_belt
        self._safety_belt = str(self._p_mtime)

    def _safety_belt_update(self, safety_belt=''):
        """Check validity of safety belt and update tracking if valid.

        Return 0 if safety belt is invalid, 1 otherwise.

        Note that the policy is deliberately lax if no safety belt value is
        present - "you're on your own if you don't use your safety belt".

        When present, either the safety belt token:
         - ... is the same as the current one given out, or
         - ... is the same as the last one given out, and the person doing the
           edit is the same as the last editor."""

        if not self.isValidSafetyBelt(safety_belt):
            return 0
        self.updateSafetyBelt(safety_belt)
        return 1

    ### Content accessor methods

    #
    #   IContentish method
    #

    security.declareProtected(View, 'SearchableText')

    def SearchableText(self):
        """ Used by the catalog for basic full text indexing """
        return "%s %s %s" % (self.Title(), self.Description(),
                             self.EditableBody())

    #
    #   IDocument methods
    #

    security.declareProtected(View, 'CookedBody')

    def CookedBody(self, stx_level=None, setlevel=0, rest_level=None):
        """ Get the "cooked" (ready for presentation) form of the text.

        The prepared basic rendering of an object.  For Documents, this
        means pre-rendered structured text, or what was between the
        <BODY> tags of HTML.

        If the format is html, and 'stx_level' or 'rest_level' are not 
        passed in or is the same as the object's current settings, return 
        the cached cooked text.  Otherwise, recook.  If we recook and 
        'setlevel' is true, then set the recooked text and stx_level or 
        rest_level on the object.
        """
        if ((self.text_format == 'html' or self.text_format == 'plain' or
             (stx_level is None) or (stx_level == self._stx_level)) and
            ((rest_level is None) or (rest_level == self._rest_level))):
            return self.cooked_text
        elif rest_level is not None:
            cooked = ReST(self.text, initial_header_level=rest_level)
            if setlevel:
                self._rest_level = rest_level
                self.cooked_text = cooked
            return cooked
        else:
            cooked = stx2html(self.text, level=stx_level, header=0)
            if setlevel:
                self._stx_level = stx_level
                self.cooked_text = cooked
            return cooked

    security.declareProtected(View, 'EditableBody')

    def EditableBody(self):
        """ Get the "raw" (as edited) form of the text.

        The editable body of text.  This is the raw structured text, or
        in the case of HTML, what was between the <BODY> tags.
        """
        return self.text

    #
    #   IDublinCore method
    #

    security.declareProtected(View, 'Format')

    def Format(self):
        """ Dublin Core Format element - resource format.
        """
        if self.text_format == 'html':
            return 'text/html'
        else:
            return 'text/plain'

    #
    #   IMutableDublinCore method
    #

    security.declareProtected(ModifyPortalContent, 'setFormat')

    def setFormat(self, format):
        """ Set text format and Dublin Core resource format.
        """
        value = str(format)
        old_value = self.text_format
        text_formats = ('structured-text', 'plain', 'restructured-text')

        if value == 'text/html' or value == 'html':
            self.text_format = 'html'
        elif value == 'text/plain':
            if self.text_format not in text_formats:
                self.text_format = 'structured-text'
        elif value == 'plain':
            self.text_format = 'plain'
        elif value == 'restructured-text':
            self.text_format = 'restructured-text'
        else:
            self.text_format = 'structured-text'

        # Did the format change? We might need to re-cook the content.
        if value != old_value:
            if html_headcheck(self.text) and value != 'plain':
                self.text = bodyfinder(self.text)

            self._edit(self.text)

    ## FTP handlers
    security.declareProtected(ModifyPortalContent, 'PUT')

    def PUT(self, REQUEST, RESPONSE):
        """ Handle HTTP (and presumably FTP?) PUT requests """
        self.dav__init(REQUEST, RESPONSE)
        self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1)

        try:
            self.failIfLocked()
        except ResourceLockedError, msg:
            transaction.abort()
            RESPONSE.setStatus(423)
            return RESPONSE

        body = REQUEST.get('BODY', '')
        if REQUEST.get_header('Content-Type', '') == 'text/html':
            format = 'html'
        else:
            format = None
        headers, body, format = self.handleText(body, format)

        safety_belt = headers.get('SafetyBelt', '')
        if not self._safety_belt_update(safety_belt):
            # XXX Can we get an error msg through?  Should we be raising an
            #     exception, to be handled in the FTP mechanism?  Inquiring
            #     minds...
            transaction.abort()
            RESPONSE.setStatus(450)
            return RESPONSE

        self.setFormat(format)
        self.setMetadata(headers)
        self._edit(body)
        RESPONSE.setStatus(204)
        self.reindexObject()
        return RESPONSE
Beispiel #23
0
class AnchoreServiceMaker(object):
    implements(IServiceMaker, IPlugin)
    tapname = "anchore-catalog"
    servicenames = ["catalog"]
    description = "Anchore Container Image Scanner Service: " + ','.join(
        servicenames)
    options = Options

    def makeService(self, options):
        slist = []

        try:
            configfile = os.path.join(options['config'], 'config.yaml')
            config = localconfig.read_config(configfile=configfile)
        except Exception as err:
            log.err("cannot load local configuration: " + str(err))
            raise err

        log_level = 'INFO'
        log_to_db = False
        if 'log_level' in config:
            log_level = config['log_level']
        if 'log_to_db' in config:
            log_to_db = config['log_to_db']

        slist = self.servicenames

        try:
            config_services = config['services']

            isEnabled = False
            for sname in slist:
                if 'log_level' in config_services[sname]:
                    log_level = config_services[sname]['log_level']

                if config_services[sname]['enabled']:
                    isEnabled = True
                    break

            if not isEnabled:
                log.err("no services in list (" + str(self.servicenames) +
                        ") are enabled in configuration file: shutting down")
                sys.exit(0)

        except Exception as err:
            log.err(
                "error checking for enabled services, check config file - exception: "
                + str(err))
            raise Exception(
                "error checking for enabled services, check config file - exception: "
                + str(err))

        try:
            logger.set_log_level(log_level, log_to_db=log_to_db)
        except Exception as err:
            log.err("exception while initializing logger - exception: " +
                    str(err))
            logger.set_log_level('INFO')

        r = anchore_engine.services.common.makeService(slist,
                                                       options,
                                                       bootstrap_db=True,
                                                       bootstrap_users=True)
        return (r)
Beispiel #24
0
class ActionInformation(SimpleItem):
    """ Represent a single selectable action.

    Actions generate links to views of content, or to specific methods
    of the site.  They can be filtered via their conditions.
    """

    implements(IAction)

    __allow_access_to_unprotected_subobjects__ = 1

    security = ClassSecurityInfo()

    def __init__(self,
                 id,
                 title='',
                 description='',
                 category='object',
                 condition='',
                 permissions=(),
                 priority=10,
                 visible=True,
                 action=''):
        """ Set up an instance.
        """
        self.edit(id, title, description, category, condition, permissions,
                  priority, visible, action)

    security.declarePrivate('edit')

    def edit(self,
             id=_unchanged,
             title=_unchanged,
             description=_unchanged,
             category=_unchanged,
             condition=_unchanged,
             permissions=_unchanged,
             priority=_unchanged,
             visible=_unchanged,
             action=_unchanged):
        """Edit the specified properties.
        """

        if id is not _unchanged:
            self.id = id
        if title is not _unchanged:
            self.title = title
        if description is not _unchanged:
            self.description = description
        if category is not _unchanged:
            self.category = category
        if condition is not _unchanged:
            if condition and isinstance(condition, basestring):
                condition = Expression(condition)
            self.condition = condition
        if permissions is not _unchanged:
            if permissions == ('', ):
                permissions = ()
            self.permissions = permissions
        if priority is not _unchanged:
            self.priority = priority
        if visible is not _unchanged:
            self.visible = visible
        if action is not _unchanged:
            if action and isinstance(action, basestring):
                action = Expression(action)
            self.setActionExpression(action)

    security.declareProtected(View, 'Title')

    def Title(self):
        """ Return the Action title.
        """
        return self.title or self.getId()

    security.declareProtected(View, 'Description')

    def Description(self):
        """ Return a description of the action.
        """
        return self.description

    security.declarePrivate('testCondition')

    def testCondition(self, ec):
        """ Evaluate condition using context, 'ec', and return 0 or 1.
        """
        if self.condition:
            return bool(self.condition(ec))
        else:
            return True

    security.declarePublic('getAction')

    def getAction(self, ec):
        """ Compute the action using context, 'ec'; return a mapping of
            info about the action.
        """
        return ActionInfo(self, ec)

    security.declarePrivate('_getActionObject')

    def _getActionObject(self):
        """ Find the action object, working around name changes.
        """
        action = getattr(self, 'action', None)

        if action is None:  # Forward compatibility, used to be '_action'
            action = getattr(self, '_action', None)
            if action is not None:
                self.action = self._action
                del self._action

        return action

    security.declarePublic('getActionExpression')

    def getActionExpression(self):
        """ Return the text of the TALES expression for our URL.
        """
        action = self._getActionObject()
        expr = action and action.text or ''
        if expr and isinstance(expr, basestring):
            if (not expr.startswith('string:')
                    and not expr.startswith('python:')):
                expr = 'string:${object_url}/%s' % expr
                self.action = Expression(expr)
        return expr

    security.declarePrivate('setActionExpression')

    def setActionExpression(self, action):
        if action and isinstance(action, basestring):
            if (not action.startswith('string:')
                    and not action.startswith('python:')):
                action = 'string:${object_url}/%s' % action
            action = Expression(action)
        self.action = action

    security.declarePublic('getCondition')

    def getCondition(self):
        """ Return the text of the TALES expression for our condition.
        """
        return getattr(self, 'condition', None) and self.condition.text or ''

    security.declarePublic('getPermissions')

    def getPermissions(self):
        """ Return the permission, if any, required to execute the action.

        Return an empty tuple if no permission is required.
        """
        return self.permissions

    security.declarePublic('getCategory')

    def getCategory(self):
        """ Return the category in which the action should be grouped.
        """
        return self.category or 'object'

    security.declarePublic('getVisibility')

    def getVisibility(self):
        """ Return whether the action should be visible in the CMF UI.
        """
        return bool(self.visible)

    security.declarePrivate('getMapping')

    def getMapping(self):
        """ Get a mapping of this object's data.
        """
        return {
            'id':
            self.id,
            'title':
            self.title or self.id,
            'description':
            self.description,
            'category':
            self.category or 'object',
            'condition':
            getattr(self, 'condition', None) and self.condition.text or '',
            'permissions':
            self.permissions,
            'visible':
            bool(self.visible),
            'action':
            self.getActionExpression()
        }

    security.declarePrivate('clone')

    def clone(self):
        """ Get a newly-created AI just like us.
        """
        return self.__class__(priority=self.priority, **self.getMapping())

    security.declarePrivate('getInfoData')

    def getInfoData(self):
        """ Get the data needed to create an ActionInfo.
        """
        lazy_keys = []
        lazy_map = self.getMapping()

        if lazy_map['action']:
            lazy_map['url'] = self._getActionObject()
            lazy_keys.append('url')
        else:
            lazy_map['url'] = ''
        del lazy_map['action']

        if lazy_map['condition']:
            lazy_map['available'] = self.testCondition
            lazy_keys.append('available')
        else:
            lazy_map['available'] = True
        del lazy_map['condition']

        return (lazy_map, lazy_keys)
Beispiel #25
0
class FolderView(BikaListingView):

    implements(IFolderContentsView, IViewView)

    template = ViewPageTemplateFile("../templates/worksheets.pt")

    def __init__(self, context, request):
        super(FolderView, self).__init__(context, request)
        self.catalog = 'bika_catalog'
        self.contentFilter = {
            'portal_type': 'Worksheet',
            'review_state': ['open', 'to_be_verified', 'verified', 'rejected'],
            'sort_on': 'id',
            'sort_order': 'reverse'
        }
        self.context_actions = {
            _('Add'): {
                'url': 'worksheet_add',
                'icon': '++resource++bika.lims.images/add.png',
                'class': 'worksheet_add'
            }
        }
        self.show_table_only = False
        self.show_sort_column = False
        self.show_select_row = False
        self.show_select_all_checkbox = True
        self.show_select_column = True
        self.pagesize = 25
        self.restrict_results = False

        request.set('disable_border', 1)

        self.icon = self.portal_url + "/++resource++bika.lims.images/worksheet_big.png"
        self.title = self.context.translate(_("Worksheets"))
        self.description = ""

        pm = getToolByName(context, "portal_membership")
        # this is a property of self, because self.getAnalysts returns it
        self.analysts = getUsers(self, ['Manager', 'LabManager', 'Analyst'])
        self.analysts = self.analysts.sortedByKey()

        bsc = getToolByName(context, 'bika_setup_catalog')
        templates = [
            t for t in bsc(portal_type='WorksheetTemplate',
                           inactive_state='active')
        ]

        self.templates = [(t.UID, t.Title) for t in templates]
        self.templates.sort(lambda x, y: cmp(x[1], y[1]))

        self.instruments = [
            (i.UID, i.Title)
            for i in bsc(portal_type='Instrument', inactive_state='active')
        ]
        self.instruments.sort(lambda x, y: cmp(x[1], y[1]))

        self.templateinstruments = {}
        for t in templates:
            i = t.getObject().getInstrument()
            if i:
                self.templateinstruments[t.UID] = i.UID()
            else:
                self.templateinstruments[t.UID] = ''

        self.columns = {
            'Title': {
                'title': _('Worksheet'),
                'index': 'sortable_title'
            },
            'Priority': {
                'title': _('Priority'),
                'index': 'Priority',
                'toggle': True
            },
            'Analyst': {
                'title': _('Analyst'),
                'index': 'getAnalyst',
                'toggle': True
            },
            'Template': {
                'title': _('Template'),
                'toggle': True
            },
            'Services': {
                'title': _('Services'),
                'sortable': False,
                'toggle': False
            },
            'SampleTypes': {
                'title': _('Sample Types'),
                'sortable': False,
                'toggle': False
            },
            'Instrument': {
                'title': _('Instrument'),
                'sortable': False,
                'toggle': False
            },
            'QC': {
                'title': _('QC'),
                'sortable': False,
                'toggle': False
            },
            'QCTotals': {
                'title': _('QC Samples (Analyses)'),
                'sortable': False,
                'toggle': False
            },
            'RoutineTotals': {
                'title': _('Routine Samples (Analyses)'),
                'sortable': False,
                'toggle': False
            },
            'CreationDate': {
                'title': PMF('Date Created'),
                'toggle': True,
                'index': 'created'
            },
            'state_title': {
                'title': _('State'),
                'index': 'review_state'
            },
        }
        self.review_states = [
            {
                'id':
                'default',
                'title':
                _('All'),
                'contentFilter': {
                    'portal_type': 'Worksheet',
                    'review_state': ['open', 'to_be_verified', 'verified'],
                    'sort_on': 'id',
                    'sort_order': 'reverse'
                },
                'transitions': [{
                    'id': 'retract'
                }, {
                    'id': 'verify'
                }, {
                    'id': 'reject'
                }],
                'columns': [
                    'Title', 'Priority', 'Analyst', 'Template', 'Services',
                    'SampleTypes', 'Instrument', 'QC', 'QCTotals',
                    'RoutineTotals', 'CreationDate', 'state_title'
                ]
            },
            # getAuthenticatedMember does not work in __init__
            # so 'mine' is configured further in 'folderitems' below.
            {
                'id':
                'mine',
                'title':
                _('Mine'),
                'contentFilter': {
                    'portal_type':
                    'Worksheet',
                    'review_state':
                    ['open', 'to_be_verified', 'verified', 'rejected'],
                    'sort_on':
                    'id',
                    'sort_order':
                    'reverse'
                },
                'transitions': [{
                    'id': 'retract'
                }, {
                    'id': 'verify'
                }, {
                    'id': 'reject'
                }],
                'columns': [
                    'Title', 'Priority', 'Analyst', 'Template', 'Services',
                    'SampleTypes', 'Instrument', 'QC', 'QCTotals',
                    'RoutineTotals', 'CreationDate', 'state_title'
                ]
            },
            {
                'id':
                'open',
                'title':
                _('Open'),
                'contentFilter': {
                    'portal_type': 'Worksheet',
                    'review_state': 'open',
                    'sort_on': 'id',
                    'sort_order': 'reverse'
                },
                'transitions': [],
                'columns': [
                    'Title', 'Priority', 'Analyst', 'Template', 'Services',
                    'SampleTypes', 'Instrument', 'QC', 'QCTotals',
                    'RoutineTotals', 'CreationDate', 'state_title'
                ]
            },
            {
                'id':
                'to_be_verified',
                'title':
                _('To be verified'),
                'contentFilter': {
                    'portal_type': 'Worksheet',
                    'review_state': 'to_be_verified',
                    'sort_on': 'id',
                    'sort_order': 'reverse'
                },
                'transitions': [{
                    'id': 'retract'
                }, {
                    'id': 'verify'
                }, {
                    'id': 'reject'
                }],
                'columns': [
                    'Title', 'Priority', 'Analyst', 'Template', 'Services',
                    'SampleTypes', 'Instrument', 'QC', 'QCTotals',
                    'RoutineTotals', 'CreationDate', 'state_title'
                ]
            },
            {
                'id':
                'verified',
                'title':
                _('Verified'),
                'contentFilter': {
                    'portal_type': 'Worksheet',
                    'review_state': 'verified',
                    'sort_on': 'id',
                    'sort_order': 'reverse'
                },
                'transitions': [],
                'columns': [
                    'Title', 'Priority', 'Analyst', 'Template', 'Services',
                    'SampleTypes', 'Instrument', 'QC', 'QCTotals',
                    'RoutineTotals', 'CreationDate', 'state_title'
                ]
            },
        ]

    def __call__(self):
        self.wf = getToolByName(self, 'portal_workflow')
        self.rc = getToolByName(self, REFERENCE_CATALOG)
        self.pm = getToolByName(self.context, "portal_membership")

        if not self.isManagementAllowed():
            # The current has no prvileges to manage WS.
            # Remove the add button
            self.context_actions = {}

        self.member = self.pm.getAuthenticatedMember()
        roles = self.member.getRoles()
        self.restrict_results = 'Manager' not in roles \
                and 'LabManager' not in roles \
                and 'LabClerk' not in roles \
                and 'RegulatoryInspector' not in roles \
                and self.context.bika_setup.getRestrictWorksheetUsersAccess()
        if self.restrict_results == True:
            # Remove 'Mine' button and hide 'Analyst' column
            del self.review_states[1]  # Mine
            self.columns['Analyst']['toggle'] = False

        self.can_manage = self.pm.checkPermission(ManageWorksheets,
                                                  self.context)
        self.selected_state = self.request.get(
            "%s_review_state" % self.form_id, 'default')

        self.analyst_choices = []
        for a in self.analysts:
            self.analyst_choices.append({
                'ResultValue': a,
                'ResultText': self.analysts.getValue(a)
            })

        self.allow_edit = self.isEditionAllowed()

        # Default value for this attr
        self.can_reassign = False

        return super(FolderView, self).__call__()

    def isManagementAllowed(self):
        mtool = getToolByName(self.context, 'portal_membership')
        return mtool.checkPermission(ManageWorksheets, self.context)

    def isEditionAllowed(self):
        pm = getToolByName(self.context, "portal_membership")
        checkPermission = self.context.portal_membership.checkPermission
        return checkPermission(EditWorksheet, self.context)

    def isItemAllowed(self, obj):
        """
        Only show "my" worksheets
        this cannot be setup in contentFilter,
        because AuthenticatedMember is not available in __init__
        It also checks if the worksheet can be added to the list depending
        on the department filter. It checks the department of each analysis
        service from each analysis belonguing to the given worksheet.
        If department filtering is disabled in bika_setup, will return True.
        @Obj: it is a worksheet object.
        @return: boolean
        """
        if self.selected_state == 'mine' or self.restrict_results == True:
            analyst = obj.getAnalyst().strip()
            if analyst != _c(self.member.getId()):
                return False
        if not self.context.bika_setup.getAllowDepartmentFiltering():
            return True
        # Gettin the department from worksheet
        deps = [
            an.getDepartment().UID() for an in obj.getWorksheetServices()
            if an.getDepartment()
        ]
        result = True
        if deps:
            # Getting the cookie value
            cookie_dep_uid = self.request.get('filter_by_department_info', '')
            # Comparing departments' UIDs
            deps_uids = set(deps)
            filter_uids = set(cookie_dep_uid.split(','))
            matches = deps_uids & filter_uids
            result = len(matches) > 0
        return result

    def folderitem(self, obj, item, index):
        # Additional info from Worksheet to be added in the item generated by
        # default by bikalisting.

        # Call the folderitem method from the base class
        item = BikaListingView.folderitem(self, obj, item, index)
        if not item:
            return None

        item['CreationDate'] = self.ulocalized_time(obj.creation_date)
        item['Analyst'] = obj.getAnalyst().strip()
        item['Priority'] = ''
        item['getPriority'] = ''

        instrument = obj.getInstrument()
        item['Instrument'] = instrument.Title() if instrument else ''

        wst = obj.getWorksheetTemplate()
        item['Template'] = wst.Title() if wst else ''
        if wst:
            item['replace']['Template'] = "<a href='%s'>%s</a>" % \
                (wst.absolute_url(), wst.Title())

        if len(obj.getAnalyses()) == 0:
            item['table_row_class'] = 'state-empty-worksheet'

        layout = obj.getLayout()
        item['Title'] = obj.Title()
        turl = "manage_results" if len(layout) > 0 else "add_analyses"
        item['replace']['Title'] = "<a href='%s/%s'>%s</a>" % \
            (item['url'], turl, item['Title'])

        # Set services
        ws_services = {}
        for slot in [s for s in layout if s['type'] == 'a']:
            analysis = self.rc.lookupObject(slot['analysis_uid'])
            if not analysis:
                error = "Analysis with uid '%s' NOT FOUND in Reference Catalog.\n Worksheet: '%s'. Layout: '%s'" % \
                        (slot['analysis_uid'], obj, layout)
                logging.info(error)
                continue
            service = analysis.getService()
            title = service.Title()
            if title not in ws_services:
                ws_services[title] = "<a href='%s'>%s</a>" % \
                    (service.absolute_url(), title)
        keys = list(ws_services.keys())
        keys.sort()
        services = [ws_services[k] for k in keys]
        item['Services'] = ""
        item['replace']['Services'] = ", ".join(services)

        pos_parent = {}
        for slot in layout:
            # compensate for bad data caused by a stupid bug.
            if type(slot['position']) in (list, tuple):
                slot['position'] = slot['position'][0]
            if slot['position'] == 'new':
                continue
            if slot['position'] in pos_parent:
                continue
            pos_parent[slot['position']] = self.rc.lookupObject(
                slot['container_uid'])

        # Set Sample Types and QC Samples
        sampletypes = []
        qcsamples = []
        for container in pos_parent.values():
            if container.portal_type == 'AnalysisRequest':
                sampletype = "<a href='%s'>%s</a>" % \
                           (container.getSample().getSampleType().absolute_url(),
                            container.getSample().getSampleType().Title())
                sampletypes.append(sampletype)
            if container.portal_type == 'ReferenceSample':
                qcsample = "<a href='%s'>%s</a>" % \
                        (container.absolute_url(),
                         container.Title())
                qcsamples.append(qcsample)

        sampletypes = list(set(sampletypes))
        sampletypes.sort()
        item['SampleTypes'] = ""
        item['replace']['SampleTypes'] = ", ".join(sampletypes)
        qcsamples = list(set(qcsamples))
        qcsamples.sort()
        item['QC'] = ""
        item['replace']['QC'] = ", ".join(qcsamples)
        item['QCTotals'] = ''

        # Total QC Samples (Total Routine Analyses)
        analyses = obj.getAnalyses()
        totalQCAnalyses = [
            a for a in analyses if a.portal_type == 'ReferenceAnalysis'
            or a.portal_type == 'DuplicateAnalysis'
        ]
        totalQCSamples = [a.getSample().UID() for a in totalQCAnalyses]
        totalQCSamples = list(set(totalQCSamples))
        item['QCTotals'] = str(len(totalQCSamples)) + ' (' + str(
            len(totalQCAnalyses)) + ')'

        # Total Routine Samples (Total Routine Analyses)
        totalRoutineAnalyses = [
            a for a in analyses if a not in totalQCAnalyses
        ]
        totalRoutineSamples = [
            a.getSample().UID() for a in totalRoutineAnalyses
        ]
        totalRoutineSamples = list(set(totalRoutineSamples))
        item['RoutineTotals'] = str(len(totalRoutineSamples)) + ' (' + str(
            len(totalRoutineAnalyses)) + ')'

        if item['review_state'] == 'open' \
            and self.allow_edit \
            and self.restrict_results == False \
            and self.can_manage == True:
            item['allow_edit'] = [
                'Analyst',
            ]
            item['required'] = [
                'Analyst',
            ]
            item['choices'] = {'Analyst': self.analyst_choices}
            self.can_reassign = True

        return item

    def folderitems(self):
        items = BikaListingView.folderitems(self)

        # can_reassigned value is assigned in folderitem(obj,item,index) function
        if self.can_reassign:
            for x in range(len(self.review_states)):
                if self.review_states[x]['id'] in ['default', 'mine', 'open']:
                    self.review_states[x]['custom_actions'] = [
                        {
                            'id': 'reassign',
                            'title': _('Reassign')
                        },
                    ]

        self.show_select_column = self.can_reassign
        self.show_workflow_action_buttons = self.can_reassign

        return items

    def getClients(self):
        """Present a list of client titles for the Template Client dropdown
        This allows a template to select analyses from only a single client
        """
        pc = getToolByName(self.context, 'portal_catalog')
        return [
            c.Title for c in pc(portal_type='Client',
                                inactive_state='active',
                                sort_on='sortable_title')
        ]

    def getAnalysts(self):
        """ Present the LabManagers and Analysts as options for analyst
            Used in bika_listing.pt
        """
        return self.analysts

    def getWorksheetTemplates(self):
        """ List of templates
            Used in bika_listing.pt
        """
        return DisplayList(self.templates)

    def getInstruments(self):
        """ List of instruments
            Used in bika_listing.pt
        """
        return DisplayList(self.instruments)

    def getTemplateInstruments(self):
        """ Distionary of instruments per template
            Used in bika_listing.pt
        """
        return json.dumps(self.templateinstruments)
class EntryProducer(object):
    """A push producer for log entries."""
    implements(iweb.IBodyProducer)

    def __init__(self, handler, reactor, uri, start, end, batch_size):
        self._handler = handler
        self._reactor = reactor
        self._uri = uri
        self._consumer = None

        assert 0 <= start <= end
        self._start = start
        self._end = end
        self._current = self._start
        self._batch_size = batch_size
        # Required attribute of the interface.
        self.length = iweb.UNKNOWN_LENGTH

    @property
    def finished(self):
        return self._current > self._end

    def _response_eb(self, result):
        self.stopProducing()
        self._done.errback(result)

    def _write_pending(self):
        if self._pending:
            self._current += len(self._pending)
            self._consumer.write(self._pending)
            self._pending = None

    @defer.deferredGenerator
    def produce(self):
        """Produce entries."""
        while not self._paused:
            self._write_pending()

            if self.finished:
                self.stopProducing()
                self._done.callback(self._end - self._start + 1)
                return

            # Currently, a naive strategy is used where each response determines
            # the next request. An optimized strategy interleaving two queries
            # would likely better fill the pipeline.
            first = self._current
            last = min(self._current + self._batch_size - 1, self._end)

            deferred_response = self._handler.get(
                self._uri + "/" + _GET_ENTRIES_PATH,
                params={"start": str(first), "end": str(last)})
            deferred_response.addCallback(_parse_entries, last - first + 1)
            deferred_response.addErrback(self._response_eb)

            wfd = defer.waitForDeferred(deferred_response)
            # Pause here until the body of the response is available.
            yield wfd
            # The producer may have been paused while waiting for the response,
            # or errored out upon receiving it: do not write the entries out
            # until after the next self._paused check.
            self._pending = wfd.getResult()

    def startProducing(self, consumer):
        """Start producing entries.

        The producer writes EntryResponse protos to the consumer in batches,
        until all entries have been received, or an error occurs.

        Args:
            consumer: the consumer to write to.

        Returns:
           a deferred that fires when no more entries will be written.
           Upon success, this deferred fires with the total number of entries
           produced. Upon failure, this deferred fires with the appropriate
           HTTPError.

        Raises:
            RuntimeError: consumer already registered.
        """
        if self._consumer:
            raise RuntimeError("Producer already has a consumer registered")
        self._consumer = consumer
        self._stopped = False
        self._paused = True
        self._pending = None
        self._done = defer.Deferred()
        # An IBodyProducer should start producing immediately, without waiting
        # for an explicit resumeProducing() call.
        task.deferLater(self._reactor, 0, self.resumeProducing)
        return self._done

    def pauseProducing(self):
        self._paused = True

    def resumeProducing(self):
        if self._paused and not self._stopped:
            self._paused = False
            self.produce()

    def stopProducing(self):
        self._paused = True
        self._stopped = True
Beispiel #27
0
class EditIRI(BaseEditIRI, SWORDTreatmentMixin, Explicit):
    """ This extends the SWORD v 2.0 Deposit Receipt to:
        - List role requests.
        - Show whether the license has been signed by the author and all
            contributors.
        - What contributors (see above: author, editor, etc), still need
            to accept their roles on the document.
        - Show whether all required metadata has been provided (including
            the ‘description-of-changes’ if this is a new version of
            existing content).

        TODO:
        Decide how to handle differences between "In-Progress: true" and
        "In-Progress: false" HTTP headers.
    """
    __name__ = "edit"
    implements(ISWORDEditIRI)

    depositreceipt = ViewPageTemplateFile('depositreceipt.pt')

    def __init__(self, context, request):
        BaseEditIRI.__init__(self, context, request)
        SWORDTreatmentMixin.__init__(self, context, request)
        Explicit.__init__(self)

    def _handleGet(self, **kw):
        view = self.__of__(self.context)
        pt = self.depositreceipt.__of__(view)
        return pt(**kw)

    def _handlePublish(self):
        context = aq_inner(self.context)
        if context.state == 'published':
            raise Unpublishable, "Module already published"

        # Call transaction.savepoint() to make _p_jar appear on
        # persistent objects, otherwise the object has a blank _p_jar
        # and cannot be moved. And if it cannot be moved it cannot be
        # published.
        transaction.savepoint(optimistic=True)

        requirements = self.get_publication_requirements(context)
        if not requirements:
            context.publishContent(message=context.message)
        else:
            raise PublishUnauthorized(
                "You do not have permission to publish this module",
                "<br />\n".join(requirements))

    def _handlePost(self):
        """ A POST fo the Edit-IRI can do one of two things. You can either add
            more metadata by posting an atom entry, you can add more data and
            metadata with a multipart post, or you can publish the module with
            an empty request and In-Progress set to false.
        """
        context = aq_inner(self.context)
        content_type = self.request.get_header('Content-Type', '')
        content_type = getContentType(content_type)

        if content_type in ATOMPUB_CONTENT_TYPES:
            # Apply more metadata to the item
            adapter = getMultiAdapter((context.aq_parent, self.request),
                                      IRhaptosWorkspaceSwordAdapter)

            body = self.request.get('BODYFILE')
            body.seek(0)
            if context.state == 'published':
                context.checkout(self.context.objectId)
            adapter.updateMetadata(context, parse(body))
        elif content_type.startswith('multipart/'):
            checkUploadSize(context, self.request.stdin)
            atom_dom, payload, payload_type = splitMultipartRequest(
                self.request)

            cksum = self.request.get_header('Content-MD5')
            merge = self.request.get_header('Update-Semantics')
            adapter = getMultiAdapter((context.aq_parent, self.request),
                                      IRhaptosWorkspaceSwordAdapter)

            if context.state == 'published':
                context.checkout(self.context.objectId)

            adapter.updateMetadata(context, atom_dom)
            adapter.updateContent(
                context, StringIO(payload), payload_type, cksum,
                merge == 'http://purl.org/oerpub/semantics/Merge')
            context.logAction(adapter.action)
        elif content_type:
            # A content type is provided, and its not atom+xml or multipart
            raise BadRequest(
                "You cannot POST content of type %s to the SE-IRI" %
                content_type)

        # If In-Progress is set to false or omitted, try to publish
        in_progress = self.request.get_header('In-Progress', 'false')
        if in_progress == 'false':
            self._handlePublish()
            # We SHOULD return a deposit receipt, status code 200, and the
            # Edit-IRI in the Location header.
            self.request.response.setHeader(
                'Location', '%s/sword' % context.absolute_url())
            self.request.response.setStatus(200)

        view = context.unrestrictedTraverse('@@sword')
        return view._handleGet()

    def _handlePut(self):
        """ PUT against an existing item should update it.
        """
        content_type = self.request.get_header('Content-Type')
        if content_type is None:
            raise BadRequest("You have no Content-Type header in your request")
        content_type = getContentType(content_type)

        if content_type in ATOMPUB_CONTENT_TYPES or \
          content_type.startswith('multipart/'):
            # If the module is published, do a transparent checkout
            if self.context.state == 'published':
                self.context.checkout(self.context.objectId)

            merge = self.request.get_header(
                'Update-Semantics') and True or False
            parent = self.context.aq_inner.aq_parent
            adapter = getMultiAdapter((parent, self.request),
                                      IRhaptosWorkspaceSwordAdapter)

            if content_type.startswith('multipart/'):
                atom_dom, payload, payload_type = splitMultipartRequest(
                    self.request)
                checkUploadSize(self.context, payload)

                # Update Content
                cksum = self.request.get_header('Content-MD5')
                adapter.updateContent(self.context, StringIO(payload),
                                      payload_type, cksum, merge)
                self.context.logAction(adapter.action)
            else:
                body = self.request.get('BODYFILE')
                checkUploadSize(self.context, body)
                atom_dom = parse(body)

            # update Metadata
            if merge:
                # merge the metadata on the request with what is on the
                # module (in this case 'self.context')
                adapter.mergeMetadata(self.context, atom_dom)
            else:
                # replace what is on the module with metadata on the request
                # in the process all fields not on the request will be reset
                # on the module (see METADATA_DEFAULTS) for the values used.
                adapter.replaceMetadata(self.context, atom_dom)

            # If In-Progress is set to false or omitted, try to publish
            if self.request.get_header('In-Progress', 'false') == 'false':
                self._handlePublish()

            # response code of 200 as required by SWORD spec:
            self.request.response.setStatus(200)
            # set the location header
            self.request.response.setHeader(
                'Location', '%s/sword' % self.context.absolute_url())

            view = self.__of__(self.context)
            pt = self.depositreceipt.__of__(view)
            return pt()
        else:
            # This will result in a 400 error
            raise ValueError(
                "%s is not a valid content type for this request" %
                content_type)

    def treatment(self):
        return self.get_treatment(self.context)
Beispiel #28
0
class Status(service.ReconfigurableServiceMixin, service.AsyncMultiService):
    implements(interfaces.IStatus)

    def __init__(self):
        service.AsyncMultiService.__init__(self)
        self.watchers = []
        # No default limit to the log size
        self.logMaxSize = None

        self._builder_observers = bbcollections.KeyedSets()
        self._buildreq_observers = bbcollections.KeyedSets()
        self._buildset_finished_waiters = bbcollections.KeyedSets()
        self._buildset_completion_sub = None
        self._buildset_sub = None
        self._build_request_sub = None
        self._change_sub = None

    @property
    def botmaster(self):
        return self.master.botmaster

    @property
    def workers(self):
        return self.master.workers

    @property
    def basedir(self):
        return self.master.basedir

    # service management

    @defer.inlineCallbacks
    def startService(self):
        # subscribe to the things we need to know about
        self._buildset_new_consumer = yield self.master.mq.startConsuming(
            self.bs_new_consumer_cb, ('buildsets', None, 'new'))
        self._buildset_complete_consumer = yield self.master.mq.startConsuming(
            self.bs_complete_consumer_cb, ('buildsets', None, 'complete'))
        self._br_consumer = yield self.master.mq.startConsuming(
            self.br_consumer_cb, ('buildrequests', None, 'new'))
        self._change_consumer = yield self.master.mq.startConsuming(
            self.change_consumer_cb, ('changes', None, 'new'))

        yield service.AsyncMultiService.startService(self)

    @defer.inlineCallbacks
    def reconfigServiceWithBuildbotConfig(self, new_config):
        # remove the old listeners, then add the new
        for sr in list(self):
            yield sr.disownServiceParent()

        for sr in new_config.status:
            yield sr.setServiceParent(self)

        # reconfig any newly-added change sources, as well as existing
        yield service.ReconfigurableServiceMixin.reconfigServiceWithBuildbotConfig(
            self, new_config)

    def stopService(self):
        if self._buildset_complete_consumer:
            self._buildset_complete_consumer.stopConsuming()
            self._buildset_complete_consumer = None

        if self._buildset_new_consumer:
            self._buildset_new_consumer.stopConsuming()
            self._buildset_new_consumer = None

        if self._change_consumer:
            self._change_consumer.stopConsuming()
            self._change_consumer = None

        return service.AsyncMultiService.stopService(self)

    # clean shutdown

    @property
    def shuttingDown(self):
        return self.botmaster.shuttingDown

    def cleanShutdown(self):
        return self.botmaster.cleanShutdown()

    def cancelCleanShutdown(self):
        return self.botmaster.cancelCleanShutdown()

    # methods called by our clients

    def getTitle(self):
        return self.master.config.title

    def getTitleURL(self):
        return self.master.config.titleURL

    def getBuildbotURL(self):
        return self.master.config.buildbotURL

    def getStatus(self):
        # some listeners expect their .parent to be a BuildMaster object, and
        # use this method to get the Status object.  This is documented, so for
        # now keep it working.
        return self

    def getMetrics(self):
        return self.master.metrics

    def getURLForBuild(self, builderid, build_number):
        prefix = self.getBuildbotURL()
        return prefix + "#builders/%d/builds/%d" % (builderid, build_number)

    def _getURLForBuildWithBuildername(self, builder_name, build_number):
        # dont use this API. this URL is not supported
        # its here waiting for getURLForThing removal or switch to deferred
        prefix = self.getBuildbotURL()
        return prefix + "#builders/%s/builds/%d" % (urlquote(
            builder_name, safe=''), build_number)

    def getURLForBuildrequest(self, buildrequestid):
        prefix = self.getBuildbotURL()
        return prefix + "#buildrequests/%d" % (buildrequestid, )

    def getURLForThing(self, thing):
        prefix = self.getBuildbotURL()
        if not prefix:
            return None
        if interfaces.IStatus.providedBy(thing):
            return prefix
        if interfaces.ISchedulerStatus.providedBy(thing):
            pass
        if interfaces.IBuilderStatus.providedBy(thing):
            bldr = thing
            return prefix + "#builders/%s" % (urlquote(bldr.getName(),
                                                       safe=''), )
        if interfaces.IBuildStatus.providedBy(thing):
            build = thing
            bldr = build.getBuilder()
            # should be:
            # builderid = yield bldr.getBuilderId()
            # return self.getURLForBuild(self, builderid, build.getNumber())
            return self._getURLForBuildWithBuildername(bldr.getName(),
                                                       build.getNumber())

        if interfaces.IBuildStepStatus.providedBy(thing):
            step = thing
            build = step.getBuild()
            bldr = build.getBuilder()
            return prefix + "#builders/%s/builds/%d/steps/%s" % (urlquote(
                bldr.getName(),
                safe=''), build.getNumber(), urlquote(step.getName(), safe=''))
        # IBuildSetStatus
        # IBuildRequestStatus
        # IWorkerStatus
        if interfaces.IWorkerStatus.providedBy(thing):
            worker = thing
            return prefix + "#buildslaves/%s" % (urlquote(worker.getName(),
                                                          safe=''), )

        # IStatusEvent
        if interfaces.IStatusEvent.providedBy(thing):
            # TODO: this is goofy, create IChange or something
            if isinstance(thing, changes.Change):
                change = thing
                return "%s#changes/%d" % (prefix, change.number)

    def getChangeSources(self):
        return list(self.master.change_svc)

    def getChange(self, number):
        """Get a Change object; returns a deferred"""
        d = self.master.db.changes.getChange(number)

        @d.addCallback
        def chdict2change(chdict):
            if not chdict:
                return None
            return changes.Change.fromChdict(self.master, chdict)

        return d

    def getSchedulers(self):
        return self.master.allSchedulers()

    def getBuilderNames(self, tags=None, categories=None):
        if categories is not None:
            # Categories is deprecated; pretend they said "tags".
            tags = categories

        if tags is None:
            return util.naturalSort(
                self.botmaster.builderNames)  # don't let them break it

        l = []
        # respect addition order
        for name in self.botmaster.builderNames:
            bldr = self.getBuilder(name)
            if bldr.matchesAnyTag(tags):
                l.append(name)
        return util.naturalSort(l)

    def getBuilder(self, name):
        """
        @rtype: L{BuilderStatus}
        """
        return self.botmaster.builders[name].builder_status

    def getWorkerNames(self):
        return list(iteritems(self.workers.workers))

    def getWorker(self, workername):
        return self.workers.workers[workername].worker_status

    def getBuildSets(self):
        d = self.master.db.buildsets.getBuildsets(complete=False)

        @d.addCallback
        def make_status_objects(bsdicts):
            return [
                buildset.BuildSetStatus(bsdict, self) for bsdict in bsdicts
            ]

        return d

    def generateFinishedBuilds(self,
                               builders=None,
                               branches=None,
                               num_builds=None,
                               finished_before=None,
                               max_search=200):
        if builders is None:
            builders = []

        if branches is None:
            branches = []

        def want_builder(bn):
            if builders:
                return bn in builders
            return True

        builder_names = [
            bn for bn in self.getBuilderNames() if want_builder(bn)
        ]

        # 'sources' is a list of generators, one for each Builder we're
        # using. When the generator is exhausted, it is replaced in this list
        # with None.
        sources = []
        for bn in builder_names:
            bldr = self.getBuilder(bn)
            g = bldr.generateFinishedBuilds(branches,
                                            finished_before=finished_before,
                                            max_search=max_search)
            sources.append(g)

        # next_build the next build from each source
        next_build = [None] * len(sources)

        def refill():
            for i, g in enumerate(sources):
                if next_build[i]:
                    # already filled
                    continue
                if not g:
                    # already exhausted
                    continue
                try:
                    next_build[i] = next(g)
                except StopIteration:
                    next_build[i] = None
                    sources[i] = None

        got = 0
        while True:
            refill()
            # find the latest build among all the candidates
            candidates = [(i, b, b.getTimes()[1])
                          for i, b in enumerate(next_build) if b is not None]
            candidates.sort(lambda x, y: cmp(x[2], y[2]))
            if not candidates:
                return

            # and remove it from the list
            i, build, finshed_time = candidates[-1]
            next_build[i] = None
            got += 1
            yield build
            if num_builds is not None:
                if got >= num_builds:
                    return

    def subscribe(self, target):
        self.watchers.append(target)
        for name in self.botmaster.builderNames:
            self.announceNewBuilder(target, name, self.getBuilder(name))

    def unsubscribe(self, target):
        self.watchers.remove(target)

    # methods called by upstream objects
    def announceNewBuilder(self, target, name, builder_status):
        t = target.builderAdded(name, builder_status)
        if t:
            builder_status.subscribe(t)

    def builderAdded(self, name, basedir, tags=None, description=None):
        """
        @rtype: L{BuilderStatus}
        """
        filename = os.path.join(self.basedir, basedir, "builder")
        log.msg("trying to load status pickle from %s" % filename)
        builder_status = None
        try:
            with open(filename, "rb") as f:
                builder_status = pickle.load(f)
            builder_status.master = self.master

            # (bug #1068) if we need to upgrade, we probably need to rewrite
            # this pickle, too.  We determine this by looking at the list of
            # Versioned objects that have been unpickled, and (after doUpgrade)
            # checking to see if any of them set wasUpgraded.  The Versioneds'
            # upgradeToVersionNN methods all set this.
            versioneds = styles.versionedsToUpgrade
            styles.doUpgrade()
            if True in [
                    hasattr(o, 'wasUpgraded') for o in itervalues(versioneds)
            ]:
                log.msg("re-writing upgraded builder pickle")
                builder_status.saveYourself()

        except IOError:
            log.msg("no saved status pickle, creating a new one")
        except Exception:
            log.err("error while loading status pickle, creating a new one")
        if not builder_status:
            builder_status = builder.BuilderStatus(name, tags, self.master,
                                                   description)
            builder_status.addPointEvent(["builder", "created"])
        log.msg("added builder %s with tags %r" % (name, tags))
        # an unpickled object might not have tags set from before,
        # so set it here to make sure
        builder_status.setTags(tags)
        builder_status.description = description
        builder_status.master = self.master
        builder_status.basedir = os.path.join(self.basedir, basedir)
        builder_status.name = name  # it might have been updated
        builder_status.status = self

        if not os.path.isdir(builder_status.basedir):
            os.makedirs(builder_status.basedir)
        builder_status.determineNextBuildNumber()

        builder_status.setBigState("offline")

        for t in self.watchers:
            self.announceNewBuilder(t, name, builder_status)

        return builder_status

    def builderRemoved(self, name):
        for t in self.watchers:
            if hasattr(t, 'builderRemoved'):
                t.builderRemoved(name)

    def workerConnected(self, name):
        for t in self.watchers:
            if hasattr(t, 'workerConnected'):
                t.workerConnected(name)

    def workerDisconnected(self, name):
        for t in self.watchers:
            if hasattr(t, 'workerDisconnected'):
                t.workerDisconnected(name)

    def workerPaused(self, name):
        for t in self.watchers:
            if hasattr(t, 'workerPaused'):
                t.workerPaused(name)

    def workerUnpaused(self, name):
        for t in self.watchers:
            if hasattr(t, 'workerUnpaused'):
                t.workerUnpaused(name)

    def changeAdded(self, change):
        for t in self.watchers:
            if hasattr(t, 'changeAdded'):
                t.changeAdded(change)

    @defer.inlineCallbacks
    def br_consumer_cb(self, key, msg):
        builderid = msg['builderid']
        buildername = None
        # convert builderid to buildername
        for b in itervalues(self.botmaster.builders):
            if builderid == (yield b.getBuilderId()):
                buildername = b.name
                break
        if buildername in self._builder_observers:
            brs = buildrequest.BuildRequestStatus(buildername,
                                                  msg['buildrequestid'], self)
            for observer in self._builder_observers[buildername]:
                if hasattr(observer, 'requestSubmitted'):
                    eventually(observer.requestSubmitted, brs)

    @defer.inlineCallbacks
    def change_consumer_cb(self, key, msg):
        # get a list of watchers - no sense querying the change
        # if nobody's listening
        interested = [t for t in self.watchers if hasattr(t, 'changeAdded')]
        if not interested:
            return

        chdict = yield self.master.db.changes.getChange(msg['changeid'])
        change = yield changes.Change.fromChdict(self.master, chdict)

        for t in interested:
            t.changeAdded(change)

    def asDict(self):
        result = {
            # Constant
            'title': self.getTitle(),
            'titleURL': self.getTitleURL(),
            'buildbotURL': self.getBuildbotURL(),
            # TODO: self.getSchedulers()
            # self.getChangeSources()
        }
        return result

    def build_started(self, brid, buildername, build_status):
        if brid in self._buildreq_observers:
            for o in self._buildreq_observers[brid]:
                eventually(o, build_status)

    def _buildrequest_subscribe(self, brid, observer):
        self._buildreq_observers.add(brid, observer)

    def _buildrequest_unsubscribe(self, brid, observer):
        self._buildreq_observers.discard(brid, observer)

    def _buildset_waitUntilFinished(self, bsid):
        d = defer.Deferred()
        self._buildset_finished_waiters.add(bsid, d)
        self._maybeBuildsetFinished(bsid)
        return d

    def _maybeBuildsetFinished(self, bsid):
        # check bsid to see if it's successful or finished, and notify anyone
        # who cares
        if bsid not in self._buildset_finished_waiters:
            return
        d = self.master.db.buildsets.getBuildset(bsid)

        @d.addCallback
        def do_notifies(bsdict):
            bss = buildset.BuildSetStatus(bsdict, self)
            if bss.isFinished():
                for d in self._buildset_finished_waiters.pop(bsid):
                    eventually(d.callback, bss)

        d.addErrback(log.err, 'while notifying for buildset finishes')

    def _builder_subscribe(self, buildername, watcher):
        # should get requestSubmitted and requestCancelled
        self._builder_observers.add(buildername, watcher)

    def _builder_unsubscribe(self, buildername, watcher):
        self._builder_observers.discard(buildername, watcher)

    def bs_new_consumer_cb(self, key, msg):
        bsid = msg['bsid']
        d = self.master.db.buildsets.getBuildset(bsid)

        @d.addCallback
        def do_notifies(bsdict):
            bss = buildset.BuildSetStatus(bsdict, self)
            for t in self.watchers:
                if hasattr(t, 'buildsetSubmitted'):
                    t.buildsetSubmitted(bss)

        return d

    def bs_complete_consumer_cb(self, key, msg):
        self._maybeBuildsetFinished(msg['bsid'])
Beispiel #29
0
class ManageItemAssemblyForm(form.Form):
    """
      This form will help MeetingManagers manage itemAssembly
      by being able to redefine it on a single
      item without having to use the edit form and to apply
      redefined value until the item number he wants.
    """
    implements(IFieldsAndContentProvidersForm)

    fields = field.Fields(IManageItemAssembly)
    ignoreContext = True  # don't use context to get widget data

    contentProviders = ContentProviders()
    contentProviders['assembly'] = DisplayAssemblyFromMeetingProvider
    contentProviders['assembly'].position = 0
    contentProviders['excused'] = DisplayExcusedFromMeetingProvider
    contentProviders['excused'].position = 2
    contentProviders['absents'] = DisplayAbsentsFromMeetingProvider
    contentProviders['absents'].position = 2

    label = _(u"Manage item assembly")
    description = u''
    _finished = False

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.label = translate('Manage item assembly',
                               domain='PloneMeeting',
                               context=self.request)

    @button.buttonAndHandler(_('Apply'), name='apply_item_assembly')
    def handleApplyItemAssembly(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        # do adapt item assembly
        self.item_assembly = data.get('item_assembly')
        self.item_excused = data.get('item_excused')
        self.item_absents = data.get('item_absents')
        self.item_guests = data.get('item_guests')
        # we receive '5' or '5.2' but we want 500 or 502
        self.apply_until_item_number = \
            _itemNumber_to_storedItemNumber(
                data.get('apply_until_item_number') or u'0'
            )
        self.meeting = self.context.getMeeting()
        self._doApplyItemAssembly()

    @button.buttonAndHandler(_('Cancel'), name='cancel')
    def handleCancel(self, action):
        self._finished = True

    def _check_auth(self):
        """Raise Unauthorized if current user can not manage itemAssembly."""
        if not self.context.mayQuickEditItemAssembly():
            raise Unauthorized

    def update(self):
        """ """
        self._check_auth()
        super(ManageItemAssemblyForm, self).update()
        # after calling parent's update, self.actions are available
        self.actions.get('cancel').addClass('standalone')

    def updateWidgets(self):
        # XXX manipulate self.fields BEFORE doing form.Form.updateWidgets
        # show only relevant fields
        tool = api.portal.get_tool('portal_plonemeeting')
        cfg = tool.getMeetingConfig(self.context)
        usedMeetingAttributes = cfg.getUsedMeetingAttributes()
        self.fields['item_assembly'].mode = 'hidden'
        self.fields['item_excused'].mode = 'hidden'
        self.fields['item_absents'].mode = 'hidden'
        self.fields['item_guests'].mode = 'hidden'
        changeItemAssemblyTitleAndDescr = False
        # this form is also used to edit only 'guests' when using attendees
        # manage also when switching from assembly to attendees
        # "assembly" field may be disabled but assembly used on meeting
        if 'assembly' in usedMeetingAttributes or \
                self.context.getItemAssembly():
            self.fields['item_assembly'].mode = 'input'
        if 'assembly_excused' in usedMeetingAttributes or \
                self.context.getItemAssemblyExcused():
            changeItemAssemblyTitleAndDescr = True
            self.fields['item_excused'].mode = 'input'
        if 'assembly_absents' in usedMeetingAttributes or \
                self.context.getItemAssemblyAbsents():
            changeItemAssemblyTitleAndDescr = True
            self.fields['item_absents'].mode = 'input'
        if 'assembly_guests' in usedMeetingAttributes or \
                self.context.getItemAssemblyGuests():
            changeItemAssemblyTitleAndDescr = True
            self.fields['item_guests'].mode = 'input'
        if changeItemAssemblyTitleAndDescr:
            self.fields['item_assembly'].field.title = \
                _('Item attendees to apply')
            self.fields['item_assembly'].field.description = \
                _(USING_ABSENTS_OR_EXCUSED_MSGID)
        else:
            self.fields['item_assembly'].field.title = \
                _('Item assembly to apply')
            self.fields['item_assembly'].field.description = \
                _(USING_ONLY_ASSEMBLY_MSGID)
        form.Form.updateWidgets(self)

    def render(self):
        if self._finished:
            IRedirect(self.request).redirect(self.context.absolute_url())
            return ""
        return super(ManageItemAssemblyForm, self).render()

    def _doApplyItemAssembly(self):
        """
          The method actually do the job, set the itemAssembly on self.context
          and following items if defined
        """
        self._check_auth()
        # only update if default proposed value was changed
        item_assembly_def = item_assembly_default()
        item_excused_def = item_excused_default()
        item_absents_def = item_absents_default()
        item_guests_def = item_guests_default()
        from_item_number = self.context.getItemNumber(relativeTo='meeting')
        until_item_number = self.apply_until_item_number
        items_to_update = _itemsToUpdate(
            from_item_number=from_item_number,
            until_item_number=until_item_number,
            meeting=self.meeting)
        for itemToUpdate in items_to_update:
            # only update if we changed default value
            if self.item_assembly != item_assembly_def:
                itemToUpdate.setItemAssembly(self.item_assembly)
            if self.item_excused != item_excused_def:
                itemToUpdate.setItemAssemblyExcused(self.item_excused)
            if self.item_absents != item_absents_def:
                itemToUpdate.setItemAssemblyAbsents(self.item_absents)
            if self.item_guests != item_guests_def:
                itemToUpdate.setItemAssemblyGuests(self.item_guests)
            notifyModifiedAndReindex(itemToUpdate)

        # invalidate assembly async load on item
        invalidate_cachekey_volatile_for(
            'Products.PloneMeeting.browser.async.AsyncLoadItemAssemblyAndSignaturesRawFields',
            get_again=True)

        first_item_number = items_to_update[0].getItemNumber(for_display=True)
        last_item_number = items_to_update[-1].getItemNumber(for_display=True)
        extras = 'item={0} from_item_number={1} until_item_number={2}'.format(
            repr(self.context), first_item_number, last_item_number)
        fplog('manage_item_assembly', extras=extras)
        api.portal.show_message(_("Item assemblies have been updated."), request=self.request)
        self._finished = True
Beispiel #30
0
from twisted.application.internet import TCPServer

class Options(usage.Options):
    optParameters = [['port', 'p', 7000, 'Port to run on'],
                     ]


class {options[projectDir]}ServerMaker(object):
    """
    Framework boilerplate class: This is used by twistd to get the service
    class.

    Basically exists to hold the IServiceMaker interface so twistd can find
    the right makeService method to call.
    """
    implements(IServiceMaker, IPlugin)
    tapname = "{options[projectName]}"
    description = "YOU SHOULD FILL IN A DESCRIPTION"
    options = Options
    serverClass = TCPServer

    def makeService(self, options):
        """
        Construct the service
        """
        from chichimec.webserver import WebSite
        from {options[projectName]}.resource import Root
        site = WebSite()
        site.resource = Root()
        ws = self.serverClass(int(options['port']), site)
        ws.site = site
class NotificacioTIC(Item):
    implements(INotificacioTIC)
Beispiel #32
0
# api.py
# Copyright (C) 2013, 2014 LEAP
#
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
"""
Soledad - Synchronization Of Locally Encrypted Data Among Devices.

This module holds the public api for Soledad.

Soledad is the part of LEAP that manages storage and synchronization of
application data. It is built on top of U1DB reference Python API and
implements (1) a SQLCipher backend for local storage in the client, (2) a
SyncTarget that encrypts data before syncing, and (3) a CouchDB backend for
remote storage in the server side.
"""
import binascii
import errno
import httplib
import logging
import os
Beispiel #33
0
class UniqueFieldValidator:
    """ Verifies that a field value is unique for items
    if the same type in this location """

    implements(IValidator)
    name = "uniquefieldvalidator"

    def __call__(self, value, *args, **kwargs):
        field = kwargs['field']
        fieldname = field.getName()
        instance = kwargs['instance']
        translate = getToolByName(instance, 'translation_service').translate

        # return directly if nothing changed
        if value == field.get(instance):
            return True

        # We want to use the catalog to speed things up, as using `objectValues`
        # is very expensive if the parent object contains many items
        parent_objects = []

        # 1. Get the right catalog for this object
        catalogs = api.get_catalogs_for(instance)
        catalog = catalogs[0]

        # 2. Check if the field accessor is indexed
        field_index = None
        accessor = field.getAccessor(instance)
        if accessor:
            field_index = accessor.__name__

        # 3. Check if the field index is in the indexes
        # Field is indexed, use the catalog instead of objectValues
        parent_path = api.get_parent_path(instance)
        portal_type = instance.portal_type
        catalog_query = {
            "portal_type": portal_type,
            "path": {
                "query": parent_path,
                "depth": 1
            }
        }

        # We try here to avoid waking up all the objects, because this can be
        # likely very expensive if the parent object contains many objects
        if fieldname in catalog.indexes():
            # We use the fieldname as index to reduce the results list
            catalog_query[fieldname] = safe_unicode(value)
            parent_objects = map(api.get_object, catalog(catalog_query))
        elif field_index and field_index in catalog.indexes():
            # We use the field index to reduce the results list
            catalog_query[field_index] = safe_unicode(value)
            parent_objects = map(api.get_object, catalog(catalog_query))
        else:
            # fall back to the objectValues :(
            parent_object = api.get_parent(instance)
            parent_objects = parent_object.objectValues()

        for item in parent_objects:
            if hasattr(item, 'UID') and item.UID() != instance.UID() and \
               fieldname in item.Schema() and \
               str(item.Schema()[fieldname].get(item)) == str(value):
                # We have to compare them as strings because
                # even if a number (as an  id) is saved inside
                # a string widget and string field, it will be
                # returned as an int. I don't know if it is
                # caused because is called with
                # <item.Schema()[fieldname].get(item)>,
                # but it happens...
                msg = _("Validation failed: '${value}' is not unique",
                        mapping={'value': safe_unicode(value)})
                return to_utf8(translate(msg))
        return True