diff --git a/.gitignore b/.gitignore index 2cb58a7..33be7cd 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,9 @@ coverage/ # Temporary files *.tmp *.temp +docs/ + +# Cursor +memory-bank/ +.cursor/ + diff --git a/st-app-cms/.env.example b/st-app-cms/.env.example index 78c956e..78c8193 100644 --- a/st-app-cms/.env.example +++ b/st-app-cms/.env.example @@ -6,3 +6,4 @@ ADMIN_JWT_SECRET=tobemodified TRANSFER_TOKEN_SALT=tobemodified JWT_SECRET=tobemodified ENCRYPTION_KEY=tobemodified +NEXT_SERVER_API_TOKEN=ebab379d647f6afd984a390254830a120f5592a6052337abac544b2239a774e17a24144f04e09b8986e39bf34523b1bf4cc639003de6f551f07a088abfaf617dd62195f0cc95e04909ea714d62848b93aeb94daa555613e2e13084a11e71c21453d7cadecdb1a7a7fd50400762fc2c479277d2bfcfde36dbaac6fb18f38342bf diff --git a/st-app-cms/package-lock.json b/st-app-cms/package-lock.json index 4c5f139..f97d5dc 100644 --- a/st-app-cms/package-lock.json +++ b/st-app-cms/package-lock.json @@ -13,6 +13,7 @@ "@strapi/strapi": "5.17.0", "better-sqlite3": "11.3.0", "fs-extra": "^10.0.0", + "koa-bodyparser": "^4.4.1", "mime-types": "^2.1.27", "react": "^18.0.0", "react-dom": "^18.0.0", @@ -20,6 +21,8 @@ "styled-components": "^6.0.0" }, "devDependencies": { + "@types/koa": "^3.0.0", + "@types/koa-bodyparser": "^4.3.12", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", @@ -5281,21 +5284,31 @@ } }, "node_modules/@types/koa": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.15.0.tgz", - "integrity": "sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-3.0.0.tgz", + "integrity": "sha512-MOcVYdVYmkSutVHZZPh8j3+dAjLyR5Tl59CN0eKgpkE1h/LBSmPAsQQuWs+bKu7WtGNn+hKfJH9Gzml+PulmDg==", "license": "MIT", "dependencies": { "@types/accepts": "*", "@types/content-disposition": "*", "@types/cookies": "*", "@types/http-assert": "*", - "@types/http-errors": "*", + "@types/http-errors": "^2", "@types/keygrip": "*", "@types/koa-compose": "*", "@types/node": "*" } }, + "node_modules/@types/koa-bodyparser": { + "version": "4.3.12", + "resolved": "https://registry.npmjs.org/@types/koa-bodyparser/-/koa-bodyparser-4.3.12.tgz", + "integrity": "sha512-hKMmRMVP889gPIdLZmmtou/BijaU1tHPyMNmcK7FAHAdATnRcGQQy78EqTTxLH1D4FTsrxIzklAQCso9oGoebQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/koa": "*" + } + }, "node_modules/@types/koa-compose": { "version": "3.2.8", "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", @@ -7248,6 +7261,12 @@ "node": ">= 0.8" } }, + "node_modules/copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==", + "license": "MIT" + }, "node_modules/copyfiles": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", @@ -10893,6 +10912,36 @@ "zod": "^3.19.1" } }, + "node_modules/koa-body/node_modules/@types/koa": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.15.0.tgz", + "integrity": "sha512-7QFsywoE5URbuVnG3loe03QXuGajrnotr3gQkXcEBShORai23MePfFYdhz90FEtBBpkyIYQbVD+evKtloCgX3g==", + "license": "MIT", + "dependencies": { + "@types/accepts": "*", + "@types/content-disposition": "*", + "@types/cookies": "*", + "@types/http-assert": "*", + "@types/http-errors": "*", + "@types/keygrip": "*", + "@types/koa-compose": "*", + "@types/node": "*" + } + }, + "node_modules/koa-bodyparser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/koa-bodyparser/-/koa-bodyparser-4.4.1.tgz", + "integrity": "sha512-kBH3IYPMb+iAXnrxIhXnW+gXV8OTzCu8VPDqvcDHW9SQrbkHmqPQtiZwrltNmSq6/lpipHnT7k7PsjlVD7kK0w==", + "license": "MIT", + "dependencies": { + "co-body": "^6.0.0", + "copy-to": "^2.0.1", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/koa-compose": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", @@ -16716,10 +16765,9 @@ } }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/st-app-cms/package.json b/st-app-cms/package.json index 7da92cd..d7f3518 100644 --- a/st-app-cms/package.json +++ b/st-app-cms/package.json @@ -21,6 +21,7 @@ "@strapi/strapi": "5.17.0", "better-sqlite3": "11.3.0", "fs-extra": "^10.0.0", + "koa-bodyparser": "^4.4.1", "mime-types": "^2.1.27", "react": "^18.0.0", "react-dom": "^18.0.0", @@ -28,6 +29,8 @@ "styled-components": "^6.0.0" }, "devDependencies": { + "@types/koa": "^3.0.0", + "@types/koa-bodyparser": "^4.3.12", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", diff --git a/st-app-cms/src/api/course/content-types/course/schema.json b/st-app-cms/src/api/course/content-types/course/schema.json new file mode 100644 index 0000000..dad0cec --- /dev/null +++ b/st-app-cms/src/api/course/content-types/course/schema.json @@ -0,0 +1,22 @@ +{ + "kind": "collectionType", + "collectionName": "courses", + "info": { + "singularName": "course", + "pluralName": "courses", + "displayName": "Course" + }, + "options": { + "draftAndPublish": true + }, + "pluginOptions": {}, + "attributes": { + "name": { + "type": "string", + "required": true + }, + "description": { + "type": "richtext" + } + } +} diff --git a/st-app-cms/src/api/course/controllers/course.ts b/st-app-cms/src/api/course/controllers/course.ts new file mode 100644 index 0000000..ac1b79d --- /dev/null +++ b/st-app-cms/src/api/course/controllers/course.ts @@ -0,0 +1,7 @@ +/** + * course controller + */ + +import { factories } from '@strapi/strapi' + +export default factories.createCoreController('api::course.course'); diff --git a/st-app-cms/src/api/course/routes/course.ts b/st-app-cms/src/api/course/routes/course.ts new file mode 100644 index 0000000..f628237 --- /dev/null +++ b/st-app-cms/src/api/course/routes/course.ts @@ -0,0 +1,7 @@ +/** + * course router + */ + +import { factories } from '@strapi/strapi'; + +export default factories.createCoreRouter('api::course.course'); diff --git a/st-app-cms/src/api/course/services/course.ts b/st-app-cms/src/api/course/services/course.ts new file mode 100644 index 0000000..f3b020d --- /dev/null +++ b/st-app-cms/src/api/course/services/course.ts @@ -0,0 +1,7 @@ +/** + * course service + */ + +import { factories } from '@strapi/strapi'; + +export default factories.createCoreService('api::course.course'); diff --git a/st-app-cms/src/api/github-login/controllers/github-login.ts b/st-app-cms/src/api/github-login/controllers/github-login.ts new file mode 100644 index 0000000..e474326 --- /dev/null +++ b/st-app-cms/src/api/github-login/controllers/github-login.ts @@ -0,0 +1,19 @@ +import LoginContext from "../interfaces/login-context"; +import BaseUser, { baseUserFields } from "../interfaces/user"; +import loginService from '../services/github-login'; + +export default { + async create(ctx: LoginContext) { + const { githubId, email } = ctx.request.body; + + if (!githubId || !email) { + return ctx.badRequest('Missing githubUsername or email'); + } + try { + const user: BaseUser & {created: boolean} = await loginService.loginUser({ githubId, email }); + return ctx.send(user, user.created ? 201 : 200); + } catch (error) { + return ctx.internalServerError('Internal error'); + } + }, +}; diff --git a/st-app-cms/src/api/github-login/interfaces/login-context.ts b/st-app-cms/src/api/github-login/interfaces/login-context.ts new file mode 100644 index 0000000..c81ce14 --- /dev/null +++ b/st-app-cms/src/api/github-login/interfaces/login-context.ts @@ -0,0 +1,10 @@ +import { Context } from 'koa'; +import LoginDto from './login-dto'; + +export default interface LoginContext extends Context { + request: Context['request'] & { + body: LoginDto; + }; +} + + diff --git a/st-app-cms/src/api/github-login/interfaces/login-dto.ts b/st-app-cms/src/api/github-login/interfaces/login-dto.ts new file mode 100644 index 0000000..acd6afc --- /dev/null +++ b/st-app-cms/src/api/github-login/interfaces/login-dto.ts @@ -0,0 +1,4 @@ +export default interface LoginDto { + githubId: string | null; + email: string | null; +} diff --git a/st-app-cms/src/api/github-login/interfaces/user.ts b/st-app-cms/src/api/github-login/interfaces/user.ts new file mode 100644 index 0000000..671a0b5 --- /dev/null +++ b/st-app-cms/src/api/github-login/interfaces/user.ts @@ -0,0 +1,7 @@ +export default interface BaseUser { + id: number; + username: string; + email: string; +} + +export const baseUserFields: (keyof BaseUser)[] = ['id', 'username', 'email']; diff --git a/st-app-cms/src/api/github-login/routes/github-login.ts b/st-app-cms/src/api/github-login/routes/github-login.ts new file mode 100644 index 0000000..c305bd4 --- /dev/null +++ b/st-app-cms/src/api/github-login/routes/github-login.ts @@ -0,0 +1,20 @@ +import { Core } from '@strapi/types'; + +type Route = Core.RouteInput +type Routes = { + routes: Route[] +} + +export default { + routes: [ + { + method: 'POST', + path: '/github-login', + handler: 'github-login.create', + config: { + policies: ['global::next-server-api-token'], + auth: false, + }, + }, + ], +} satisfies Routes diff --git a/st-app-cms/src/api/github-login/services/github-login.ts b/st-app-cms/src/api/github-login/services/github-login.ts new file mode 100644 index 0000000..c45b95f --- /dev/null +++ b/st-app-cms/src/api/github-login/services/github-login.ts @@ -0,0 +1,30 @@ +import LoginDto from "../interfaces/login-dto"; +import BaseUser, { baseUserFields } from "../interfaces/user"; + +const loginUser = async ({ githubId, email }: LoginDto) => { + const existingUser = await strapi.db.query('plugin::users-permissions.user').findOne({ + select: baseUserFields, + where: { username: githubId }, + }); + + if (existingUser) { + return { + ...existingUser satisfies BaseUser, + created: false, + }; + } + + const newUser = await strapi.db.query('plugin::users-permissions.user').create({ + select: baseUserFields, + data: { username: githubId, email, confirmed: true }, + }); + + return { + ...newUser satisfies BaseUser, + created: true, + }; +}; + +export default { + loginUser, +}; diff --git a/st-app-cms/src/extensions/users-permissions/content-types/user/schema.json b/st-app-cms/src/extensions/users-permissions/content-types/user/schema.json new file mode 100644 index 0000000..0fa2a8b --- /dev/null +++ b/st-app-cms/src/extensions/users-permissions/content-types/user/schema.json @@ -0,0 +1,70 @@ +{ + "kind": "collectionType", + "collectionName": "up_users", + "info": { + "name": "user", + "description": "", + "singularName": "user", + "pluralName": "users", + "displayName": "User" + }, + "options": { + "draftAndPublish": false + }, + "pluginOptions": {}, + "attributes": { + "username": { + "type": "string", + "minLength": 3, + "unique": true, + "configurable": false, + "required": true + }, + "email": { + "type": "email", + "minLength": 6, + "configurable": false, + "required": true + }, + "provider": { + "type": "string", + "configurable": false + }, + "password": { + "type": "password", + "minLength": 6, + "configurable": false, + "private": true, + "searchable": false + }, + "resetPasswordToken": { + "type": "string", + "configurable": false, + "private": true, + "searchable": false + }, + "confirmationToken": { + "type": "string", + "configurable": false, + "private": true, + "searchable": false + }, + "confirmed": { + "type": "boolean", + "default": false, + "configurable": false + }, + "blocked": { + "type": "boolean", + "default": false, + "configurable": false + }, + "role": { + "type": "relation", + "relation": "manyToOne", + "target": "plugin::users-permissions.role", + "inversedBy": "users", + "configurable": false + } + } +} diff --git a/st-app-cms/src/index.ts b/st-app-cms/src/index.ts index 58be268..ede9603 100644 --- a/st-app-cms/src/index.ts +++ b/st-app-cms/src/index.ts @@ -1,4 +1,4 @@ -// import type { Core } from '@strapi/strapi'; +import type { Core } from '@strapi/strapi'; export default { /** @@ -7,7 +7,10 @@ export default { * * This gives you an opportunity to extend code. */ - register(/* { strapi }: { strapi: Core.Strapi } */) {}, + register({ strapi }: { strapi: Core.Strapi }) { + strapi.get('policies').set('next-server-api-token', require('./policies/next-server-api-token').default); + }, + /** * An asynchronous bootstrap function that runs before diff --git a/st-app-cms/src/policies/next-server-api-token.ts b/st-app-cms/src/policies/next-server-api-token.ts new file mode 100644 index 0000000..8f7ac86 --- /dev/null +++ b/st-app-cms/src/policies/next-server-api-token.ts @@ -0,0 +1,30 @@ +import { Core } from '@strapi/strapi'; +import { errors } from '@strapi/utils'; + +type PolicyConfig = {}; + +type PolicyDependencies = { + strapi: Core.Strapi; + env: typeof process.env; +}; + +const nextServerApiToken = async ( + ctx: Core.PolicyContext, + _config: PolicyConfig, + { strapi }: PolicyDependencies +) => { + const token = ctx.request.header.authorization?.replace('Bearer ', ''); + + if (!process.env.NEXT_SERVER_API_TOKEN) { + strapi.log.error('NEXT_SERVER_API_TOKEN is not configured'); + throw new errors.PolicyError('Server misconfiguration'); + } + + if (token !== process.env.NEXT_SERVER_API_TOKEN) { + strapi.log.error('NEXT_SERVER_API_TOKEN is invalid'); + throw new errors.ForbiddenError('Invalid token'); + } + return true; +}; + +export default nextServerApiToken; diff --git a/st-app-cms/tsconfig.json b/st-app-cms/tsconfig.json index b9fa686..76fa6e3 100644 --- a/st-app-cms/tsconfig.json +++ b/st-app-cms/tsconfig.json @@ -3,7 +3,7 @@ "module": "CommonJS", "moduleResolution": "Node", "lib": ["ES2020"], - "target": "ES2019", + "target": "ES2020", "strict": false, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, @@ -13,7 +13,12 @@ "noEmitOnError": true, "noImplicitThis": true, "outDir": "dist", - "rootDir": "." + "rootDir": ".", + "baseUrl": "./", + "paths": { + "@/*": ["./src/*"] + }, + "types": ["node", "koa", "koa-bodyparser", "@strapi/types"] }, "include": [ // Include root files diff --git a/st-app-cms/types/generated/components.d.ts b/st-app-cms/types/generated/components.d.ts new file mode 100644 index 0000000..84c09e2 --- /dev/null +++ b/st-app-cms/types/generated/components.d.ts @@ -0,0 +1,75 @@ +import type { Schema, Struct } from '@strapi/strapi'; + +export interface SharedMedia extends Struct.ComponentSchema { + collectionName: 'components_shared_media'; + info: { + displayName: 'Media'; + icon: 'file-video'; + }; + attributes: { + file: Schema.Attribute.Media<'images' | 'files' | 'videos'>; + }; +} + +export interface SharedQuote extends Struct.ComponentSchema { + collectionName: 'components_shared_quotes'; + info: { + displayName: 'Quote'; + icon: 'indent'; + }; + attributes: { + body: Schema.Attribute.Text; + title: Schema.Attribute.String; + }; +} + +export interface SharedRichText extends Struct.ComponentSchema { + collectionName: 'components_shared_rich_texts'; + info: { + description: ''; + displayName: 'Rich text'; + icon: 'align-justify'; + }; + attributes: { + body: Schema.Attribute.RichText; + }; +} + +export interface SharedSeo extends Struct.ComponentSchema { + collectionName: 'components_shared_seos'; + info: { + description: ''; + displayName: 'Seo'; + icon: 'allergies'; + name: 'Seo'; + }; + attributes: { + metaDescription: Schema.Attribute.Text & Schema.Attribute.Required; + metaTitle: Schema.Attribute.String & Schema.Attribute.Required; + shareImage: Schema.Attribute.Media<'images'>; + }; +} + +export interface SharedSlider extends Struct.ComponentSchema { + collectionName: 'components_shared_sliders'; + info: { + description: ''; + displayName: 'Slider'; + icon: 'address-book'; + }; + attributes: { + files: Schema.Attribute.Media<'images', true>; + }; +} + +declare module '@strapi/strapi' { + export module Public { + export interface ComponentSchemas { + 'shared.media': SharedMedia; + 'shared.quote': SharedQuote; + 'shared.rich-text': SharedRichText; + 'shared.seo': SharedSeo; + 'shared.slider': SharedSlider; + } + } +} diff --git a/st-app-cms/types/generated/contentTypes.d.ts b/st-app-cms/types/generated/contentTypes.d.ts new file mode 100644 index 0000000..d664b8b --- /dev/null +++ b/st-app-cms/types/generated/contentTypes.d.ts @@ -0,0 +1,1096 @@ +import type { Schema, Struct } from '@strapi/strapi'; + +export interface AdminApiToken extends Struct.CollectionTypeSchema { + collectionName: 'strapi_api_tokens'; + info: { + description: ''; + displayName: 'Api Token'; + name: 'Api Token'; + pluralName: 'api-tokens'; + singularName: 'api-token'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + accessKey: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + description: Schema.Attribute.String & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }> & + Schema.Attribute.DefaultTo<''>; + encryptedKey: Schema.Attribute.Text & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + expiresAt: Schema.Attribute.DateTime; + lastUsedAt: Schema.Attribute.DateTime; + lifespan: Schema.Attribute.BigInteger; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation<'oneToMany', 'admin::api-token'> & + Schema.Attribute.Private; + name: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.Unique & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + permissions: Schema.Attribute.Relation< + 'oneToMany', + 'admin::api-token-permission' + >; + publishedAt: Schema.Attribute.DateTime; + type: Schema.Attribute.Enumeration<['read-only', 'full-access', 'custom']> & + Schema.Attribute.Required & + Schema.Attribute.DefaultTo<'read-only'>; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface AdminApiTokenPermission extends Struct.CollectionTypeSchema { + collectionName: 'strapi_api_token_permissions'; + info: { + description: ''; + displayName: 'API Token Permission'; + name: 'API Token Permission'; + pluralName: 'api-token-permissions'; + singularName: 'api-token-permission'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + action: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'admin::api-token-permission' + > & + Schema.Attribute.Private; + publishedAt: Schema.Attribute.DateTime; + token: Schema.Attribute.Relation<'manyToOne', 'admin::api-token'>; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface AdminPermission extends Struct.CollectionTypeSchema { + collectionName: 'admin_permissions'; + info: { + description: ''; + displayName: 'Permission'; + name: 'Permission'; + pluralName: 'permissions'; + singularName: 'permission'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + action: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + actionParameters: Schema.Attribute.JSON & Schema.Attribute.DefaultTo<{}>; + conditions: Schema.Attribute.JSON & Schema.Attribute.DefaultTo<[]>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation<'oneToMany', 'admin::permission'> & + Schema.Attribute.Private; + properties: Schema.Attribute.JSON & Schema.Attribute.DefaultTo<{}>; + publishedAt: Schema.Attribute.DateTime; + role: Schema.Attribute.Relation<'manyToOne', 'admin::role'>; + subject: Schema.Attribute.String & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface AdminRole extends Struct.CollectionTypeSchema { + collectionName: 'admin_roles'; + info: { + description: ''; + displayName: 'Role'; + name: 'Role'; + pluralName: 'roles'; + singularName: 'role'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + code: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.Unique & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + description: Schema.Attribute.String; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation<'oneToMany', 'admin::role'> & + Schema.Attribute.Private; + name: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.Unique & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + permissions: Schema.Attribute.Relation<'oneToMany', 'admin::permission'>; + publishedAt: Schema.Attribute.DateTime; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + users: Schema.Attribute.Relation<'manyToMany', 'admin::user'>; + }; +} + +export interface AdminTransferToken extends Struct.CollectionTypeSchema { + collectionName: 'strapi_transfer_tokens'; + info: { + description: ''; + displayName: 'Transfer Token'; + name: 'Transfer Token'; + pluralName: 'transfer-tokens'; + singularName: 'transfer-token'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + accessKey: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + description: Schema.Attribute.String & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }> & + Schema.Attribute.DefaultTo<''>; + expiresAt: Schema.Attribute.DateTime; + lastUsedAt: Schema.Attribute.DateTime; + lifespan: Schema.Attribute.BigInteger; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'admin::transfer-token' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.Unique & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + permissions: Schema.Attribute.Relation< + 'oneToMany', + 'admin::transfer-token-permission' + >; + publishedAt: Schema.Attribute.DateTime; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface AdminTransferTokenPermission + extends Struct.CollectionTypeSchema { + collectionName: 'strapi_transfer_token_permissions'; + info: { + description: ''; + displayName: 'Transfer Token Permission'; + name: 'Transfer Token Permission'; + pluralName: 'transfer-token-permissions'; + singularName: 'transfer-token-permission'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + action: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'admin::transfer-token-permission' + > & + Schema.Attribute.Private; + publishedAt: Schema.Attribute.DateTime; + token: Schema.Attribute.Relation<'manyToOne', 'admin::transfer-token'>; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface AdminUser extends Struct.CollectionTypeSchema { + collectionName: 'admin_users'; + info: { + description: ''; + displayName: 'User'; + name: 'User'; + pluralName: 'users'; + singularName: 'user'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + blocked: Schema.Attribute.Boolean & + Schema.Attribute.Private & + Schema.Attribute.DefaultTo; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + email: Schema.Attribute.Email & + Schema.Attribute.Required & + Schema.Attribute.Private & + Schema.Attribute.Unique & + Schema.Attribute.SetMinMaxLength<{ + minLength: 6; + }>; + firstname: Schema.Attribute.String & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + isActive: Schema.Attribute.Boolean & + Schema.Attribute.Private & + Schema.Attribute.DefaultTo; + lastname: Schema.Attribute.String & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation<'oneToMany', 'admin::user'> & + Schema.Attribute.Private; + password: Schema.Attribute.Password & + Schema.Attribute.Private & + Schema.Attribute.SetMinMaxLength<{ + minLength: 6; + }>; + preferedLanguage: Schema.Attribute.String; + publishedAt: Schema.Attribute.DateTime; + registrationToken: Schema.Attribute.String & Schema.Attribute.Private; + resetPasswordToken: Schema.Attribute.String & Schema.Attribute.Private; + roles: Schema.Attribute.Relation<'manyToMany', 'admin::role'> & + Schema.Attribute.Private; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + username: Schema.Attribute.String; + }; +} + +export interface ApiAboutAbout extends Struct.SingleTypeSchema { + collectionName: 'abouts'; + info: { + description: 'Write about yourself and the content you create'; + displayName: 'About'; + pluralName: 'abouts'; + singularName: 'about'; + }; + options: { + draftAndPublish: false; + }; + attributes: { + blocks: Schema.Attribute.DynamicZone< + ['shared.media', 'shared.quote', 'shared.rich-text', 'shared.slider'] + >; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation<'oneToMany', 'api::about.about'> & + Schema.Attribute.Private; + publishedAt: Schema.Attribute.DateTime; + title: Schema.Attribute.String; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface ApiArticleArticle extends Struct.CollectionTypeSchema { + collectionName: 'articles'; + info: { + description: 'Create your blog content'; + displayName: 'Article'; + pluralName: 'articles'; + singularName: 'article'; + }; + options: { + draftAndPublish: true; + }; + attributes: { + author: Schema.Attribute.Relation<'manyToOne', 'api::author.author'>; + blocks: Schema.Attribute.DynamicZone< + ['shared.media', 'shared.quote', 'shared.rich-text', 'shared.slider'] + >; + category: Schema.Attribute.Relation<'manyToOne', 'api::category.category'>; + cover: Schema.Attribute.Media<'images' | 'files' | 'videos'>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + description: Schema.Attribute.Text & + Schema.Attribute.SetMinMaxLength<{ + maxLength: 80; + }>; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'api::article.article' + > & + Schema.Attribute.Private; + publishedAt: Schema.Attribute.DateTime; + slug: Schema.Attribute.UID<'title'>; + title: Schema.Attribute.String; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface ApiAuthorAuthor extends Struct.CollectionTypeSchema { + collectionName: 'authors'; + info: { + description: 'Create authors for your content'; + displayName: 'Author'; + pluralName: 'authors'; + singularName: 'author'; + }; + options: { + draftAndPublish: false; + }; + attributes: { + articles: Schema.Attribute.Relation<'oneToMany', 'api::article.article'>; + avatar: Schema.Attribute.Media<'images' | 'files' | 'videos'>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + email: Schema.Attribute.String; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'api::author.author' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String; + publishedAt: Schema.Attribute.DateTime; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface ApiCategoryCategory extends Struct.CollectionTypeSchema { + collectionName: 'categories'; + info: { + description: 'Organize your content into categories'; + displayName: 'Category'; + pluralName: 'categories'; + singularName: 'category'; + }; + options: { + draftAndPublish: false; + }; + attributes: { + articles: Schema.Attribute.Relation<'oneToMany', 'api::article.article'>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + description: Schema.Attribute.Text; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'api::category.category' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String; + publishedAt: Schema.Attribute.DateTime; + slug: Schema.Attribute.UID; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface ApiCourseCourse extends Struct.CollectionTypeSchema { + collectionName: 'courses'; + info: { + displayName: 'Course'; + pluralName: 'courses'; + singularName: 'course'; + }; + options: { + draftAndPublish: true; + }; + attributes: { + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + description: Schema.Attribute.RichText; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'api::course.course' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String & Schema.Attribute.Required; + publishedAt: Schema.Attribute.DateTime; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface ApiGlobalGlobal extends Struct.SingleTypeSchema { + collectionName: 'globals'; + info: { + description: 'Define global settings'; + displayName: 'Global'; + pluralName: 'globals'; + singularName: 'global'; + }; + options: { + draftAndPublish: false; + }; + attributes: { + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + defaultSeo: Schema.Attribute.Component<'shared.seo', false>; + favicon: Schema.Attribute.Media<'images' | 'files' | 'videos'>; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'api::global.global' + > & + Schema.Attribute.Private; + publishedAt: Schema.Attribute.DateTime; + siteDescription: Schema.Attribute.Text & Schema.Attribute.Required; + siteName: Schema.Attribute.String & Schema.Attribute.Required; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface PluginContentReleasesRelease + extends Struct.CollectionTypeSchema { + collectionName: 'strapi_releases'; + info: { + displayName: 'Release'; + pluralName: 'releases'; + singularName: 'release'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + actions: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::content-releases.release-action' + >; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::content-releases.release' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String & Schema.Attribute.Required; + publishedAt: Schema.Attribute.DateTime; + releasedAt: Schema.Attribute.DateTime; + scheduledAt: Schema.Attribute.DateTime; + status: Schema.Attribute.Enumeration< + ['ready', 'blocked', 'failed', 'done', 'empty'] + > & + Schema.Attribute.Required; + timezone: Schema.Attribute.String; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface PluginContentReleasesReleaseAction + extends Struct.CollectionTypeSchema { + collectionName: 'strapi_release_actions'; + info: { + displayName: 'Release Action'; + pluralName: 'release-actions'; + singularName: 'release-action'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + contentType: Schema.Attribute.String & Schema.Attribute.Required; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + entryDocumentId: Schema.Attribute.String; + isEntryValid: Schema.Attribute.Boolean; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::content-releases.release-action' + > & + Schema.Attribute.Private; + publishedAt: Schema.Attribute.DateTime; + release: Schema.Attribute.Relation< + 'manyToOne', + 'plugin::content-releases.release' + >; + type: Schema.Attribute.Enumeration<['publish', 'unpublish']> & + Schema.Attribute.Required; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface PluginI18NLocale extends Struct.CollectionTypeSchema { + collectionName: 'i18n_locale'; + info: { + collectionName: 'locales'; + description: ''; + displayName: 'Locale'; + pluralName: 'locales'; + singularName: 'locale'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + code: Schema.Attribute.String & Schema.Attribute.Unique; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::i18n.locale' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String & + Schema.Attribute.SetMinMax< + { + max: 50; + min: 1; + }, + number + >; + publishedAt: Schema.Attribute.DateTime; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface PluginReviewWorkflowsWorkflow + extends Struct.CollectionTypeSchema { + collectionName: 'strapi_workflows'; + info: { + description: ''; + displayName: 'Workflow'; + name: 'Workflow'; + pluralName: 'workflows'; + singularName: 'workflow'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + contentTypes: Schema.Attribute.JSON & + Schema.Attribute.Required & + Schema.Attribute.DefaultTo<'[]'>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::review-workflows.workflow' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.Unique; + publishedAt: Schema.Attribute.DateTime; + stageRequiredToPublish: Schema.Attribute.Relation< + 'oneToOne', + 'plugin::review-workflows.workflow-stage' + >; + stages: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::review-workflows.workflow-stage' + >; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface PluginReviewWorkflowsWorkflowStage + extends Struct.CollectionTypeSchema { + collectionName: 'strapi_workflows_stages'; + info: { + description: ''; + displayName: 'Stages'; + name: 'Workflow Stage'; + pluralName: 'workflow-stages'; + singularName: 'workflow-stage'; + }; + options: { + draftAndPublish: false; + version: '1.1.0'; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + color: Schema.Attribute.String & Schema.Attribute.DefaultTo<'#4945FF'>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::review-workflows.workflow-stage' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String; + permissions: Schema.Attribute.Relation<'manyToMany', 'admin::permission'>; + publishedAt: Schema.Attribute.DateTime; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + workflow: Schema.Attribute.Relation< + 'manyToOne', + 'plugin::review-workflows.workflow' + >; + }; +} + +export interface PluginUploadFile extends Struct.CollectionTypeSchema { + collectionName: 'files'; + info: { + description: ''; + displayName: 'File'; + pluralName: 'files'; + singularName: 'file'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + alternativeText: Schema.Attribute.String; + caption: Schema.Attribute.String; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + ext: Schema.Attribute.String; + folder: Schema.Attribute.Relation<'manyToOne', 'plugin::upload.folder'> & + Schema.Attribute.Private; + folderPath: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.Private & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + formats: Schema.Attribute.JSON; + hash: Schema.Attribute.String & Schema.Attribute.Required; + height: Schema.Attribute.Integer; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::upload.file' + > & + Schema.Attribute.Private; + mime: Schema.Attribute.String & Schema.Attribute.Required; + name: Schema.Attribute.String & Schema.Attribute.Required; + previewUrl: Schema.Attribute.String; + provider: Schema.Attribute.String & Schema.Attribute.Required; + provider_metadata: Schema.Attribute.JSON; + publishedAt: Schema.Attribute.DateTime; + related: Schema.Attribute.Relation<'morphToMany'>; + size: Schema.Attribute.Decimal & Schema.Attribute.Required; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + url: Schema.Attribute.String & Schema.Attribute.Required; + width: Schema.Attribute.Integer; + }; +} + +export interface PluginUploadFolder extends Struct.CollectionTypeSchema { + collectionName: 'upload_folders'; + info: { + displayName: 'Folder'; + pluralName: 'folders'; + singularName: 'folder'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + children: Schema.Attribute.Relation<'oneToMany', 'plugin::upload.folder'>; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + files: Schema.Attribute.Relation<'oneToMany', 'plugin::upload.file'>; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::upload.folder' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + parent: Schema.Attribute.Relation<'manyToOne', 'plugin::upload.folder'>; + path: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 1; + }>; + pathId: Schema.Attribute.Integer & + Schema.Attribute.Required & + Schema.Attribute.Unique; + publishedAt: Schema.Attribute.DateTime; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface PluginUsersPermissionsPermission + extends Struct.CollectionTypeSchema { + collectionName: 'up_permissions'; + info: { + description: ''; + displayName: 'Permission'; + name: 'permission'; + pluralName: 'permissions'; + singularName: 'permission'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + action: Schema.Attribute.String & Schema.Attribute.Required; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::users-permissions.permission' + > & + Schema.Attribute.Private; + publishedAt: Schema.Attribute.DateTime; + role: Schema.Attribute.Relation< + 'manyToOne', + 'plugin::users-permissions.role' + >; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + }; +} + +export interface PluginUsersPermissionsRole + extends Struct.CollectionTypeSchema { + collectionName: 'up_roles'; + info: { + description: ''; + displayName: 'Role'; + name: 'role'; + pluralName: 'roles'; + singularName: 'role'; + }; + options: { + draftAndPublish: false; + }; + pluginOptions: { + 'content-manager': { + visible: false; + }; + 'content-type-builder': { + visible: false; + }; + }; + attributes: { + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + description: Schema.Attribute.String; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::users-permissions.role' + > & + Schema.Attribute.Private; + name: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 3; + }>; + permissions: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::users-permissions.permission' + >; + publishedAt: Schema.Attribute.DateTime; + type: Schema.Attribute.String & Schema.Attribute.Unique; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + users: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::users-permissions.user' + >; + }; +} + +export interface PluginUsersPermissionsUser + extends Struct.CollectionTypeSchema { + collectionName: 'up_users'; + info: { + description: ''; + displayName: 'User'; + name: 'user'; + pluralName: 'users'; + singularName: 'user'; + }; + options: { + draftAndPublish: false; + }; + attributes: { + blocked: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo; + confirmationToken: Schema.Attribute.String & Schema.Attribute.Private; + confirmed: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo; + createdAt: Schema.Attribute.DateTime; + createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + email: Schema.Attribute.Email & + Schema.Attribute.Required & + Schema.Attribute.SetMinMaxLength<{ + minLength: 6; + }>; + locale: Schema.Attribute.String & Schema.Attribute.Private; + localizations: Schema.Attribute.Relation< + 'oneToMany', + 'plugin::users-permissions.user' + > & + Schema.Attribute.Private; + password: Schema.Attribute.Password & + Schema.Attribute.Private & + Schema.Attribute.SetMinMaxLength<{ + minLength: 6; + }>; + provider: Schema.Attribute.String; + publishedAt: Schema.Attribute.DateTime; + resetPasswordToken: Schema.Attribute.String & Schema.Attribute.Private; + role: Schema.Attribute.Relation< + 'manyToOne', + 'plugin::users-permissions.role' + >; + updatedAt: Schema.Attribute.DateTime; + updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & + Schema.Attribute.Private; + username: Schema.Attribute.String & + Schema.Attribute.Required & + Schema.Attribute.Unique & + Schema.Attribute.SetMinMaxLength<{ + minLength: 3; + }>; + }; +} + +declare module '@strapi/strapi' { + export module Public { + export interface ContentTypeSchemas { + 'admin::api-token': AdminApiToken; + 'admin::api-token-permission': AdminApiTokenPermission; + 'admin::permission': AdminPermission; + 'admin::role': AdminRole; + 'admin::transfer-token': AdminTransferToken; + 'admin::transfer-token-permission': AdminTransferTokenPermission; + 'admin::user': AdminUser; + 'api::about.about': ApiAboutAbout; + 'api::article.article': ApiArticleArticle; + 'api::author.author': ApiAuthorAuthor; + 'api::category.category': ApiCategoryCategory; + 'api::course.course': ApiCourseCourse; + 'api::global.global': ApiGlobalGlobal; + 'plugin::content-releases.release': PluginContentReleasesRelease; + 'plugin::content-releases.release-action': PluginContentReleasesReleaseAction; + 'plugin::i18n.locale': PluginI18NLocale; + 'plugin::review-workflows.workflow': PluginReviewWorkflowsWorkflow; + 'plugin::review-workflows.workflow-stage': PluginReviewWorkflowsWorkflowStage; + 'plugin::upload.file': PluginUploadFile; + 'plugin::upload.folder': PluginUploadFolder; + 'plugin::users-permissions.permission': PluginUsersPermissionsPermission; + 'plugin::users-permissions.role': PluginUsersPermissionsRole; + 'plugin::users-permissions.user': PluginUsersPermissionsUser; + } + } +}