Managing personal and private content

Introduction

When an end user leaves your company, what happens to the analysis they create and curate? When you need to extract and promote a sheet from a Sense app in a managed space to a base-level asset, how do you do that?

In this tutorial, you are going to learn how to configure an OAuth machine-to-machine client to access resources located in personal spaces. In addition, you will learn how to access private content like sheets in a Qlik Sense analytics application to copy/paste it into another app and publish it.

Get started

To complete this tutorial you need:

  • A Qlik Cloud enterprise tenant.
  • Access to create an OAuth machine-to-machine client in the management console.
  • Knowledge of JavaScript or qlik-cli.

For the rest of this tutorial, the OAuth machine-to-machine client will be referred to as the private content bot.

1.0.0 Configuration

1.1.0 Create an OAuth client

Access the management console in your Qlik Cloud tenant and create a machine-to-machine OAuth client.

When you create the OAuth client:

  • Select the admin.apps scope.
  • Select the admin_classic scope.
  • Check the machine-to-machine grant type checkbox.

Save the OAuth client per the instructions in the OAuth client tutorial. Record the client_id and client_secret for later use.

You have created the private content bot.

1.2.0 Create a context in qlik-cli

Follow the directions in the qlik-cli-contexts tutorial to enable the private content bot with qlik-cli.

1.2.1 Create a host configuration in qlik-api

The qlik-api is a typescript typed library for accessing Qlik Cloud REST APIs and the Qlik Analytics Engine. The library works as an ES module only, so you may have to configure your package.json to support type: 'module'.

The hostConfig variable is where you input the information to connect to your Qlik Cloud tenant. Adding the scope property is optional as machine-to-machine tokens will automatically scope to their configuraiton in the management console.

Set qlik-api to use the hostConfig by issuing the auth.setDefaultHostConfig() command with the hostConfig variable as a parameter.

import { auth, spaces } from "@qlik/api";

const hostConfig = {
  host: "<your-tenant>.<region>.qlikcloud.com",
  authType: "oauth2",
  clientId: "<client-id>",
  clientSecret "<client-secret>",
  scope: "user_default admin.apps admin_classic",
};

auth.setDefaultHostConfig(hostConfig);

You can begin issuing requests as the private content bot using qlik-api.

2.0.0 Using the private content bot with qlik-api

2.1.0 List all analytics applications in personal spaces

In this example, the private content bot uses qlik-api to list all the analytics applications in personal spaces. In addition, the bot obtains the name of the application owner.

import { auth, users, items } from "@qlik/api";

(async () => {
  auth.setDefaultHostConfig(hostConfig);

  //get apps in personal spaces
  const itemList = await items
    .getItems({
      resourceType: "app",
      spaceType: "personal",
      limit: 100,
    })
    .then((res) => {
      return res.data;
    });
  
  //use a promise to return a new array of apps containing the app owner's name
  let appList = await Promise.all(
    itemList.data.map(async (item) => {
      return {
        id: item.id,
        resourceId: item.resourceId,
        name: item.name,
        ownerId: item.ownerId,
        ownerName: await getUserName(item.ownerId),
      };
    }),
  );
  console.log(appList);
  process.exit();
})();

//helper function that returns a name for the supplied userId
async function getUserName(userId) {
  const user = await users.getUser(userId);
  return user.data.name;
}

2.2.0 List a user’s private sheets in an analytics application

import { auth, qix} from '@qlik/api';

const appId = "ff345764-ee83-4488-8637-e93ddb7ccc47";

(async () => {
  auth.setDefaultHostConfig({
    authType: "oauth2",
    host: "<your-tenant>.<region>.qlik-stage.com",
    clientId: "<client-id>",
    clientSecret "<client-secret>",
    scope: "user_default admin.apps admin_classic",
  });

  const app = await qix.openAppSession(appId).getDoc();
  const sheets = await app.getSheetList();
  for(let sheet of sheets) {
    console.log(sheet.qMeta.title, sheet.qMeta.privileges, `Current publish status is:${sheet.qMeta.published}`);
  }
  process.exit();
})();

2.3.0 Publish a private sheet

import { auth, qix } from '@qlik/api';

const appId = "ff345764-ee83-4488-8637-e93ddb7ccc47";
const sheetId = "fa5fc527-3717-4a90-88f0-c6e4638c60b0";

(async () => {
  auth.setDefaultHostConfig(hostConfig);

  const app = await qix.openAppSession(appId).getDoc();
  const sheet = await app.getObject(sheetId);
  
  try {
    await sheet.publish();
    await app.doSave();
    console.log("Published");
  } catch (error) {
    console.log(error);
  }

  process.exit();
})();

2.4.0 Duplicate a sheet in an application

import { auth, users, items, qix, apps } from '@qlik/api';

const appId = "ff345764-ee83-4488-8637-e93ddb7ccc47";
const sheetId = "fa5fc527-3717-4a90-88f0-c6e4638c60b0";

(async () => {
  auth.setDefaultHostConfig(hostConfig);

  const app = await qix.openAppSession(appId).getDoc();
  const sheet = await app.getObject(sheetId);
  const sheetPropsTree = await sheet.getFullPropertyTree();

  //duplicate the sheet by creating a new object;
  //if you are inserting into a new app, you do not need to
  //change the object Id.
  sheetPropsTree.qProperty.qInfo.qId = "randoString21";

  //create the new sheet by supplying the QProperty attribute.
  const newSheet = await app.createObject(sheetPropsTree.qProperty);
  
  //get the properties so you can confirm the object id
  const newSheetProps = await newSheet.getProperties();
  console.log(newSheetProps);
  
  //save the app to persist changes
  await app.doSave();

  //run apps.updateAppObjectOwner to change the owner of the sheet
  try {
    const co = await apps.updateAppObjectOwner(appId,newSheetProps.qInfo.qId,{"ownerId": "64fb23dd7a7b40079f26346c"});
    await app.doSave();
    console.log(co);

  } catch (error) {
    console.log(error);
  }

  //sheet will show up in private. This example was performed
  //on an app in a managed space.

  process.exit();

})();

Conclusion

These are just a few of the different management actions you can take with the new private content bot.

Was this page helpful?