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
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
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
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)
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
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
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
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)
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)
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
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
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.
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)
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'...'
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
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)
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)
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
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)
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'])
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
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)
# 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
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