How do I search for unpublished Plone content in an IPython debug shell?

I like to use IPython's zope profile to inspect my Plone instance, but a few annoying permissions differences come up compared to inserting a breakpoint and hitting it with the admin user.

For example, I would like to iterate over the content objects in an unpublished testing folder. This query will return no results in the shell, but works from a breakpoint.

$ bin/instance shell
$ ipython --profile=zope

from Products.CMFPlone.utils import getToolByName
catalog = getToolByName(context, 'portal_catalog')
catalog({'path':'Plone/testing'})

Can I authenticate as admin or otherwise rejigger the permissions to fully manipulate my site from ipython?


Asked by: Miranda697 | Posted: 05-10-2021






Answer 1

here's the (very dirty) code I use to manage my plone app from the debug shell. It may requires some updates depending on your versions of Zope and Plone.

from sys import stdin, stdout, exit
import base64
from thread import get_ident
from ZPublisher.HTTPRequest import HTTPRequest
from ZPublisher.HTTPResponse import HTTPResponse
from ZPublisher.BaseRequest import RequestContainer
from ZPublisher import Publish

from AccessControl import ClassSecurityInfo, getSecurityManager
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.User import UnrestrictedUser

def loginAsUnrestrictedUser():
    """Exemple of use :
        old_user = loginAsUnrestrictedUser()
        # Manager stuff
        loginAsUser(old_user)
    """
    current_user = getSecurityManager().getUser()
    newSecurityManager(None, UnrestrictedUser('manager', '', ['Manager'], []))
    return current_user

def loginAsUser(user):
    newSecurityManager(None, user)

def makerequest(app, stdout=stdout, query_string=None, user_pass=None):
    """Make a request suitable for CMF sites & Plone
      - user_pass = "user:pass"
    """
    # copy from Testing.makerequest
    resp = HTTPResponse(stdout=stdout)
    env = {}
    env['SERVER_NAME'] = 'lxtools.makerequest.fr'
    env['SERVER_PORT'] = '80'
    env['REQUEST_METHOD'] = 'GET'
    env['REMOTE_HOST'] = 'a.distant.host'
    env['REMOTE_ADDR'] = '77.77.77.77'
    env['HTTP_HOST']   = '127.0.0.1'
    env['HTTP_USER_AGENT'] = 'LxToolsUserAgent/1.0'
    env['HTTP_ACCEPT']='image/gif, image/x-xbitmap, image/jpeg, */* '
    if user_pass:
        env['HTTP_AUTHORIZATION']="Basic %s" % base64.encodestring(user_pass)
    if query_string:
        p_q = query_string.split('?')
        if   len(p_q) == 1: 
            env['PATH_INFO'] = p_q[0]
        elif len(p_q) == 2: 
            (env['PATH_INFO'], env['QUERY_STRING'])=p_q
        else: 
            raise TypeError, ''
    req = HTTPRequest(stdin, env, resp)
    req['URL1']=req['URL'] # fix for CMFQuickInstaller
    #
    # copy/hacked from Localizer __init__ patches
    # first put the needed values in the request
    req['HTTP_ACCEPT_CHARSET'] = 'latin-9'
    #req.other['AcceptCharset'] = AcceptCharset(req['HTTP_ACCEPT_CHARSET'])
    #
    req['HTTP_ACCEPT_LANGUAGE'] = 'fr'
    #accept_language = AcceptLanguage(req['HTTP_ACCEPT_LANGUAGE'])
    #req.other['AcceptLanguage'] = accept_language 
    # XXX For backwards compatibility
    #req.other['USER_PREF_LANGUAGES'] = accept_language
    #req.other['AcceptLanguage'] = accept_language 
    #
    # Plone stuff
    #req['plone_skin'] = 'Plone Default'
    #
    # then store the request in Publish._requests
    # with the thread id
    id = get_ident()
    if hasattr(Publish, '_requests'):
        # we do not have _requests inside ZopeTestCase
        Publish._requests[id] = req
    # add a brainless session container
    req['SESSION'] = {}
    #
    # ok, let's wrap
    return app.__of__(RequestContainer(REQUEST = req))


def debug_init(app):
    loginAsUnrestrictedUser()
    app = makerequest(app)
    return app

This lives in a wshelpers Zope product. Once the debug shell launched, it's just a matter of;

>> from Products.wshelpers import wsdebug
>> app = wsdebug.debug_init(app)
>> # now you're logged in as admin

Answered by: Edward140 | Posted: 06-11-2021



Answer 2

Just use catalog.search({'path':'Plone/testing'}). It performs the same query as catalog() but does not filter the results based on the current user's permissions.

IPython's zope profile does provide a method utils.su('username') to change the current user, but it does not recognize the admin user (defined in /acl_users instead of /Plone/acl_users) and after calling it subsequent calls to catalog() fail with AttributeError: 'module' object has no attribute 'checkPermission'.

Answered by: Kirsten467 | Posted: 06-11-2021



Similar questions

python - How to get count of unpublished commit with GitPython?

With git status I can get information about count of unpublished commits: » git status # On branch master # Your branch is ahead of 'origin/master' by 2 commits. # (use "git push" to publish your local commits) # nothing to commit, working directory clean I want to get unpublished commits (or count) with GitPython. I docs I found repo.git.status(), ...


python - Django-CMS Unpublished page still navigable

I have 3 sites with Django-CMS sharing the same database and code but in different folders (the SITE_ID conf changes from folder to folder). They were suppose to have translations in en but for now we just want to show the pt pages so I unpublished all en pages. In my first site it works ok but in the other the en pages are visible in the published site instead of redirec...


python - If page is unpublished go to the next available page

I'm creating a webcomic using Django. I have a status choice field in my model: 1 to publish a page and 0 to unpublish it. STATUS = ( (0,"Draft"), (1,"Publish")) I have created two functions: the first one to go to the previous page and the second one to go to the next page. def get_previous(self): previous = Page.objects.filter(status=1).get(number=sel...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top