Пример #1
0
class SynchronizeRightActionsHandler(SynchronizeCategoryActionsHandler):
    '''
    Implementation for a processor that synchronizes the actions of the groups in the configuration file with
    the database.
    '''
    
    actionCategoryService = IActionRightService; wire.entity('actionCategoryService')
    rightService = IRightService; wire.entity('rightService')
    
    def __init__(self):
        super().__init__(Repository=RepositoryRight)
        
    def process(self, chain, solicit:Solicit, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Synchronize the actions of the groups in the configuration file with the database.
        '''
        assert isinstance(chain, Chain), 'Invalid chain %s' % chain
        assert isinstance(solicit, Solicit), 'Invalid solicit %s' % solicit
        assert isinstance(solicit.repository, RepositoryRight), 'Invalid repository %s' % solicit.repository
        
        rights = listBFS(solicit.repository, RepositoryRight.children, RepositoryRight.rightId)
        #group the actions by right name: rightId -> [actions]
        rightActions = self.groupActions(rights, RepositoryRight, 'rightId')
        self.synchronize(rightActions)
Пример #2
0
class VideoInfoServiceAlchemy(MetaInfoServiceBaseAlchemy, IVideoInfoService):
    '''
    @see: IVideoInfoService
    '''

    queryIndexer = IQueryIndexer
    wire.entity('queryIndexer')
    # The query indexer manages the query related information about plugins in order to be able to support the multi-plugin queries
    searchProvider = ISearchProvider
    wire.entity('searchProvider')
    # The search provider that will be used to manage all search related activities
    videoDataService = IVideoDataService
    wire.entity('videoDataService')

    #The correspondent meta data service for video

    def __init__(self):
        assert isinstance(
            self.queryIndexer,
            IQueryIndexer), 'Invalid IQueryIndexer %s' % self.queryIndexer
        assert isinstance(self.searchProvider, ISearchProvider
                          ), 'Invalid search provider %s' % self.searchProvider
        assert isinstance(
            self.videoDataService, IVideoDataService
        ), 'Invalid video meta data service %s' % self.videoDataService

        MetaInfoServiceBaseAlchemy.__init__(self, VideoInfoMapped, QVideoInfo,
                                            VideoDataMapped, QVideoData,
                                            self.searchProvider,
                                            self.videoDataService,
                                            META_TYPE_KEY)

        self.queryIndexer.register(VideoInfoEntry, QVideoInfo, VideoDataEntry,
                                   QVideoData, META_TYPE_KEY)
Пример #3
0
class PersonIconServiceAlchemy(SessionSupport, IPersonIconService):
    '''
    Implementation for @see: IPersonIconService
    '''
    metaDataService = IMetaDataService; wire.entity('metaDataService')
    # provides the metadata service in order to retrieve metadata of the person icon
    
    userService = IUserService; wire.entity('userService')

    def __init__(self):
        '''
        Construct the service
        '''
        assert isinstance(self.metaDataService, IMetaDataService), 'Invalid metadata service %s' % self.metaDataService

    def getByPersonId(self, id, scheme='http', thumbSize=None):
        '''
        @see: IPersonIconService.getById
        '''
        personIcon = self.session().query(PersonIconMapped).get(id)
        if not personIcon: raise InputError(Ref(_('Invalid person icon'), ref=PersonIconMapped.Id))
        assert isinstance(personIcon, PersonIconMapped)
        assert isinstance(self.metaDataService, IMetaDataService)
        metaData = self.metaDataService.getById(personIcon.MetaData, scheme, thumbSize)
        return metaData

    def setIcon(self, personId, metaDataId, update):
        '''
        @see: IPersonIconService.setIcon
        '''
     
        if update:   
            user = User()
            user.Id = personId
            self.userService.update(user)
        
        entityDb = PersonIconMapped()
        entityDb.Id, entityDb.MetaData = personId, metaDataId
        
        try:
            self.session().merge(entityDb)
            self.session().flush((entityDb,))
        except SQLAlchemyError as e: handle(e, entityDb)
        return entityDb.Id

    def detachIcon(self, personIconId):
        '''
        @see: IPersonIconService.detachIcon
        '''
        try:
            return self.session().query(PersonIconMapped).filter(PersonIconMapped.Id == personIconId).delete() > 0
        except (OperationalError, IntegrityError):
            raise InputError(Ref(_('Can not detach person icon because in use'),))
Пример #4
0
class AudioDataServiceAlchemy(MetaDataServiceBaseAlchemy, IMetaDataReferencer, IAudioDataService):
    '''
    Implementation for see @see: IAudioDataService
    '''
    
    cdmArchiveAudio = ICDM; wire.entity('cdmArchiveAudio')
    thumbnailManager = IThumbnailManager; wire.entity('thumbnailManager')

    def __init__(self):
        assert isinstance(self.cdmArchiveAudio, ICDM), 'Invalid archive CDM %s' % self.cdmArchiveAudio
        assert isinstance(self.thumbnailManager, IThumbnailManager), 'Invalid thumbnail manager %s' % self.thumbnailManager
       
        MetaDataServiceBaseAlchemy.__init__(self, AudioDataMapped, QAudioData, self, self.cdmArchiveAudio, self.thumbnailManager)
Пример #5
0
class BlogThemeServiceAlchemy(EntityServiceAlchemy, IBlogThemeService):
    '''
    Implementation for @see: IBlogThemeService
    '''
    blogThemeCDM = ICDM
    wire.entity('blogThemeCDM')

    # The GUI resources CDM.

    def __init__(self):
        '''
        Construct the blog theme service.
        '''
        EntityServiceAlchemy.__init__(self, BlogThemeMapped, QBlogTheme)

    def upload(self, content):
        '''
        @see IBlogThemeService.upload
        '''
        # TODO: implement blog theme upload
        return False

    def delete(self, id):
        '''
        @see IBlogThemeService.delete
        '''
        # TODO: implement deletion of the blog theme content if local
        return super().delete(id)
Пример #6
0
class PluginService(ComponentServiceBase, IPluginService):
    '''
    Provides the implementation for @see: IPluginService.
    '''
    
    package = '__plugin__'
    # The top package where the plugins are configured
    Component = Plugin
    # The model class to use as a component.
    
    componentService = IComponentService; wire.entity('componentService')

    def __init__(self):
        '''
        Constructs the plugins service.
        '''
        assert isinstance(self.componentService, IComponentService), 'Invalid component service %s' % self.componentService
        super().__init__()

    def getById(self, id):
        '''
        @see: IPluginService.getById
        '''
        p = super().getById(id)
        assert isinstance(p, Plugin), 'Invalid plugin %s' % p
        
        try: p.Component = next(iter(self.componentService.getAll(q=QComponent(path=p.Path), limit=1)))
        except StopIteration: pass

        return p
Пример #7
0
class GatewayACLService(IGatewayACLService):
    '''
    Implementation for @see: IGatewayACLService that provides the ACL gateways.
    '''
    
    assemblyGroupGateways = Assembly; wire.entity('assemblyGroupGateways')
    # The assembly to be used for generating gateways
    
    def __init__(self):
        assert isinstance(self.assemblyGroupGateways, Assembly), \
        'Invalid assembly gateways %s' % self.assemblyGroupGateways
        
        self._processing = self.assemblyGroupGateways.create(solicit=Solicit)
    
    def getGateways(self, group):
        '''
        @see: IGatewayACLService.getGateways
        '''
        assert isinstance(group, str), 'Invalid group name %s' % group
        
        proc = self._processing
        assert isinstance(proc, Processing), 'Invalid processing %s' % proc
        
        solicit = proc.execute(FILL_CLASSES, solicit=proc.ctx.solicit(acl={group})).solicit
        assert isinstance(solicit, Solicit), 'Invalid solicit %s' % solicit
        return solicit.gateways or ()
Пример #8
0
class AnonymousGroupHandler(HandlerProcessor):
    '''
    Provides the handler that injects the anonymous groups for gateways.
    '''

    groupService = IGroupService
    wire.entity('groupService')

    def __init__(self):
        assert isinstance(
            self.groupService,
            IGroupService), 'Invalid group service %s' % self.groupService
        super().__init__()

    def process(self, chain, solicit: Solicit, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Inject the groups identifiers.
        '''
        assert isinstance(chain, Chain), 'Invalid chain %s' % chain
        assert isinstance(solicit, Solicit), 'Invalid solicit %s' % solicit
        assert solicit.acl is None, 'There is already an acl object %s' % solicit.acl

        solicit.acl = list(
            self.groupService.getAll(q=QGroup(isAnonymous=True)))
        if not solicit.acl: chain.cancel()
Пример #9
0
class RbacSupportAlchemy(SessionSupport, IRbacSupport):
    '''
    Implementation for @see: IRbacSupport
    '''

    rbacService = IRbacService
    wire.entity('rbacService')

    # Rbac service to use for complex role operations.

    def __init__(self):
        assert isinstance(
            self.rbacService,
            IRbacService), 'Invalid rbac service %s' % self.rbacService

    def iterateTypeAndRightsNames(self, rbacId):
        '''
        @see: IRbacSupport.iterateTypeAndRightsNames
        '''
        sql = self.session().query(RightMapped.Name,
                                   RightTypeMapped.Name).join(RightTypeMapped)
        sql = self.rbacService.rightsForRbacSQL(rbacId, sql=sql)
        sql = sql.order_by(RightTypeMapped.Name, RightMapped.Name)

        current = names = None
        for name, typeName in sql.all():
            if current != typeName:
                if current is not None: yield current, names
                current = typeName
                names = []
            names.append(name)
        if current is not None: yield current, names
Пример #10
0
class SynchronizeGroupActionsHandler(SynchronizeCategoryActionsHandler):
    '''
    Implementation for a processor that synchronizes the actions of the groups in the configuration file with
    the database.
    '''
    
    actionCategoryService = IActionGroupService; wire.entity('actionCategoryService')
    
    def __init__(self):
        super().__init__(Repository=RepositoryGroup)
        
    def process(self, chain, solicit:Solicit, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Synchronize the actions of the groups in the configuration file with the database.
        '''
        assert isinstance(chain, Chain), 'Invalid chain %s' % chain
        assert isinstance(solicit, Solicit), 'Invalid solicit %s' % solicit
        assert isinstance(solicit.repository, RepositoryGroup), 'Invalid repository %s' % solicit.repository
        
        groups = listBFS(solicit.repository, RepositoryGroup.children, RepositoryGroup.groupName)
        #first group the actions by group name: groupName -> [actions]
        groupActions = self.groupActions(groups, RepositoryGroup, 'groupName')        
        self.synchronize(groupActions)
Пример #11
0
class RightServiceAlchemy(EntityGetServiceAlchemy, EntityCRUDServiceAlchemy,
                          AclServiceAlchemy, CompensateServiceAlchemy,
                          IRightService):
    '''
    Implementation for @see: IRightService
    '''

    signaturesRight = dict
    wire.entity('signaturesRight')

    def __init__(self):
        EntitySupportAlchemy.__init__(self, RightMapped, QRight)
        AclServiceAlchemy.__init__(self, RightMapped, RightAccess)
        CompensateServiceAlchemy.__init__(self,
                                          RightMapped,
                                          RightAccess,
                                          RightCompensate,
                                          signatures=self.signaturesRight)

    def getAll(self, typeName=None, q=None, **options):
        '''
        @see: IRightService.getAll
        '''
        sql = self.session().query(RightMapped.Id)
        if typeName:
            sql = sql.join(RightTypeMapped).filter(
                RightTypeMapped.Name == typeName)
        if q is not None:
            assert isinstance(q, QRight), 'Invalid query %s' % q
            sql = buildQuery(sql, q, RightMapped)
        return iterateCollection(sql, **options)
Пример #12
0
class GatewayService(IGatewayService):
    '''
    Implementation for @see: IGatewayService that provides the default anonymous gateway data.
    '''

    assemblyAnonymousGateways = Assembly
    wire.entity('assemblyAnonymousGateways')

    # The assembly to be used for generating gateways

    def __init__(self):
        assert isinstance(self.assemblyAnonymousGateways, Assembly), \
        'Invalid assembly gateways %s' % self.assemblyAnonymousGateways

        self._processing = self.assemblyAnonymousGateways.create(reply=Reply)

    def getAnonymous(self):
        '''
        @see: IGatewayService.getAnonymous
        '''
        proc = self._processing
        assert isinstance(proc, Processing), 'Invalid processing %s' % proc

        chain = Chain(proc)
        chain.process(reply=proc.ctx.reply()).doAll()

        reply = chain.arg.reply
        assert isinstance(reply, Reply), 'Invalid reply %s' % reply
        if Reply.gateways not in reply: return ()
        return reply.gateways
Пример #13
0
class SynchronizeRightAccessHandler(SynchronizeCategoryAccessHandler):
    '''
    Implementation for a processor that synchronizes the category (groups and rights) 
    accesses in the configuration file with the database.
    '''
    accessCategoryService = IRightService; wire.entity('accessCategoryService')
    
    def __init__(self):
        assert isinstance(self.accessCategoryService, IRightService), \
        'Invalid right service %s' % self.accessCategoryService
        super().__init__()
    
    def process(self, chain, solicit:Solicit, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Synchronize the accesses in the configuration file with the accesses in the database.
        '''
        assert isinstance(chain, Chain), 'Invalid chain %s' % chain
        assert isinstance(solicit, Solicit), 'Invalid solicit %s' % solicit
        
        #get the accesses for the rights and group them by rightId
        accesses = [acc for acc in filter(lambda access: access.rightId, solicit.syncAccesses)]
        grouped = self.groupByCategory(accesses, SyncAccess.rightId)
        
        self.syncAccessesWithDb(grouped)
        self.syncCompensatesWithDb(grouped)
Пример #14
0
class PersonIconServiceAlchemy(SessionSupport, IPersonIconService):
    '''
    Implementation for @see: IPersonIconService
    '''
    metaDataService = IMetaDataService; wire.entity('metaDataService')
    # provides the metadata service in order to retrieve metadata of the person icon

    def __init__(self):
        '''
        Construct the service
        '''
        assert isinstance(self.metaDataService, IMetaDataService), 'Invalid metadata service %s' % self.metaDataService

    def getByPersonId(self, id, scheme='http', thumbSize=None):
        '''
        @see: IPersonIconService.getById
        '''
        personIcon = self.session().query(PersonIconMapped).get(id)
        if not personIcon: raise InputError(Ref(_('Invalid person icon'), ref=PersonIconMapped.Id))
        assert isinstance(personIcon, PersonIconMapped)
        assert isinstance(self.metaDataService, IMetaDataService)
        metaData = self.metaDataService.getById(personIcon.MetaData, scheme, thumbSize)
        return metaData

    def setIcon(self, personId, metaDataId):
        '''
        @see: IPersonIconService.setIcon
        '''
        entityDb = PersonIconMapped()
        entityDb.Id, entityDb.MetaData = personId, metaDataId
        try:
            self.session().merge(entityDb)
            self.session().flush((entityDb,))
        except SQLAlchemyError as e: handle(e, entityDb)
        return entityDb.Id
Пример #15
0
class MemoryStatusPresenter:
    '''
    Class providing the memory status presentation.
    '''

    resourcesRoot = Node
    wire.entity('resourcesRoot')

    # The resources root node structure.

    def __init__(self):
        assert isinstance(self.resourcesRoot,
                          Node), 'Invalid root node %s' % self.resourcesRoot
        node = NodePath(self.resourcesRoot, True, 'MemoryStatus')
        node.get = InvokerFunction(GET, self.present, typeFor(Non), [
            Input('limit', typeFor(Integer), True, None),
            Input('include', typeFor(String), True, None),
            Input('exclude', typeFor(String), True, None),
        ], {})

    def present(self, limit, include=None, exclude=None):
        '''
        Provides the dictionary structure presenting the memory.
        Attention this will also call the garbage collection.
        
        @return: dictionary
            The dictionary containing the memory status.
        '''
        if not limit: limit = 10
        gc.collect()
        total, referencess = self.getRefcounts(limit, include, exclude)
        return {'References': {'Total': total, 'Class': referencess}}

    def getRefcounts(self, limit, prefixInclude, prefixExclude):
        counts = {}
        total = 0
        for m in sys.modules.values():
            for sym in dir(m):
                o = getattr(m, sym)
                typ = type(o)
                if isclass(typ):
                    name = fullyQName(typ)
                    if name not in counts:
                        count = sys.getrefcount(o)
                        counts[name] = count
                        total += count
        # sort by refcount
        counts = [(name, count) for name, count in counts.items()]
        counts.sort(key=lambda pack: pack[1], reverse=True)
        d = OrderedDict()
        k = 0
        for className, count in counts:
            add = True
            if prefixInclude: add = className.startswith(prefixInclude)
            if prefixExclude: add = not className.startswith(prefixExclude)
            if add: d[className] = str(count)
            if k >= limit: break
            k += 1
        return str(total), d
Пример #16
0
class SynchronizeCategoryActionsHandler(HandlerProcessor):
    '''
    Base implementation for a processor that synchronizes the actions of the groups and rights in the configuration file with
    the database.
    '''
    
    actionCategoryService = IActionCategoryPrototype; wire.entity('actionCategoryService')
    
    def __init__(self, Repository):
        assert isinstance(self.actionCategoryService, IActionCategoryPrototype), \
        'Invalid action category service %s' % self.actionCategoryService
        super().__init__(Repository=Repository)
        
    def synchronize(self, entityActions):
        ''' 
        Method to synchronize actions from configuration file with the database for groups and rights.
        @param entityActions: mapping entityId : list of actions
        '''
        for entity, actions in entityActions.items():
            actionsDb = set(self.actionCategoryService.getActions(entity))
            if actions:
                actionsSet = set(action.path for action in actions)
                toDelete = actionsDb.difference(actionsSet)
                toAdd = actionsSet.difference(actionsDb)
            else:
                toDelete = actionsDb
                toAdd = None
                
            if toDelete:
                for path in toDelete:
                    self.actionCategoryService.remAction(entity, path)
            
            if toAdd:
                for path in toAdd:
                    self.actionCategoryService.addAction(entity, path)
                
    def groupActions(self, repositories, Repository, idName):
        '''
        For a list of repositories, groups the actions by some Id attribute.
        @type Repository: Context
        @param idName: the name of the attribute representing the id of the entity (e.g groupName or rightId) 
        @return: mapping Id : list of actions
        '''
        groupActions = {}
        for repository in repositories:
            assert isinstance(repository, Repository), 'Invalid repository %s' % repository
            assert hasAttribute(Repository, idName), 'Invalid repository %s' % repository
            actions = groupActions.get(getattr(repository, idName))
            if not actions: groupActions[getattr(repository, idName)] = repository.actions
            else: actions.extend(repository.actions)
        
        return groupActions
Пример #17
0
class AudioInfoServiceAlchemy(MetaInfoServiceBaseAlchemy, IAudioInfoService):
    '''
    @see: IAudioInfoService
    '''

    queryIndexer = QueryIndexer
    wire.entity('queryIndexer')

    def __init__(self):
        MetaInfoServiceBaseAlchemy.__init__(self, AudioInfoMapped, QAudioInfo,
                                            AudioDataMapped, QAudioData)
        self.queryIndexer.register(AudioInfoEntry, QAudioInfo, AudioDataEntry,
                                   QAudioData)
Пример #18
0
class ImageDataServiceAlchemy(MetaDataServiceBaseAlchemy, IMetaDataReferencer,
                              IImageDataService):
    '''
    @see: IImageDataService
    '''

    cdmArchiveImage = ICDM
    wire.entity('cdmArchiveImage')
    thumbnailManager = IThumbnailManager
    wire.entity('thumbnailManager')

    def __init__(self):
        assert isinstance(
            self.cdmArchiveImage,
            ICDM), 'Invalid archive CDM %s' % self.cdmArchiveImage
        assert isinstance(
            self.thumbnailManager, IThumbnailManager
        ), 'Invalid thumbnail manager %s' % self.thumbnailManager

        MetaDataServiceBaseAlchemy.__init__(self, ImageDataMapped, QImageData,
                                            self, self.cdmArchiveImage,
                                            self.thumbnailManager)
Пример #19
0
class MetaInfoServiceAlchemy(MetaInfoServiceBaseAlchemy, IMetaInfoService):
    '''
    Implementation for @see: IMetaInfoService
    '''

    queryIndexer = IQueryIndexer
    wire.entity('queryIndexer')
    # The query indexer manages the query related information about plugins in order to be able to support the multi-plugin queries
    searchProvider = ISearchProvider
    wire.entity('searchProvider')
    # The search provider that will be used to manage all search related activities
    metaDataService = IMetaDataService
    wire.entity('metaDataService')

    #The correspondent meta data service for other media type

    def __init__(self):
        '''
        Construct the meta info service.
        '''
        assert isinstance(
            self.queryIndexer,
            IQueryIndexer), 'Invalid IQueryIndexer %s' % self.queryIndexer
        assert isinstance(self.searchProvider, ISearchProvider
                          ), 'Invalid search provider %s' % self.searchProvider
        assert isinstance(
            self.metaDataService, IMetaDataService
        ), 'Invalid meta data service %s' % self.metaDataService

        MetaInfoServiceBaseAlchemy.__init__(self, MetaInfoMapped, QMetaInfo,
                                            MetaDataMapped, QMetaData,
                                            self.searchProvider,
                                            self.metaDataService,
                                            META_TYPE_KEY)

        self.queryIndexer.register(MetaInfoMapped, QMetaInfo, MetaDataMapped,
                                   QMetaData, META_TYPE_KEY)
Пример #20
0
class ArticleFileServiceAlchemy(EntityServiceAlchemy, IArticleFileService):
    '''
    Implementation for @see: IArticleFileService
    '''

    articleService = IArticleService
    wire.entity('articleService')

    # TODO: comment

    def __init__(self):
        '''
        Construct the article file service.
        '''
        EntityServiceAlchemy.__init__(self, ArticleFileMapped, QArticleFile)
Пример #21
0
class SynchronizeGroupsHandler(HandlerProcessor):
    '''
    Implementation for a processor that synchronizes the groups in the configuration file with the database.
    '''

    groupService = IGroupService
    wire.entity('groupService')

    anonymousGroups = set

    # The set with the anonymous groups names

    def __init__(self):
        assert isinstance(self.groupService, IGroupService)
        'Invalid group service %s' % self.groupService
        assert isinstance(
            self.anonymousGroups,
            set), 'Invalid anonymous groups %s' % self.anonymousGroups
        super().__init__(Repository=RepositoryGroup)

    def process(self, chain, solicit: Solicit, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Synchronize the groups of the groups in the configuration file with the database.
        '''
        assert isinstance(chain, Chain), 'Invalid chain %s' % chain
        assert isinstance(solicit, Solicit), 'Invalid solicit %s' % solicit
        assert isinstance(
            solicit.repository,
            RepositoryGroup), 'Invalid repository %s' % solicit.repository

        #maps name to id
        groupsDb = {name: name for name in self.groupService.getAll()}
        #maps group_name to arguments required for group creation (None for groups)
        groups = {
            r.groupName: (self.createEntity, r)
            for r in listBFS(solicit.repository, RepositoryGroup.children,
                             RepositoryGroup.groupName)
        }
        syncWithDatabase(self.groupService, groups, groupsDb)

    def createEntity(self, groupName):
        group = Group()
        group.Name = groupName
        group.IsAnonymous = groupName in self.anonymousGroups
        return group
Пример #22
0
class RbacPopulateRights(HandlerProcessorProceed):
    '''
    Provides the handler that populates the rights based on RBAC structure.
    '''

    rbacSupport = IRbacSupport
    wire.entity('rbacSupport')

    # Rbac support to use for complex role operations.

    def __init__(self):
        assert isinstance(
            self.rbacSupport,
            IRbacSupport), 'Invalid rbac support %s' % self.rbacSupport
        super().__init__()

    def process(self, solicitation: Solicitation, **keyargs):
        '''
        @see: HandlerProcessorProceed.process
        
        Populate the rights.
        '''
        assert isinstance(
            solicitation,
            Solicitation), 'Invalid solicitation %s' % solicitation
        assert isinstance(solicitation.rbacId,
                          int), 'Invalid rbac Id %s' % solicitation.rbacId

        allTypes, rights, types = {
            aclType.name: aclType
            for aclType in solicitation.types
        }, [], []
        for typeName, names in self.rbacSupport.iterateTypeAndRightsNames(
                solicitation.rbacId):
            aclType = allTypes.get(typeName)
            if not aclType: continue
            types.append(aclType)
            assert isinstance(aclType, TypeAcl)
            rights.extend(aclType.rightsFor(names))

        solicitation.types = types
        if solicitation.rights is not None:
            solicitation.rights = chain(solicitation.rights, rights)
        else:
            solicitation.rights = rights
Пример #23
0
class ModelFiltersForPermissions(HandlerProcessorProceed):
    '''
    Processor that provides the model filters on the resources permissions.
    '''

    processorModelFilters = ProcessorModelFilters
    wire.entity('processorModelFilters')

    # The model filters processor.

    def __init__(self):
        '''
        Construct the persistence invoker service.
        '''
        assert isinstance(self.processorModelFilters, ProcessorModelFilters), \
        'Invalid model filters processor %s' % self.processorModelFilters
        super().__init__()

    def process(self, Permission: PermissionWithModelFilters,
                ModelFilter: ModelFilterResource, solicitation: Solicitation,
                **keyargs):
        '''
        @see: HandlerProcessorProceed.process
        
        Process permission model fitler.
        '''
        assert issubclass(
            Permission,
            PermissionResource), 'Invalid permission class %s' % Permission
        assert issubclass(
            ModelFilter,
            ModelFilterResource), 'Invalid model filter class %s' % ModelFilter
        assert isinstance(
            solicitation,
            Solicitation), 'Invalid solicitation %s' % solicitation
        assert isinstance(
            solicitation.permissions,
            Iterable), 'Invalid permissions %s' % solicitation.permissions

        solicitation.permissions = self.processorModelFilters.processPermissions(
            solicitation.permissions, ModelFilter)
Пример #24
0
class RegisterDatabaseGatewayHandler(HandlerProcessor):
    '''
    Provides the handler that populates Gateway objects based on database GatewayData.
    '''
    
    databaseGatewayProvider = DatabaseGatewayProviderAlchemy; wire.entity('databaseGatewayProvider')
    
    def __init__(self):
        assert isinstance(self.databaseGatewayProvider, DatabaseGatewayProviderAlchemy), \
        'Invalid database gateway provider %s' % self.databaseGatewayProvider
        super().__init__()
    
    def process(self, chain, solicit:Solicit, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Adds the databse gateways.
        '''
        assert isinstance(solicit, Solicit), 'Invalid solicit %s' % solicit
        
        gateways = self.databaseGatewayProvider.iterateGateways()
        if solicit.gateways is not None: solicit.gateways = itertools.chain(solicit.gateways, gateways)
        else: solicit.gateways = gateways
Пример #25
0
class UserRbacProvider(HandlerProcessor):
    '''
    Provides the handler that extracts the rbac id for the user id.
    '''

    userRbacSupport = IUserRbacSupport
    wire.entity('userRbacSupport')

    # The user rbac support use by the provider.

    def __init__(self):
        assert isinstance(
            self.userRbacSupport, IUserRbacSupport
        ), 'Invalid user rbac support %s' % self.userRbacSupport
        super().__init__()

    def process(self, chain, solicitation: Solicitation, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Populate the rbac id.
        '''
        assert isinstance(chain, Chain), 'Invalid chain %s' % chain
        assert isinstance(
            solicitation,
            Solicitation), 'Invalid solicitation %s' % solicitation
        assert isinstance(
            solicitation.userId,
            int), 'Invalid solicitation user id %s' % solicitation.userId

        solicitation.rbacId = self.userRbacSupport.rbacIdFor(
            solicitation.userId)
        if solicitation.rbacId is None:
            return  # No rbac available so stopping the processing
        if Solicitation.provider in solicitation:
            solicitation.provider = UserProvider(str(solicitation.userId))
        chain.proceed()
Пример #26
0
class JSONFileService(IJSONLocaleFileService):
    '''
    Implementation for @see: IJSONLocaleFileService
    '''

    default_charset = 'UTF-8'
    wire.config('default_charset',
                doc='''
    The default character set to use whenever a JSON locale file is uploaded and
    the character set of the content is not specified''')

    poFileManager = IPOFileManager
    wire.entity('poFileManager')
    cdmLocale = ICDM
    wire.entity('cdmLocale')
    pluginService = IPluginService
    wire.entity('pluginService')
    componentService = IComponentService
    wire.entity('componentService')

    def __init__(self):
        assert isinstance(
            self.default_charset,
            str), 'Invalid default charset %s' % self.default_charset
        assert isinstance(
            self.poFileManager,
            IPOFileManager), 'Invalid PO file manager %s' % self.poFileManager
        assert isinstance(self.cdmLocale,
                          ICDM), 'Invalid PO CDM %s' % self.cdmLocale
        assert isinstance(
            self.pluginService,
            IPluginService), 'Invalid plugin service %s' % self.pluginService
        assert isinstance(
            self.componentService, IComponentService
        ), 'Invalid component service %s' % self.componentService

    def getGlobalJSONFile(self, locale, scheme):
        '''
        @see: IPOService.getGlobalPOFile
        '''
        path = self._cdmPath(locale)
        try:
            try:
                cdmFileTimestamp = self.cdmLocale.getTimestamp(path)
            except PathNotFound:
                republish = True
            else:
                mngFileTimestamp = self.poFileManager.getGlobalPOTimestamp(
                    locale)
                republish = False if mngFileTimestamp is None else cdmFileTimestamp < mngFileTimestamp

            if republish:
                jsonString = JSONEncoder(ensure_ascii=False).encode(
                    self.poFileManager.getGlobalAsDict(locale))
                self.cdmLocale.publishContent(
                    path, BytesIO(bytes(jsonString, getdefaultencoding())))
        except InvalidLocaleError:
            raise InputError(
                _('Invalid locale %(locale)s') % dict(locale=locale))
        return self.cdmLocale.getURI(path, scheme)

    def getComponentJSONFile(self, component, locale, scheme):
        '''
        @see: IPOService.getComponentPOFile
        '''
        self.componentService.getById(component)
        path = self._cdmPath(locale, component=component)
        try:
            try:
                cdmFileTimestamp = self.cdmLocale.getTimestamp(path)
            except PathNotFound:
                republish = True
            else:
                mngFileTimestamp = max(
                    self.poFileManager.getGlobalPOTimestamp(locale)
                    or datetime.min,
                    self.poFileManager.getComponentPOTimestamp(
                        component, locale) or datetime.min)
                republish = False if mngFileTimestamp is None else cdmFileTimestamp < mngFileTimestamp

            if republish:
                jsonString = JSONEncoder(ensure_ascii=False).encode(
                    self.poFileManager.getComponentAsDict(component, locale))
                self.cdmLocale.publishContent(
                    path, BytesIO(bytes(jsonString, getdefaultencoding())))
        except InvalidLocaleError:
            raise InputError(
                _('Invalid locale %(locale)s') % dict(locale=locale))
        return self.cdmLocale.getURI(path, scheme)

    def getPluginJSONFile(self, plugin, locale, scheme):
        '''
        @see: IPOService.getPluginPOFile
        '''
        pluginObj = self.pluginService.getById(plugin)
        assert isinstance(pluginObj, Plugin)
        if pluginObj.Component:
            return self.getComponentJSONFile(pluginObj.Component, locale,
                                             scheme)

        path = self._cdmPath(locale, plugin=plugin)
        try:
            try:
                cdmFileTimestamp = self.cdmLocale.getTimestamp(path)
            except PathNotFound:
                republish = True
            else:
                mngFileTimestamp = max(
                    self.poFileManager.getGlobalPOTimestamp(locale)
                    or datetime.min,
                    self.poFileManager.getPluginPOTimestamp(plugin, locale)
                    or datetime.min)
                republish = False if mngFileTimestamp is None else cdmFileTimestamp < mngFileTimestamp

            if republish:
                jsonString = JSONEncoder(ensure_ascii=False).encode(
                    self.poFileManager.getPluginAsDict(plugin, locale))
                self.cdmLocale.publishContent(
                    path, BytesIO(bytes(jsonString, getdefaultencoding())))
        except InvalidLocaleError:
            raise InputError(
                _('Invalid locale %(locale)s') % dict(locale=locale))
        return self.cdmLocale.getURI(path, scheme)

    # ----------------------------------------------------------------

    def _cdmPath(self, locale, component=None, plugin=None):
        '''
        Returns the path to the CDM JSON file corresponding to the given locale and / or
        component / plugin. If no component of plugin was specified it returns the
        name of the global JSON file.

        @param locale: string
            The locale.
        @param component: string
            The component id.
        @param plugin: string
            The plugin id.
        @return: string
            The file path.
        '''
        assert isinstance(locale, str), 'Invalid locale %s' % locale

        path = []
        if component:
            path.append('component')
            path.append(component)
        elif plugin:
            path.append('plugin')
            path.append(plugin)
        else:
            path.append('global')
        path.append(locale)
        return '%s.json' % '-'.join(path)
Пример #27
0
class ContentPublisherService(IContentPublisherService):
    '''
    Implementation for @see: IContentPublisherService
    '''

    mongodb_server = 'localhost'
    wire.config('mongodb_server', doc='''The address of the mongoDb server''')
    mongodb_port = 27017
    wire.config('mongodb_port', doc='''The port of the mongoDb server''')
    mongodb_database = 'mongodb'
    wire.config('mongodb_database', doc='''The name of the mongoDb database''')

    itemService = IItemService
    wire.entity('itemService')
    # item service used to convert article content to NewsML structure
    itemContentService = IItemContentService
    wire.entity('itemContentService')

    # item content service used to convert article content to NewsML structure

    def __init__(self):
        '''
        Construct the content publisher service.
        '''
        assert isinstance(
            self.mongodb_server,
            str), 'Invalid mongoDb server address %s' % self.mongodb_server
        assert isinstance(
            self.mongodb_port,
            int), 'Invalid mongoDb server port %s' % self.mongodb_port
        assert isinstance(
            self.mongodb_database,
            str), 'Invalid mongoDb database name %s' % self.mongodb_database

        mongoengine.connect(self.mongodb_database,
                            host=self.mongodb_server,
                            port=self.mongodb_port)

    def publish(self, guid):
        '''
        Implementation for @see: IContentPublisherService.publish
        '''
        # Test add document
        myItem = self.itemService.getById(guid)
        assert isinstance(myItem, PackageItem)

        item = Item()
        item.guid = myItem.GUId
        item.version = myItem.Version
        item.itemClass = myItem.ItemClass
        item.urgency = myItem.Urgency
        item.headline = myItem.HeadLine
        item.slugline = myItem.SlugLine
        item.byline = myItem.Byline
        item.creditline = myItem.CreditLine
        item.firstCreated = myItem.FirstCreated
        item.versionCreated = myItem.VersionCreated

        q = QItemContent()
        q.item = myItem.GUId
        contents = self.itemContentService.getAll(q=q)
        for c in contents:
            assert isinstance(c, ItemContent)
            content = Content()
            content.contenttype = c.ContentType
            content.content = c.Content
            content.residRef = c.ResidRef
            content.href = c.HRef
            content.size = c.Size
            content.rendition = c.Rendition
            item.contents.append(content)

        self.unpublish(item.guid)
        item.save(safe=True)
        return True

    def unpublish(self, guid):
        '''
        Implementation for @see: IContentPublisherService.unpublish
        '''
        # Test delete document
        Item.objects(guid=guid).delete(safe=True)
        return True
Пример #28
0
class Scanner:
    '''
    The class that provides the scanner.
    '''

    componentService = IComponentService
    wire.entity('componentService')
    pluginService = IPluginService
    wire.entity('pluginService')
    fileService = IFileService
    wire.entity('fileService')
    sourceService = ISourceService
    wire.entity('sourceService')
    messageService = IMessageService
    wire.entity('messageService')

    def __init__(self):
        '''
        Construct the scanner.
        '''
        assert isinstance(self.componentService, IComponentService), \
        'Invalid component service %s' % self.componentService
        assert isinstance(
            self.pluginService,
            IPluginService), 'Invalid plugin service %s' % self.pluginService
        assert isinstance(
            self.fileService,
            IFileService), 'Invalid file service %s' % self.fileService
        assert isinstance(
            self.sourceService,
            ISourceService), 'Invalid source service %s' % self.sourceService
        assert isinstance(self.messageService, IMessageService
                          ), 'Invalid message service %s' % self.messageService

    @app.populate(app.CHANGED)
    def scanLocalization(self):
        '''
        Scans the application for localization messages.
        '''
#        log.info('Scanning the application distribution for localized messages')
#        self.scanComponents()
#        self.scanPlugins()

# ----------------------------------------------------------------

    def scanComponents(self):
        '''
        Scan the current application components for the localized text messages.
        '''
        for component in self.componentService.getComponents():
            assert isinstance(component, Component)
            files = {
                file.Path: file
                for file in self.fileService.getAll(q=QFile(
                    component=component.Id))
            }
            if component.InEgg:
                lastModified = modificationTimeFor(component.Path)
                file = files.get(component.Path)
                if file and lastModified <= file.LastModified:
                    log.info(
                        'No modifications for component zip file "%s" in %s',
                        component.Path, component.Name)
                    continue
                if not file:
                    file = File()
                    file.Component = component.Id
                    file.Path = component.Path
                    file.LastModified = lastModified
                    files[component.Path] = file
                    self.fileService.insert(file)
                else:
                    file.LastModified = lastModified
                    self.fileService.update(file)
                scanner = scanZip(component.Path)
            else:
                lastModified, scanner = None, scanFolder(component.Path)

            files.update({
                source.Path: source
                for source in self.sourceService.getAll(q=QSource(
                    component=component.Id))
            })
            self._persist(files, scanner, component.Path, lastModified,
                          component.Id, None)

    def scanPlugins(self):
        '''
        Scan the current application plugins for the localized text messages.
        '''
        for plugin in self.pluginService.getPlugins():
            assert isinstance(plugin, Plugin)
            files = {
                file.Path: file
                for file in self.fileService.getAll(q=QFile(plugin=plugin.Id))
            }
            if plugin.InEgg:
                lastModified = modificationTimeFor(plugin.Path)
                file = files.get(plugin.Path)
                if file and lastModified <= file.LastModified:
                    log.info('No modifications for plugin zip file "%s" in %s',
                             plugin.Path, plugin.Name)
                    continue
                if not file:
                    file = File()
                    file.Plugin = plugin.Id
                    file.Path = plugin.Path
                    file.LastModified = lastModified
                    files[plugin.Path] = file
                    self.fileService.insert(file)
                else:
                    file.LastModified = lastModified
                    self.fileService.update(file)
                scanner = scanZip(plugin.Path)
            else:
                lastModified, scanner = None, scanFolder(plugin.Path)

            files.update({
                source.Path: source
                for source in self.sourceService.getAll(q=QSource(
                    plugin=plugin.Id))
            })
            self._persist(files, scanner, plugin.Path, lastModified, None,
                          plugin.Id)

    # ----------------------------------------------------------------

    def _persist(self, files, scanner, path, lastModified, componentId,
                 pluginId):
        '''
        Persist the sources and messages. 
        '''
        assert isinstance(files, dict), 'Invalid files %s' % files
        processModified = lastModified is None
        for filePath, method, extractor in scanner:
            assert method in TYPES, 'Invalid method %s' % method

            file = files.get(filePath)
            if processModified:
                lastModified = modificationTimeFor(filePath)
                if file:
                    assert isinstance(file, File)
                    if lastModified <= file.LastModified:
                        log.info('No modifications for file "%s"', filePath)
                        continue
                    file.LastModified = lastModified
                    self.fileService.update(file)

            if isinstance(file, Source): source = file
            else: source = None
            messages = None
            try:
                for text, context, lineno, comments in extractor:
                    if not source:
                        if file: self.fileService.delete(file.Id)
                        source = Source()
                        source.Component = componentId
                        source.Plugin = pluginId
                        source.Path = filePath
                        source.Type = method
                        source.LastModified = lastModified
                        files[filePath] = source
                        self.sourceService.insert(source)

                    if messages is None:
                        messages = {
                            msg.Singular: msg
                            for msg in self.messageService.getMessages(
                                source.Id)
                        }

                    if isinstance(text, str): singular, plurals = text, None
                    elif len(text) == 1: singular, plurals = text[0], None
                    else: singular, plurals = text[0], list(text[1:])

                    msg = messages.get(singular)
                    if not msg:
                        msg = Message()
                        msg.Source = source.Id
                        msg.Singular = singular
                        msg.Plural = plurals
                        msg.Context = context
                        msg.LineNumber = lineno
                        msg.Comments = '\n'.join(comments)

                        self.messageService.insert(msg)
                        messages[singular] = msg
                    else:
                        msg.Plural = plurals
                        msg.Context = context
                        msg.LineNumber = lineno
                        msg.Comments = '\n'.join(comments)
                        self.messageService.update(msg)
            except UnicodeDecodeError as e:
                log.error('%s: %s' % (filePath, str(e)))

            if processModified and filePath not in files:
                file = File()
                file.Component = componentId
                file.Plugin = pluginId
                file.Path = filePath
                file.LastModified = lastModified
                files[filePath] = file
                self.fileService.insert(file)
Пример #29
0
class ChainedSyncProcess:
    '''
    Chained sync process.
    '''

    blogSyncService = IBlogSyncService
    wire.entity('blogSyncService')
    # blog sync service used to retrieve blogs set on auto publishing

    sourceService = ISourceService
    wire.entity('sourceService')
    # source service used to retrieve source data

    blogPostService = IBlogPostService
    wire.entity('blogPostService')
    # blog post service used to insert blog posts

    postService = IPostService
    wire.entity('postService')
    # post service used to insert/update posts

    collaboratorService = ICollaboratorService
    wire.entity('collaboratorService')
    # blog post service used to retrive collaborator

    userService = IUserService
    wire.entity('userService')

    metaDataService = IMetaDataUploadService
    wire.entity('metaDataService')

    metaInfoService = IMetaInfoService
    wire.entity('metaInfoService')

    personIconService = IPersonIconService
    wire.entity('personIconService')

    syncThreads = {}
    # dictionary of threads that perform synchronization

    sync_interval = 53
    wire.config('sync_interval',
                doc='''
    The number of seconds to perform sync for blogs.''')

    timeout_inteval = 4  #; wire.config('timeout_interval', doc='''
    #The number of seconds after the sync ownership can be taken.''')

    published_posts_path = 'Post/Published'
    wire.config('published_posts_path',
                doc='''
    The partial path used to construct the URL for published posts retrieval'''
                )

    user_type_key = 'chained blog'
    wire.config('user_type_key',
                doc='''
    The user type that is used for the anonymous users of chained blog posts'''
                )

    blog_provider_type = 'blog provider'
    wire.config('blog_provider_type',
                doc='''
    Key of the source type for blog providers''')

    acceptType = 'text/json'
    # mime type accepted for response from remote blog
    encodingType = 'UTF-8'
    # character encoding type accepted for response from remove blog

    @app.deploy
    def startChainSyncThread(self):
        '''
        Starts the chain sync thread.
        '''
        schedule = scheduler(time.time, time.sleep)

        def syncChains():
            self.syncChains()
            schedule.enter(self.sync_interval, 1, syncChains, ())

        schedule.enter(self.sync_interval, 1, syncChains, ())
        scheduleRunner = Thread(name='chained sync', target=schedule.run)
        scheduleRunner.daemon = True
        scheduleRunner.start()
        log.info('Started the chained blogs automatic synchronization.')

    def syncChains(self):
        '''
        Read all chained blog sync entries and sync with the corresponding blogs.
        '''
        log.info('Start chained blog synchronization')
        for blogSync in self.blogSyncService.getBySourceType(
                self.blog_provider_type):
            assert isinstance(blogSync, BlogSync)
            key = (blogSync.Blog, blogSync.Source)
            thread = self.syncThreads.get(key)
            if thread:
                assert isinstance(thread, Thread), 'Invalid thread %s' % thread
                if thread.is_alive():
                    log.info('Chained thread for blog %d is alive',
                             blogSync.Blog)
                    continue

                if not self.blogSyncService.checkTimeout(
                        blogSync.Id,
                        self.timeout_inteval * self.sync_interval):
                    log.info('Chained thread for blog %d is already taken',
                             blogSync.Blog)
                    continue

            self.syncThreads[key] = Thread(name='blog %d sync' % blogSync.Blog,
                                           target=self._syncChain,
                                           args=(blogSync, ))
            self.syncThreads[key].daemon = True
            self.syncThreads[key].start()
            log.info('Chained thread started for blog id %d and source id %d',
                     blogSync.Blog, blogSync.Source)

        log.info('End chained blog synchronization')

    def _syncChain(self, blogSync):
        '''
        Synchronize the blog for the given sync entry.

        @param blogSync: BlogSync
            The blog sync entry declaring the blog and source from which the blog
            has to be updated.
        '''
        assert isinstance(blogSync,
                          BlogSync), 'Invalid blog sync %s' % blogSync
        source = self.sourceService.getById(blogSync.Source)

        log.info('_syncChain blogId=%d, sourceId=%d', blogSync.Blog,
                 blogSync.Source)

        assert isinstance(source, Source)
        (scheme, netloc, path, params, query, fragment) = urlparse(source.URI)

        if not scheme: scheme = 'http'

        q = parse_qsl(query, keep_blank_values=True)
        q.append(('asc', 'cId'))
        q.append(
            ('cId.since', blogSync.CId if blogSync.CId is not None else 0))

        url = urlunparse(
            (scheme, netloc, path + '/' + self.published_posts_path, params,
             urlencode(q), fragment))
        req = Request(url,
                      headers={
                          'Accept': self.acceptType,
                          'Accept-Charset': self.encodingType,
                          'X-Filter':
                          '*,Creator.*,Author.User.*,Author.Source.*',
                          'User-Agent': 'Magic Browser'
                      })

        try:
            resp = urlopen(req)
        except (HTTPError, socket.error) as e:
            log.error('Read error on %s: %s' % (source.URI, e))
            blogSync.LastActivity = None
            self.blogSyncService.update(blogSync)
            return

        if str(resp.status) != '200':
            log.error('Read problem on %s, status: %s' %
                      (source.URI, resp.status))
            blogSync.LastActivity = None
            self.blogSyncService.update(blogSync)
            return

        try:
            msg = json.load(codecs.getreader(self.encodingType)(resp))
        except ValueError as e:
            log.error('Invalid JSON data %s' % e)
            blogSync.LastActivity = None
            self.blogSyncService.update(blogSync)
            return

        usersForIcons = {}
        for post in msg['PostList']:
            try:
                if post['IsPublished'] != 'True': continue

                insert = False
                if 'Uuid' in post:
                    uuid = post['Uuid']
                    localPost = self.postService.getByUuidAndSource(
                        uuid, source.Id)
                else:
                    #To support old instances that don't have Uuid attribute
                    uuid = str(uuid4().hex)
                    localPost = None

                if localPost == None:
                    if 'DeletedOn' in post: continue
                    localPost = Post()
                    localPost.Uuid = uuid
                    insert = True

                if 'DeletedOn' not in post:
                    #TODO: workaround, read again the Author because sometimes we get access denied
                    post['Author'] = self._readAuthor(post['Author']['href'])
                    post['Creator'] = self._readCreator(
                        post['Creator']['href'])

                    #if exists local, update it, otherwise continue the original insert
                    localPost.Type = post['Type']['Key']
                    localPost.Author, localPost.Creator, needUpdate, isAuthor = self._getCollaboratorForAuthor(
                        post['Author'], post['Creator'], source)
                    localPost.Feed = source.Id
                    localPost.Meta = post['Meta'] if 'Meta' in post else None
                    localPost.ContentPlain = post[
                        'ContentPlain'] if 'ContentPlain' in post else None
                    localPost.Content = post[
                        'Content'] if 'Content' in post else None
                    localPost.Order = post['Order'] if 'Order' in post else None
                    localPost.CreatedOn = current_timestamp()
                    if blogSync.Auto:
                        localPost.PublishedOn = current_timestamp()
                        localPost.WasPublished = True

                    log.info("received post: %s", str(localPost))

                    if localPost.Creator and (
                            localPost.Creator
                            not in usersForIcons) and needUpdate:
                        try:
                            if isAuthor:
                                usersForIcons[
                                    localPost.Creator] = post['Author']['User']
                            else:
                                usersForIcons[
                                    localPost.Creator] = post['Creator']
                        except KeyError:
                            pass

                else:
                    localPost.DeletedOn = datetime.strptime(
                        post['DeletedOn'], '%m/%d/%y %I:%M %p')

                # prepare the blog sync model to update the change identifier
                blogSync.CId = int(post['CId']) if blogSync.CId is None or int(
                    post['CId']) > blogSync.CId else blogSync.CId

                if insert:
                    self.blogPostService.insert(blogSync.Blog, localPost)
                else:
                    self.blogPostService.update(blogSync.Blog, localPost)

                # update blog sync entry
                blogSync.LastActivity = datetime.now().replace(microsecond=0)
                self.blogSyncService.update(blogSync)

            except KeyError as e:
                log.error('Post from source %s is missing attribute %s' %
                          (source.URI, e))
            except Exception as e:
                log.error('Error in source %s post: %s' % (source.URI, e))

        self._updateIcons(usersForIcons)

        blogSync.LastActivity = None
        self.blogSyncService.update(blogSync)

    def _getCollaboratorForAuthor(self, author, creator, source):
        '''
        Returns a collaborator identifier for the user/source defined in the post.
        If the post was not created by a user (it is twitter, facebook, etc. post) 
        it returns a collaborator for the user that has added the post.

        @param author: dict
            The author data in JSON decoded format
        @param creator: dict
            The creator data in JSON decoded format
        @param source: Source
            The source from which the blog synchronization is done
        @return: integer
            The collaborator identifier.
        '''
        assert isinstance(source, Source)

        user = User()

        isAuthor = False

        if 'User' in author:
            userJSON = author['User']
            isAuthor = True
        else:
            userJSON = creator

        #To support old instances that don't have Uuid attribute
        if 'Uuid' in userJSON: user.Uuid = userJSON.get('Uuid', '')
        else: user.Uuid = str(uuid4().hex)

        if 'Cid' in userJSON: cid = int(userJSON.get('Cid', ''))
        else: cid = None

        user.Name = user.Uuid
        user.FirstName, user.LastName = userJSON.get('FirstName',
                                                     ''), userJSON.get(
                                                         'LastName', '')
        user.Address, user.PhoneNumber = userJSON.get('Address',
                                                      ''), userJSON.get(
                                                          'PhoneNumber', '')
        user.EMail, user.Password = userJSON.get('EMail', ''), '~'
        user.Type = self.user_type_key

        needUpdate = True
        try:
            userId = self.userService.insert(user)
        except InputError:
            localUser = self.userService.getByUuid(user.Uuid)
            userId = localUser.Id
            if localUser.Type == self.user_type_key and (cid is None or
                                                         localUser.Cid < cid):
                user.Id = localUser.Id
                user.Type = localUser.Type
                user.Cid = cid
                self.userService.update(user)
            else:
                needUpdate = False

        collaborator = Collaborator()
        collaborator.User, collaborator.Source = userId, source.Id
        try:
            collaboratorId = self.collaboratorService.insert(collaborator)
        except InputError:
            collaborators = self.collaboratorService.getAll(userId, source.Id)
            collaboratorId = collaborators[0].Id

        if isAuthor:
            return [collaboratorId, userId, needUpdate, isAuthor]
        else:
            q = QSource(name=author['Source']['Name'], isModifiable=False)
            sources = self.sourceService.getAll(q=q)
            if not sources: raise Exception('Invalid source %s' % q.name)
            collaborators = self.collaboratorService.getAll(
                userId=None, sourceId=sources[0].Id)
            if collaborators:
                return [collaborators[0].Id, userId, needUpdate, isAuthor]
            else:
                collaborator = Collaborator()
                collaborator.Source = sources[0].Id
                return [
                    self.collaboratorService.insert(collaborator), userId,
                    needUpdate, isAuthor
                ]

    def _updateIcons(self, usersData):
        '''
        Setting the icon of the user
        '''
        userIcons = {}
        for userId in usersData:
            userJSON = usersData[userId]
            userIcons[userId] = {'url': None, 'name': None}

            try:
                metaDataIconJSON = userJSON['MetaDataIcon']
                metaDataIconURL = metaDataIconJSON.get('href', '')
                if not metaDataIconURL:
                    continue

                (scheme, netloc, path, params, query,
                 fragment) = urlparse(metaDataIconURL)
                if not scheme:
                    metaDataIconURL = urlunparse(
                        ('http', netloc, path, params, query, fragment))

                req = Request(metaDataIconURL,
                              headers={
                                  'Accept': self.acceptType,
                                  'Accept-Charset': self.encodingType,
                                  'User-Agent': 'Magic Browser'
                              })
                try:
                    resp = urlopen(req)
                except (HTTPError, socket.error) as e:
                    continue
                if str(resp.status) != '200':
                    continue

                try:
                    msg = json.load(codecs.getreader(self.encodingType)(resp))
                except ValueError as e:
                    log.error('Invalid JSON data %s' % e)
                    continue

                userIcons[userId]['url'] = msg['Content'].get('href', None)

                if userIcons[userId]['url']:
                    iconFileName = userIcons[userId]['url'].split('/')[-1]
                    if iconFileName:
                        iconFileName = '_' + iconFileName
                    userIcons[userId]['name'] = 'icon_' + str(
                        userId) + iconFileName

            except KeyError:
                continue

        for userId in userIcons:
            iconInfo = userIcons[userId]
            self._synchronizeIcon(userId, iconInfo)

    def _synchronizeIcon(self, userId, iconInfo):
        '''
        Synchronizing local icon according to the remote one
        '''
        if not userId:
            return

        shouldRemoveOld = False
        needToUploadNew = False

        try:
            metaDataLocal = self.personIconService.getByPersonId(
                userId, 'http')
        except InputError:
            metaDataLocal = None

        if metaDataLocal:
            localId = metaDataLocal.Id
            localName = metaDataLocal.Name
        else:
            localId = None
            localName = None

        if not localId:
            if iconInfo['url']:
                needToUploadNew = True

        else:
            if iconInfo['url']:
                #on changed avatar the name of the file is changed
                if (not iconInfo['name']) or (not localName) or (
                        localName != iconInfo['name']):
                    shouldRemoveOld = True
                    needToUploadNew = True
            else:
                shouldRemoveOld = True

        if shouldRemoveOld:
            try:
                self.personIconService.detachIcon(userId)
                #self.metaInfoService.delete(localId)
            except InputError:
                log.error('Can not remove old icon for chained user %s' %
                          userId)

        if needToUploadNew:
            try:
                iconContent = ChainedIconContent(iconInfo['url'],
                                                 iconInfo['name'])
                imageData = self.metaDataService.insert(
                    userId, iconContent, 'http')
                if (not imageData) or (not imageData.Id):
                    return
                self.personIconService.setIcon(userId, imageData.Id, False)
            except InputError:
                log.error('Can not upload icon for chained user %s' % userId)

    def _readAuthor(self, url):

        (scheme, netloc, path, params, query, fragment) = urlparse(url)
        if not scheme:
            url = urlunparse(('http', netloc, path, params, query, fragment))

        request = Request(url,
                          headers={
                              'Accept': self.acceptType,
                              'Accept-Charset': self.encodingType,
                              'User-Agent': 'Magic Browser',
                              'X-Filter': '*,User.*,Source.*'
                          })

        try:
            response = urlopen(request)
        except (HTTPError, socket.error) as e:
            return None

        if str(response.status) != '200':
            return None

        try:
            return json.load(codecs.getreader(self.encodingType)(response))
        except ValueError as e:
            log.error('Invalid JSON data %s' % e)
            return None

    def _readCreator(self, url):

        (scheme, netloc, path, params, query, fragment) = urlparse(url)
        if not scheme:
            url = urlunparse(('http', netloc, path, params, query, fragment))

        request = Request(url,
                          headers={
                              'Accept': self.acceptType,
                              'Accept-Charset': self.encodingType,
                              'User-Agent': 'Magic Browser',
                              'X-Filter': '*'
                          })

        try:
            response = urlopen(request)
        except (HTTPError, socket.error) as e:
            return None

        if str(response.status) != '200':
            return None

        try:
            return json.load(codecs.getreader(self.encodingType)(response))
        except ValueError as e:
            log.error('Invalid JSON data %s' % e)
            return None
Пример #30
0
class BlogCollaboratorServiceAlchemy(SessionSupport, IBlogCollaboratorService):
    '''
    Implementation for @see: IBlogCollaboratorService
    '''

    collaboratorSpecification = CollaboratorSpecification
    wire.entity('collaboratorSpecification')
    userActionService = IUserActionService
    wire.entity('userActionService')
    default_user_type_key = 'standard'
    wire.config('default_user_type_key',
                doc='''
    Default user type for users without specified the user type key''')
    internal_source_name = 'internal'
    wire.config('internal_source_name',
                doc='''
    Source for collaborators''')

    def __init__(self):
        '''
        Construct the blog collaborator service.
        '''
        assert isinstance(self.collaboratorSpecification, CollaboratorSpecification), \
        'Invalid collaborator specification %s' % self.collaboratorSpecification
        assert isinstance(self.userActionService, IUserActionService), \
        'Invalid user actions service %s' % self.userActionService
        super().__init__()

        self._collaboratorTypeIds = {}

    def getAllTypes(self):
        '''
        @see: IBlogCollaboratorService.getAllTypes
        '''
        return self.session().query(BlogCollaboratorTypeMapped).all()

    def getActions(self, userId, blogId, path=None, origPath=None):
        '''
        @see: IBlogCollaboratorService.getActions
        '''
        actions = list(self.userActionService.getAll(userId, path))
        paths = {a.Path for a in actions}
        for name, f in self.collaboratorSpecification.type_filter:
            assert isinstance(f, Filter), 'Invalid filter'
            assert isinstance(f.filter, IAclFilter)
            if f.filter.isAllowed(userId, blogId):
                collActions = list(
                    self.collaboratorSpecification.type_actions.get(name))
                collPaths = {a.Path for a in collActions}.difference(paths)
                actions.extend([
                    action for action in collActions
                    if action.Path in collPaths
                ])
                break
        return actions

    def getById(self, blogId, collaboratorId):
        '''
        @see: IBlogCollaboratorService.getById
        '''
        sql = self.session().query(BlogCollaboratorMapped)
        sql = sql.filter(BlogCollaboratorMapped.Blog == blogId)
        sql = sql.filter(BlogCollaboratorMapped.Id == collaboratorId)

        try:
            return sql.one()
        except NoResultFound:
            raise InputError(
                Ref(_('No collaborator'), ref=BlogCollaboratorMapped.Id))

    def getAll(self, blogId, offset=None, limit=None, detailed=True):
        '''
        @see: IBlogCollaboratorService.getAll
        '''
        sql = self.session().query(BlogCollaboratorMapped).filter(
            BlogCollaboratorMapped.Blog == blogId)
        sql = sql.join(UserMapped).join(SourceMapped).order_by(
            BlogCollaboratorMapped.Name)
        sql = sql.filter(UserMapped.Active == True)
        sql = sql.filter(UserMapped.Type == self.default_user_type_key)

        sqlLimit = buildLimits(sql, offset, limit)
        if detailed:
            return IterPart(sqlLimit.all(), sql.count(), offset, limit)
        return sqlLimit.all()

    def getPotential(self,
                     blogId,
                     excludeSources=True,
                     offset=None,
                     limit=None,
                     detailed=True,
                     qu=None,
                     qs=None):
        '''
        @see: IBlogCollaboratorService.getPotential
        '''
        sqlBlog = self.session().query(BlogCollaboratorMapped.Id).filter(
            BlogCollaboratorMapped.Blog == blogId)
        sql = self.session().query(CollaboratorMapped)
        sql = sql.join(UserMapped, CollaboratorMapped.User == UserMapped.Id)
        sql = sql.join(SourceMapped,
                       SourceMapped.Id == CollaboratorMapped.Source)
        sql = sql.filter(not_(CollaboratorMapped.Id.in_(sqlBlog)))
        sql = sql.filter(UserMapped.Active == True)
        sql = sql.filter(UserMapped.Type == self.default_user_type_key)
        sql = sql.filter(SourceMapped.Name == self.internal_source_name)
        sql = sql.order_by(CollaboratorMapped.Name)
        if excludeSources: sql = sql.filter(CollaboratorMapped.User != None)
        if qu: sql = buildQuery(sql, qu, UserMapped)
        if qs: sql = buildQuery(sql, qs, SourceMapped)
        sqlLimit = buildLimits(sql, offset, limit)
        if detailed:
            return IterPart(sqlLimit.distinct(),
                            sql.distinct().count(), offset, limit)
        return sqlLimit.distinct()

    def addCollaboratorAsDefault(self, blogId, collaboratorId):
        '''
        @see: IBlogCollaboratorService.addCollaboratorAsDefault
        '''
        self.addCollaborator(
            blogId, collaboratorId,
            self.collaboratorSpecification.collaborator_types[0])

    def addCollaborator(self, blogId, collaboratorId, typeName):
        '''
        @see: IBlogCollaboratorService.addCollaborator
        '''
        typeId = self.collaboratorTypeIds()[typeName]
        if typeId is None:
            raise InputError(
                Ref(_('Invalid collaborator type'), ref=BlogCollaborator.Type))

        sql = self.session().query(BlogCollaboratorEntry)
        sql = sql.filter(BlogCollaboratorEntry.Blog == blogId)
        sql = sql.filter(
            BlogCollaboratorEntry.blogCollaboratorId == collaboratorId)
        if sql.update({BlogCollaboratorEntry.typeId: typeId}) > 0: return

        sql = self.session().query(BlogCollaboratorMapped.Id)
        sql = sql.join(BlogMapped)
        sql = sql.filter(BlogCollaboratorMapped.User == BlogMapped.Creator)
        sql = sql.filter(BlogMapped.Id == blogId)
        sql = sql.filter(BlogCollaboratorMapped.Id == collaboratorId)
        if sql.count() > 0:
            raise InputError(
                _('The blog creator cannot be assigned as a collaborator'))

        bgc = BlogCollaboratorEntry()
        bgc.Blog = blogId
        bgc.blogCollaboratorId = collaboratorId
        bgc.typeId = typeId
        self.session().add(bgc)
        self.session().flush((bgc, ))

    def removeCollaborator(self, blogId, collaboratorId):
        '''
        @see: IBlogCollaboratorService.removeCollaborator
        '''
        try:
            sql = self.session().query(BlogCollaboratorEntry)
            sql = sql.filter(BlogCollaboratorEntry.Blog == blogId)
            sql = sql.filter(
                BlogCollaboratorEntry.blogCollaboratorId == collaboratorId)
            return sql.delete() > 0
        except OperationalError:
            raise InputError(
                Ref(_('Cannot remove'), model=BlogCollaboratorMapped))

    # ----------------------------------------------------------------

    def collaboratorTypeIds(self):
        '''
        Provides the collaborator types ids dictionary.
        '''
        if not self._collaboratorTypeIds:
            for name in self.collaboratorSpecification.collaborator_types:
                sql = self.session().query(BlogCollaboratorTypeMapped)
                sql = sql.filter(BlogCollaboratorTypeMapped.Name == name)
                try:
                    bt = sql.one()
                except NoResultFound:
                    bt = BlogCollaboratorTypeMapped()
                    bt.Name = name
                    self.session().add(bt)
                    self.session().flush((bt, ))
                self._collaboratorTypeIds[name] = bt.id
        return self._collaboratorTypeIds