Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cms-oss-doc/src/main/guides.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ index:
- title: "Editor and Administration User Interfaces"
text: "Overview of Gentics CMS user interfaces"
url: userinterfaces
- title: "API Tokens"
text: "How users can create and manage their own API Tokens"
url: api_token
- title: "Features"
url: oss-feature_overview
text: "Overview of Gentics CMS features"
Expand Down
39 changes: 39 additions & 0 deletions cms-oss-doc/src/main/source/api_tokens.textile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
h2. API Tokens

Every user can create and manage their own API tokens in the API Token Manager. The API Token Manager
is available in the user menu of the Editor and Administration User Interface.

endprologue.

h3. Overview

The API Token Manager is opened from the user menu: click the user image in the top right corner of
the "Editor or Administration User Interface":userinterfaces.html and choose the API token entry -
the same menu that also contains the entry for changing the password.

h3. Creating a token

The token creation dialog requires the user to provide a name. An expiry date can optionally be specified.

* *Name* – Required. The name used to identify the token.
* *Expiry date* – Optional. The date on which the token expires.

WARNING: The token value is shown only once directly after creation and cannot be retrieved again afterwards.

h3. Listing tokens

The token list shows the following information for each API token:

* *Name* – The name assigned to the token when it was created.
* *Creation date* – The date on which the token was created.
* *Expiry date* – The date on which the token expires, if an expiry date was specified.

h3. Revoking a token

A token can be revoked by deleting it directly from the token list. Once deleted, the token is no longer
valid and cannot be used for authentication.

h3. Permissions

Users need the appropriate permission to manage API tokens. Users with this permission can create, list,
and revoke their own tokens.
13 changes: 13 additions & 0 deletions cms-oss-doc/src/main/source/feature_mesh_contentrepository.textile
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,16 @@ To support languages in the CMS with codes not defined in ISO-639-1, they need t
h3. GIS image variants publication

With CMP 8.1, Mesh has the capability to generate all the Gentics Image Store image variants referenced from the content, during the publish run only, and store it in the database instead of the cache, disabling the ability to trigger a service denial on random GIS resized image requests in the runtime. This feature can be enabled per Node with the @Publish GIS image variants to Mesh@ checkbox.

h3. User API Tokens

API tokens can be maintained for users. Users with the required permissions can create and manage API tokens for other users.

To manage API tokens, go to Management → Users. For the desired user, click on "Manage API Tokens" (the key symbol)

Each API token has a Name and an optional Expiration Date:

Name: A descriptive name for the API token.
Expiration Date: An optional date specifying when the API token expires. If no expiration date is specified, the token does not expire.

API tokens can be deleted at any time. Deleting an API token invalidates the token and prevents it from being used.
27 changes: 11 additions & 16 deletions cms-ui/apps/admin-ui/e2e/api-tokens.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import {
TestSize,
UserImportData,
} from '@gentics/e2e-utils';
import { expect, Page, test } from '@playwright/test';
import { expect, Locator, Page, test } from '@playwright/test';
import { cloneWithSymbols } from '@gentics/common';
import { AccessControlledType, GcmsPermission, LoginResponse } from '@gentics/cms-models';
import { dateShouldBeDisabled, setGtxDateFromXpath } from './helpers';

const API_MODAL = 'gtx-api-tokens-modal';
const API_CREATE_MODAL = 'gtx-api-tokens-create-modal';
Expand Down Expand Up @@ -120,29 +121,21 @@ test.describe('Api Tokens', () => {

await expect(submitBtn.locator('button')).toBeEnabled();

const dateInput = form.locator('input[type="date"]');
const dateInput = form.locator('gtx-date-time-picker');

// fill with date from yesterday
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);

await dateInput.fill(yesterday.toISOString().split('T')[0]);

await expect(submitBtn.locator('button')).toBeDisabled();
// date from yesterday should be disabled
await dateShouldBeDisabled(page, form, 'xpath=preceding-sibling::button[1]');

// fill with date from tomorrow
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);

await dateInput.fill(tomorrow.toISOString().split('T')[0]);
await setGtxDateFromXpath(page, dateInput, 'xpath=following-sibling::button[1]');

await expect(submitBtn.locator('button')).toBeEnabled();

await submitBtn.click();

await expect(page.locator('.success-message')).toBeVisible();
await expect(page.locator('gtx-copy-token-modal')).toBeVisible();
await expect(findNotification(page, 'api-token-create-success')).toBeVisible();
await expect(page.locator('.success-message').locator('.content')).toHaveText(/\S+/);
await expect(page.locator('gtx-copy-token-modal').locator('.content')).toHaveText(/\S+/);
});

test('can delete Api Tokens', async ({ page }) => {
Expand All @@ -155,6 +148,8 @@ test.describe('Api Tokens', () => {

const row = table.locator('.data-row').first();

const rowId = await row.getAttribute('data-id');

const deleteButton = findTableAction(row, 'delete');

await deleteButton.click();
Expand All @@ -165,7 +160,7 @@ test.describe('Api Tokens', () => {

await expect(findNotification(page, 'api-token-delete-success')).toBeVisible();

await expect(row).not.toBeAttached();
await expect(table.locator(`.data-row[data-id="${rowId}"]`)).not.toBeAttached();
});

test('can delete multiple Api Tokens', async ({ page }) => {
Expand Down
5 changes: 5 additions & 0 deletions cms-ui/apps/admin-ui/e2e/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ export const AUTH = {
password: 'cms_integrationTest#node',
},
};

export const ADMIN = {
username: 'admin',
password: 'admin',
};
29 changes: 28 additions & 1 deletion cms-ui/apps/admin-ui/e2e/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export async function navigateToModule(page: Page, moduleId: string): Promise<Lo
* Logs out from the mesh management interface
*/
export async function logoutMeshManagement(page: Page): Promise<void> {
const req = page.waitForResponse(response =>
const req = page.waitForResponse((response) =>
response.ok() && matchesPath(response.url(), '/rest/contentrepositories/*/proxy/api/v2/auth/logout'),
);
await page.locator('.management-container .logout-button').click();
Expand All @@ -42,3 +42,30 @@ export async function loginWithCR(page: Page, shouldBeLoggedIn: boolean = true):
export function findEntityTableActionButton(source: Page | Locator, action: string): Locator {
return source.locator(`.entity-table-actions-bar .table-action-button[data-action="${action}"] button`);
}

export async function setGtxDateFromXpath(page: Page, dateInput: Locator, xPath: string): Promise<void> {
await dateInput.click();

const modal = page.locator('gtx-date-time-picker-modal');

await modal.waitFor({ state: 'visible' });

await modal.locator('.day.active').locator(xPath).click();
await modal.locator('[data-action="confirm"] button').click();
}

export async function dateShouldBeDisabled(page: Page, createTokenModalForm: Locator, xPath: string): Promise<void> {
const nameInput = createTokenModalForm.locator('input[type="text"]');
await nameInput.fill('test');

const dateInput = createTokenModalForm.locator('gtx-date-time-picker');

await dateInput.click();

const modal = page.locator('gtx-date-time-picker-modal');

await modal.waitFor({ state: 'visible' });

await modal.locator('.day.active').locator(xPath).isDisabled();
await modal.locator('.modal-footer [data-action="cancel"]').click();
}
Loading