How to use PermissionDelegate for CustomContentType?

Hi all,

I created a custom ContentType object. I want to check user permission when search this object so I create a class MyTypePermissionDelegate which implements PermissionDelegate to check permission for my content type. In this class I override 2 method:

  1. @Override
    public boolean canView(final User user, final Object o)
    2)@Override
    public boolean canView( User user)

But when I use Confluence search to search my custom content type, I see that it does not call method 1, so I cannot check user permission on my custom content type.

Can anyone help me on this?

I assume that your custom ContentType implements ContentType. What is your ContentEntityAdapter then? The ContentEntityAdapter exposes a method “isIndexable”, which if returns false your object will never get indexed -> searched.

Hi @Panos,
My object is indexed and can be searched. But I want to check permission when a user want to search my object, so I implement PermissionDelegate interface, but I don’t find anyway to check permission here. Do you have any idea?

Thanks!

Post code of the object implementing the ContentType and of class that implements the PermissionDelegate.
Are you sure you are not getting any exceptions in the logs and that all modules are enabled?

Hi @Panos,
Please help to check the classes that I used for my content type.
The method canView(final User user, final Object o) of ProductPermissionDelegate never gets called.

Thanks,

public class ProductContentType implements ContentType {

public static final String KEY = ProductContentTypes.PRODUCT_CONTENT_TYPE_KEY;
private final ContentEntityAdapter contentEntityAdapter;
private final PermissionDelegate permissionDelegate;
private final ContentUiSupport contentUiSupport;

@Autowired
public ProductContentType(
        @Qualifier ("ProductContentEntityAdapter") final ContentEntityAdapter contentEntityAdapter,
        @Qualifier("ProductPermissionDelegate") final PermissionDelegate permissionDelegate)
{
    this.permissionDelegate = permissionDelegate;
    this.contentEntityAdapter = contentEntityAdapter;
    this.contentUiSupport = new ProductContentUiSupport();
}

@Override
public ContentEntityAdapter getContentAdapter()
{
    return contentEntityAdapter;
}

@Override
public PermissionDelegate getPermissionDelegate()
{
    return permissionDelegate;
}

@Override
public ContentUiSupport getContentUiSupport()
{
    return contentUiSupport;
}

}

@Component
public class ProductPermissionDelegate implements PermissionDelegate {

private final static Logger LOG = LoggerFactory.getLogger(ProductPermissionDelegate.class);
private final ProductManager ProductManager;
private final UserAccessor userAccessor;

@Autowired
public ProductPermissionDelegate(ProductManager ProductManager, UserAccessor userAccessor)
{
    this.ProductManager = ProductManager;
    this.userAccessor = userAccessor;
}

@Override
public boolean canView(final User user, final Object o)
{
    
    ConfluenceUser confluenceUser = user == null ? null : userAccessor.getUserByName(user.getName());
    if (o instanceof CustomContentEntityObject)
    {
        
        return canViewCustomContentEntityObject((CustomContentEntityObject) o);
    }

    return false;
}

@Override
public boolean canView(@Nullable User user) {

    

    return true;
    
}

@Override
public boolean canEdit(User user, Object o) {
    return true;
}

@Override
public boolean canSetPermissions(User user, Object o) {
    return true;
}

@Override
public boolean canRemove(User user, Object o) {
    return true;
}

@Override
public boolean canExport(User user, Object o) {
    return true;
}

@Override
public boolean canAdminister(User user, Object o) {
    return true;
}

@Override
public boolean canCreate(User user, Object o) {
    return true;
}

@Override
public boolean canCreateInTarget(User user, Class aClass) {
    return true;
}

protected boolean canViewCustomContentEntityObject(CustomContentEntityObject contentEntityObject)
{
    
    String contentKey = contentEntityObject.getPluginModuleKey();
    String spaceKey = contentEntityObject.getProperties().getStringProperty(ProductContentTypes.SPACE_KEY);
    if (ProductContentType.KEY.equals(contentKey))
    {
        return ProductManager.hasViewingPermission(spaceKey);

    }

    return false;
}

}

@Component
public class ProductContentEntityAdapter extends ContentEntityAdapterParent {

@Override
public Option<String> getUrlPath(CustomContentEntityObject cceo)
{
    String spaceKey = getSpaceKey(cceo);
    String ProductId = getProductId(cceo);

    if(StringUtils.isEmpty(spaceKey)){
        return Option.some("/my/Products/" + ProductId);
    }

    return Option.some("/display/" + spaceKey + "/my/Products/" + ProductId);
}

@Override
public Option<String> getDisplayTitle(CustomContentEntityObject pluginContentEntityObject)
{
    return Option.some(pluginContentEntityObject.getTitle());
}

@Override
public BodyType getDefaultBodyType(CustomContentEntityObject pluginContentEntityObject)
{
    return BodyType.XHTML;
}

@Override
public Option<String> getExcerpt(CustomContentEntityObject pluginContentEntityObject)
{
    return Option.some(pluginContentEntityObject.getBodyAsString());
}

public boolean isIndexable(final CustomContentEntityObject pluginContentEntityObject, final boolean isDefaultIndexable)
{
    return true;
}

private String getProductId(CustomContentEntityObject pluginContentEntityObject)
{
    return pluginContentEntityObject.getProperties().getStringProperty(ProductContentTypes.Product_ID);
}

private String getSpaceKey(CustomContentEntityObject pluginContentEntityObject)
{
    return pluginContentEntityObject.getProperties().getStringProperty(ProductContentTypes.SPACE_KEY);
}

}

public class ProductContentTypeManager implements InitializingBean, DisposableBean {

private final static Logger LOG = LoggerFactory.getLogger(ProductContentTypeManager.class);
SaveContext RETAIN_MODIFICATION_DATA = new DefaultSaveContext(false, true, false);

private final CustomContentManager customContentManager;
private final EventPublisher eventPublisher;

public  ProductContentTypeManager(CustomContentManager customContentManager, EventPublisher eventPublisher)
{
    this.customContentManager = customContentManager;
    this.eventPublisher = eventPublisher;
}

@Override
public void destroy() throws Exception {
    eventPublisher.unregister(this);
}

@Override
public void afterPropertiesSet() throws Exception {
    eventPublisher.register(this);
}

@EventListener
public void handleProductCreated(ProductEvent ProductEvent)
{        
    Product product = ProductEvent.getProduct();

    CustomContentEntityObject productContentEntity = customContentManager.newPluginContentEntityObject(ProductContentType.KEY);

    productContentEntity.setTitle(product.getTitle());
    productContentEntity.setBodyAsString(StringEscapeUtils.escapeHtml(product.getBody()));
    productContentEntity.getProperties().setStringProperty(ProductContentTypes.SPACE_KEY, product.getSpaceKey());
    productContentEntity.getProperties().setStringProperty(ProductContentTypes.Product_ID, Long.toString(product.getId()));

    customContentManager.saveContentEntity(productContentEntity, RETAIN_MODIFICATION_DATA);
}

}

a) Check your addon in the admin page, are all modules enabled?
b) Change the @Component in your ProductPermissionDelegate class to @Component(“productPermissionDelegate”) and the Qualifier in the ProductContentType to productPermissionDelegate as well.

If that doesn’t fix it, post your error logs, should probably be something there

Hi @Panos,

All of my plugin modules are enabled.
I changed the code based on your suggestion, it still doesn’t work. It only calls public boolean canView(@Nullable User user) instead of public boolean canView(final User user, final Object o).
So I cannot check permission on each custom content type instance. For example: I have Product 1 of space S1, Product 2 of space S2. I want to check permission before return to the search result of Confluence, ony users who have permission can see the result in Confluence search page: http://localhost:8080/confluence/dosearchsite.action?queryString=product

Would you please share me any idea?
Thank you very much for your help!

Weird… Are you maybe targeting other confluence version? Check your pom.xml, does the version in the dependency of confluence (groupId: com.atlassian.confluence artifactId: confluence) matches with your server’s version?

Thank you Panos!
I figure out the issue. Just need to set the space for the Custom entity

Can i see your code for setting the space?