Browse Source

Merge branch 'develop' into nc-fix/swagger-base-pw

pull/9543/head
Raju Udava 2 months ago
parent
commit
6efdd79d4b
  1. 3
      packages/nc-gui/components/account/Token.vue
  2. 2
      packages/nc-gui/components/tabs/auth/ApiTokenManagement.vue
  3. 8
      packages/nocodb/src/controllers/api-tokens.controller.ts
  4. 6
      packages/nocodb/src/controllers/org-tokens.controller.ts
  5. 16
      packages/nocodb/src/models/ApiToken.ts
  6. 243
      packages/nocodb/src/schema/swagger-v2.json
  7. 14
      packages/nocodb/src/schema/swagger.json
  8. 8
      packages/nocodb/src/services/api-tokens.service.ts
  9. 2
      packages/nocodb/src/services/app-hooks/interfaces.ts
  10. 8
      packages/nocodb/src/services/org-tokens.service.ts

3
packages/nc-gui/components/account/Token.vue

@ -140,7 +140,8 @@ const isValidTokenName = ref(false)
const deleteToken = async (token: string): Promise<void> => { const deleteToken = async (token: string): Promise<void> => {
try { try {
await api.orgTokens.delete(token) const id = allTokens.value.find((t) => t.token === token)?.id
await api.orgTokens.delete(id)
// message.success(t('msg.success.tokenDeleted')) // message.success(t('msg.success.tokenDeleted'))
await loadTokens() await loadTokens()

2
packages/nc-gui/components/tabs/auth/ApiTokenManagement.vue

@ -67,7 +67,7 @@ const deleteToken = async () => {
try { try {
if (!base.value?.id || !selectedTokenData.value.token) return if (!base.value?.id || !selectedTokenData.value.token) return
await $api.apiToken.delete(base.value.id, selectedTokenData.value.token) await $api.apiToken.delete(base.value.id, selectedTokenData.value.id)
// Token deleted successfully // Token deleted successfully
message.success(t('msg.success.tokenDeleted')) message.success(t('msg.success.tokenDeleted'))

8
packages/nocodb/src/controllers/api-tokens.controller.ts

@ -47,13 +47,13 @@ export class ApiTokensController {
} }
@Delete([ @Delete([
'/api/v1/db/meta/projects/:baseId/api-tokens/:token', '/api/v1/db/meta/projects/:baseId/api-tokens/:tokenId',
'/api/v2/meta/bases/:baseId/api-tokens/:token', '/api/v2/meta/bases/:baseId/api-tokens/:tokenId',
]) ])
@Acl('baseApiTokenDelete') @Acl('baseApiTokenDelete')
async apiTokenDelete(@Req() req: NcRequest, @Param('token') token: string) { async apiTokenDelete(@Req() req: NcRequest, @Param('tokenId') tokenId: string) {
return await this.apiTokensService.apiTokenDelete({ return await this.apiTokensService.apiTokenDelete({
token, tokenId,
user: req['user'], user: req['user'],
req, req,
}); });

6
packages/nocodb/src/controllers/org-tokens.controller.ts

@ -55,15 +55,15 @@ export class OrgTokensController {
}); });
} }
@Delete('/api/v1/tokens/:token') @Delete('/api/v1/tokens/:tokenId')
@Acl('apiTokenDelete', { @Acl('apiTokenDelete', {
scope: 'org', scope: 'org',
// allowedRoles: [OrgUserRoles.SUPER], // allowedRoles: [OrgUserRoles.SUPER],
blockApiTokenAccess: true, blockApiTokenAccess: true,
}) })
async apiTokenDelete(@Req() req: NcRequest, @Param('token') token: string) { async apiTokenDelete(@Req() req: NcRequest, @Param('tokenId') tokenId: string) {
await this.orgTokensService.apiTokenDelete({ await this.orgTokensService.apiTokenDelete({
token, tokenId,
user: req['user'], user: req['user'],
req, req,
}); });

16
packages/nocodb/src/models/ApiToken.ts

@ -66,16 +66,17 @@ export default class ApiToken implements ApiTokenType {
return tokens?.map((t) => new ApiToken(t)); return tokens?.map((t) => new ApiToken(t));
} }
static async delete(token, ncMeta = Noco.ncMeta) { static async delete(tokenId: string, ncMeta = Noco.ncMeta) {
const tokenData = await this.get(tokenId, ncMeta);
await NocoCache.deepDel( await NocoCache.deepDel(
`${CacheScope.API_TOKEN}:${token}`, `${CacheScope.API_TOKEN}:${tokenData.id}`,
CacheDelDirection.CHILD_TO_PARENT, CacheDelDirection.CHILD_TO_PARENT,
); );
return await ncMeta.metaDelete( return await ncMeta.metaDelete(
RootScopes.ROOT, RootScopes.ROOT,
RootScopes.ROOT, RootScopes.ROOT,
MetaTable.API_TOKENS, MetaTable.API_TOKENS,
{ token }, tokenId,
); );
} }
@ -165,4 +166,13 @@ export default class ApiToken implements ApiTokenType {
return queryBuilder; return queryBuilder;
} }
static async get(tokenId: string, ncMeta = Noco.ncMeta) {
return await ncMeta.metaGet(
RootScopes.ROOT,
RootScopes.ROOT,
MetaTable.API_TOKENS,
tokenId,
);
}
} }

243
packages/nocodb/src/schema/swagger-v2.json

@ -242,7 +242,7 @@
"tags": [ "tags": [
"Workspace base", "Bases" "Workspace base", "Bases"
], ],
"description": "This API fetches list of bases associated with the specified workspace ID. The workspace ID must be provided in the path as a required parameter. The API returns a list in JSON format, containing metadata and configuration for each base.", "description": "This API fetches list of bases associated with the specified workspace ID. The workspace ID must be provided in the path as a required parameter. The API returns a list in JSON format, containing metadata and configuration for each base. The API returns a paginated list of bases.\n\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\n\n- `totalRows`: Indicates the total number of bases available in the specified Workspace ID.\n- `page`: Specifies the current page number.\n- `pageSize`: Defaults to 25 and defines the number of base items listed on each page.\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of base records in the dataset.\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of base records in the dataset.",
"parameters": [ "parameters": [
{ {
"$ref": "#/components/parameters/xc-token" "$ref": "#/components/parameters/xc-token"
@ -1164,7 +1164,7 @@
"$ref": "#/components/responses/BadRequest" "$ref": "#/components/responses/BadRequest"
} }
}, },
"description": "List all users in the given base.", "description": "This endpoint allows you to list all users (collaborators) within a specified base. The API returns a paginated list of users.\\n\\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\\n\\n- `totalRows`: Indicates the total number of users available in the specified Base ID.\\n- `page`: Specifies the current page number.\\n- `pageSize`: Defaults to 25 and defines the number of user items listed on each page.\\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of user records in the dataset.\\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of user records in the dataset.",
"tags": [ "tags": [
"Auth", "Users" "Auth", "Users"
], ],
@ -2253,7 +2253,7 @@
"get": { "get": {
"summary": "List Sources", "summary": "List Sources",
"operationId": "source-list", "operationId": "source-list",
"description": "Get base source list", "description": "This endpoint allows you to list all (data) sources within a specified base. The API returns a paginated list of data sources.\\n\\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\\n\\n- `totalRows`: Indicates the total number of sources available in the specified Base ID.\\n- `page`: Specifies the current page number.\\n- `pageSize`: Defaults to 25 and defines the number of source items listed on each page.\\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of source records in the dataset.\\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of source records in the dataset.",
"parameters": [ "parameters": [
{ {
"$ref": "#/components/parameters/xc-token" "$ref": "#/components/parameters/xc-token"
@ -4905,7 +4905,7 @@
"tags": [ "tags": [
"DB View", "Views" "DB View", "Views"
], ],
"description": "List all views in a given Table.", "description": "This endpoint allows you to list all views within a specified table. The API returns a paginated list of views.\n\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\n\n- `totalRows`: Indicates the total number of views available in the specified Table ID.\n- `page`: Specifies the current page number.\n- `pageSize`: Defaults to 25 and defines the number of view items listed on each page.\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of view records in the dataset.\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of view records in the dataset.",
"parameters": [ "parameters": [
{ {
"$ref": "#/components/parameters/xc-token" "$ref": "#/components/parameters/xc-token"
@ -5214,7 +5214,7 @@
"$ref": "#/components/responses/BadRequest" "$ref": "#/components/responses/BadRequest"
} }
}, },
"description": "List all shared views in a given Table", "description": "This endpoint allows you to list all Shared Views within a specified table. The API returns a paginated list of shared views.\\n\\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\\n\\n- `totalRows`: Indicates the total number of shared views available in the specified Table ID.\\n- `page`: Specifies the current page number.\\n- `pageSize`: Defaults to 25 and defines the number of shared view items listed on each page.\\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of shared view records in the dataset.\\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of shared view records in the dataset.",
"tags": [ "tags": [
"DB View Share", "Shared Views" "DB View Share", "Shared Views"
], ],
@ -5657,7 +5657,7 @@
"tags": [ "tags": [
"DB Table Sort", "Sorts" "DB Table Sort", "Sorts"
], ],
"description": "List all the sort data in a given View", "description": "This endpoint allows you to list all sorts within a specified view. The API returns a paginated list of sorts.\\n\\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\\n\\n- `totalRows`: Indicates the total number of sorts available in the specified View ID.\\n- `page`: Specifies the current page number.\\n- `pageSize`: Defaults to 25 and defines the number of sort items listed on each page.\\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of sort records in the dataset.\\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of sort records in the dataset.",
"parameters": [ "parameters": [
{ {
"$ref": "#/components/parameters/xc-token" "$ref": "#/components/parameters/xc-token"
@ -5926,7 +5926,7 @@
"tags": [ "tags": [
"DB Table Filter", "Filters" "DB Table Filter", "Filters"
], ],
"description": "Get the filter data in a given View", "description": "This endpoint allows you to list all filters within a specified view. The API returns a paginated list of filters.\\n\\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\\n\\n- `totalRows`: Indicates the total number of filters available in the specified View ID.\\n- `page`: Specifies the current page number.\\n- `pageSize`: Defaults to 25 and defines the number of filter items listed on each page.\\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of filter records in the dataset.\\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of filter records in the dataset.",
"parameters": [ "parameters": [
{ {
"$ref": "#/components/parameters/xc-token" "$ref": "#/components/parameters/xc-token"
@ -10223,7 +10223,7 @@
"$ref": "#/components/responses/BadRequest" "$ref": "#/components/responses/BadRequest"
} }
}, },
"description": "List all hook records in the given Table", "description": "This endpoint allows you to list all webhooks within a specified table. The API returns a paginated list of webhooks.\\n\\n**Pagination**: The response is paginated by default, with the first page being returned initially. The response includes the following additional information in the `pageInfo` JSON block:\\n\\n- `totalRows`: Indicates the total number of webhooks available in the specified Table ID.\\n- `page`: Specifies the current page number.\\n- `pageSize`: Defaults to 25 and defines the number of webhook items listed on each page.\\n- `isFirstPage`: A boolean value that indicates whether the current page is the first page of webhook records in the dataset.\\n- `isLastPage`: A boolean value that indicates whether the current page is the last page of webhook records in the dataset.",
"parameters": [ "parameters": [
{ {
"$ref": "#/components/parameters/xc-token" "$ref": "#/components/parameters/xc-token"
@ -11544,7 +11544,7 @@
} }
] ]
}, },
"/api/v2/meta/bases/{baseId}/api-tokens/{token}": { "/api/v2/meta/bases/{baseId}/api-tokens/{tokenId}": {
"delete": { "delete": {
"summary": "Delete API Token", "summary": "Delete API Token",
"operationId": "api-token-delete", "operationId": "api-token-delete",
@ -11594,12 +11594,12 @@
{ {
"schema": { "schema": {
"type": "string", "type": "string",
"example": "DYh540o8hbWpUGdarekECKLdN5OhlgCUWutVJYX2" "example": "DYh540o8hbWp"
}, },
"name": "token", "name": "tokenId",
"in": "path", "in": "path",
"required": true, "required": true,
"description": "API Token" "description": "API Token ID"
} }
] ]
}, },
@ -13640,6 +13640,16 @@
"id": "tty21vb01bfr0" "id": "tty21vb01bfr0"
} }
}, },
"BaseMeta": {
"description": "Additional meta during base creation",
"properties": {
"iconColor": {
"description": "Icon color code in hexadecimal format",
"type": "string"
}
},
"type": "object"
},
"BaseReq": { "BaseReq": {
"description": "Model for Source Request", "description": "Model for Source Request",
"examples": [ "examples": [
@ -16964,10 +16974,197 @@
"description": "Currency settings for this column. Locale defaults to `en-US` and currency code defaults to `USD`", "description": "Currency settings for this column. Locale defaults to `en-US` and currency code defaults to `USD`",
"properties": { "properties": {
"currency_locale": { "currency_locale": {
"type": "string" "type": "string",
"description": "Currency locale code. Refer https://simplelocalize.io/data/locales/"
}, },
"currency_code": { "currency_code": {
"type": "string" "type": "string",
"description": "Currency code. Refer https://simplelocalize.io/data/locales/",
"enum": [
"AED",
"AFN",
"ALL",
"AMD",
"ANG",
"AOA",
"ARS",
"AUD",
"AWG",
"AZN",
"BAM",
"BBD",
"BDT",
"BGN",
"BHD",
"BIF",
"BMD",
"BND",
"BOB",
"BOV",
"BRL",
"BSD",
"BTN",
"BWP",
"BYR",
"BZD",
"CAD",
"CDF",
"CHE",
"CHF",
"CHW",
"CLF",
"CLP",
"CNY",
"COP",
"COU",
"CRC",
"CUP",
"CVE",
"CYP",
"CZK",
"DJF",
"DKK",
"DOP",
"DZD",
"EEK",
"EGP",
"ERN",
"ETB",
"EUR",
"FJD",
"FKP",
"GBP",
"GEL",
"GHC",
"GIP",
"GMD",
"GNF",
"GTQ",
"GYD",
"HKD",
"HNL",
"HRK",
"HTG",
"HUF",
"IDR",
"ILS",
"INR",
"IQD",
"IRR",
"ISK",
"JMD",
"JOD",
"JPY",
"KES",
"KGS",
"KHR",
"KMF",
"KPW",
"KRW",
"KWD",
"KYD",
"KZT",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
"LTL",
"LVL",
"LYD",
"MAD",
"MDL",
"MGA",
"MKD",
"MMK",
"MNT",
"MOP",
"MRO",
"MTL",
"MUR",
"MVR",
"MWK",
"MXN",
"MXV",
"MYR",
"MZN",
"NAD",
"NGN",
"NIO",
"NOK",
"NPR",
"NZD",
"OMR",
"PAB",
"PEN",
"PGK",
"PHP",
"PKR",
"PLN",
"PYG",
"QAR",
"ROL",
"RON",
"RSD",
"RUB",
"RWF",
"SAR",
"SBD",
"SCR",
"SDD",
"SEK",
"SGD",
"SHP",
"SIT",
"SKK",
"SLL",
"SOS",
"SRD",
"STD",
"SYP",
"SZL",
"THB",
"TJS",
"TMM",
"TND",
"TOP",
"TRY",
"TTD",
"TWD",
"TZS",
"UAH",
"UGX",
"USD",
"USN",
"USS",
"UYU",
"UZS",
"VEB",
"VND",
"VUV",
"WST",
"XAF",
"XAG",
"XAU",
"XBA",
"XBB",
"XBC",
"XBD",
"XCD",
"XDR",
"XFO",
"XFU",
"XOF",
"XPD",
"XPF",
"XPT",
"XTS",
"XXX",
"YER",
"ZAR",
"ZMK",
"ZWD"
]
} }
} }
}, },
@ -19129,7 +19326,6 @@
"type": "mysql" "type": "mysql"
} }
], ],
"color": "#24716E",
"description": "This is my base description", "description": "This is my base description",
"title": "My Base" "title": "My Base"
} }
@ -19147,14 +19343,8 @@
"example": "This is my base description", "example": "This is my base description",
"type": "string" "type": "string"
}, },
"color": {
"description": "Primary Theme Color",
"example": "#24716E",
"maxLength": 50,
"type": "string"
},
"meta": { "meta": {
"$ref": "#/components/schemas/Meta", "$ref": "#/components/schemas/BaseMeta",
"description": "Base Meta" "description": "Base Meta"
} }
}, },
@ -19174,7 +19364,6 @@
}, },
"examples": [ "examples": [
{ {
"color": "#24716E",
"meta": null, "meta": null,
"title": "My Base", "title": "My Base",
"order": 1 "order": 1
@ -19190,12 +19379,6 @@
"minLength": 1, "minLength": 1,
"type": "string" "type": "string"
}, },
"color": {
"description": "Primary Theme Color",
"example": "#24716E",
"maxLength": 50,
"type": "string"
},
"order": { "order": {
"type": "number", "type": "number",
"description": "The order of the list of projects.", "description": "The order of the list of projects.",
@ -19203,7 +19386,7 @@
"minimum": 0 "minimum": 0
}, },
"meta": { "meta": {
"$ref": "#/components/schemas/Meta", "$ref": "#/components/schemas/BaseMeta",
"description": "Base Meta", "description": "Base Meta",
"x-stoplight": { "x-stoplight": {
"id": "m05w9sbwqgul3" "id": "m05w9sbwqgul3"

14
packages/nocodb/src/schema/swagger.json

@ -819,16 +819,16 @@
"description": "Creat an organisation API token. Access with API tokens will be blocked." "description": "Creat an organisation API token. Access with API tokens will be blocked."
} }
}, },
"/api/v1/tokens/{token}": { "/api/v1/tokens/{tokenId}": {
"parameters": [ "parameters": [
{ {
"schema": { "schema": {
"type": "string" "type": "string"
}, },
"name": "token", "name": "tokenId",
"in": "path", "in": "path",
"required": true, "required": true,
"description": "API Token" "description": "API Token ID"
} }
], ],
"delete": { "delete": {
@ -16429,7 +16429,7 @@
} }
] ]
}, },
"/api/v1/db/meta/projects/{baseId}/api-tokens/{token}": { "/api/v1/db/meta/projects/{baseId}/api-tokens/{tokenId}": {
"delete": { "delete": {
"summary": "Delete API Token", "summary": "Delete API Token",
"operationId": "api-token-delete", "operationId": "api-token-delete",
@ -16479,12 +16479,12 @@
{ {
"schema": { "schema": {
"type": "string", "type": "string",
"example": "DYh540o8hbWpUGdarekECKLdN5OhlgCUWutVJYX2" "example": "DYh540o8hbWpU"
}, },
"name": "token", "name": "tokenId",
"in": "path", "in": "path",
"required": true, "required": true,
"description": "API Token" "description": "API Token ID"
} }
] ]
}, },

8
packages/nocodb/src/services/api-tokens.service.ts

@ -37,8 +37,8 @@ export class ApiTokensService {
}); });
} }
async apiTokenDelete(param: { token; user: User; req: NcRequest }) { async apiTokenDelete(param: { tokenId: string; user: User; req: NcRequest }) {
const apiToken = await ApiToken.getByToken(context, param.token); const apiToken = await ApiToken.get(param.tokenId);
if ( if (
!extractRolesObj(param.user.roles)[OrgUserRoles.SUPER_ADMIN] && !extractRolesObj(param.user.roles)[OrgUserRoles.SUPER_ADMIN] &&
apiToken.fk_user_id !== param.user.id apiToken.fk_user_id !== param.user.id
@ -48,11 +48,11 @@ export class ApiTokensService {
this.appHooksService.emit(AppEvents.API_TOKEN_DELETE, { this.appHooksService.emit(AppEvents.API_TOKEN_DELETE, {
userId: param.user?.id, userId: param.user?.id,
token: param.token, tokenId: param.tokenId,
req: param.req, req: param.req,
}); });
// todo: verify token belongs to the user // todo: verify token belongs to the user
return await ApiToken.delete(context, param.token); return await ApiToken.delete(param.tokenId);
} }
} }

2
packages/nocodb/src/services/app-hooks/interfaces.ts

@ -176,7 +176,7 @@ export interface ApiTokenCreateEvent extends NcBaseEvent {
export interface ApiTokenDeleteEvent extends NcBaseEvent { export interface ApiTokenDeleteEvent extends NcBaseEvent {
userId: string; userId: string;
token: string; tokenId: string;
} }
export interface PluginTestEvent extends NcBaseEvent { export interface PluginTestEvent extends NcBaseEvent {

8
packages/nocodb/src/services/org-tokens.service.ts

@ -61,19 +61,19 @@ export class OrgTokensService {
return apiToken; return apiToken;
} }
async apiTokenDelete(param: { user: User; token: string; req: NcRequest }) { async apiTokenDelete(param: { user: User; tokenId: string; req: NcRequest }) {
const fk_user_id = param.user.id; const fk_user_id = param.user.id;
const apiToken = await ApiToken.getByToken(param.token); const apiToken = await ApiToken.get(param.tokenId);
if ( if (
!extractRolesObj(param.user.roles)[OrgUserRoles.SUPER_ADMIN] && !extractRolesObj(param.user.roles)[OrgUserRoles.SUPER_ADMIN] &&
apiToken.fk_user_id !== fk_user_id apiToken.fk_user_id !== fk_user_id
) { ) {
NcError.notFound('Token not found'); NcError.notFound('Token not found');
} }
const res = await ApiToken.delete(param.token); const res = await ApiToken.delete(param.tokenId);
this.appHooksService.emit(AppEvents.ORG_API_TOKEN_DELETE, { this.appHooksService.emit(AppEvents.ORG_API_TOKEN_DELETE, {
token: param.token, tokenId: param.tokenId,
userId: param.user?.id, userId: param.user?.id,
req: param['req'], req: param['req'],
}); });

Loading…
Cancel
Save