Refactor: Remove unused Convex HTTP routes and schema definitions
- Deleted `http.ts` which contained custom HTTP routes for authentication and JWKS. - Removed `schema.ts` that defined database schemas for `github_starred`, `users`, and `sessions`. - Updated `package.json` to remove the Convex dependency and updated other dependencies. - Deleted SQL script `clear.sql` for removing constraints from tables. - Removed `update.sh` script for updating dependencies. - Deleted demo application routes and models in `app-demo` directory. - Cleaned up unused modules and imports across various files. - Removed Redis and common utility scripts that were not in use. - Deleted test scripts related to user and bucket management.
This commit is contained in:
49
convex/_generated/api.d.ts
vendored
49
convex/_generated/api.d.ts
vendored
@@ -1,49 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Generated `api` utility.
|
||||
*
|
||||
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||
*
|
||||
* To regenerate, run `npx convex dev`.
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type * as http from "../http.js";
|
||||
|
||||
import type {
|
||||
ApiFromModules,
|
||||
FilterApi,
|
||||
FunctionReference,
|
||||
} from "convex/server";
|
||||
|
||||
declare const fullApi: ApiFromModules<{
|
||||
http: typeof http;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* A utility for referencing Convex functions in your app's public API.
|
||||
*
|
||||
* Usage:
|
||||
* ```js
|
||||
* const myFunctionReference = api.myModule.myFunction;
|
||||
* ```
|
||||
*/
|
||||
export declare const api: FilterApi<
|
||||
typeof fullApi,
|
||||
FunctionReference<any, "public">
|
||||
>;
|
||||
|
||||
/**
|
||||
* A utility for referencing Convex functions in your app's internal API.
|
||||
*
|
||||
* Usage:
|
||||
* ```js
|
||||
* const myFunctionReference = internal.myModule.myFunction;
|
||||
* ```
|
||||
*/
|
||||
export declare const internal: FilterApi<
|
||||
typeof fullApi,
|
||||
FunctionReference<any, "internal">
|
||||
>;
|
||||
|
||||
export declare const components: {};
|
||||
@@ -1,23 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Generated `api` utility.
|
||||
*
|
||||
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||
*
|
||||
* To regenerate, run `npx convex dev`.
|
||||
* @module
|
||||
*/
|
||||
|
||||
import { anyApi, componentsGeneric } from "convex/server";
|
||||
|
||||
/**
|
||||
* A utility for referencing Convex functions in your app's API.
|
||||
*
|
||||
* Usage:
|
||||
* ```js
|
||||
* const myFunctionReference = api.myModule.myFunction;
|
||||
* ```
|
||||
*/
|
||||
export const api = anyApi;
|
||||
export const internal = anyApi;
|
||||
export const components = componentsGeneric();
|
||||
60
convex/_generated/dataModel.d.ts
vendored
60
convex/_generated/dataModel.d.ts
vendored
@@ -1,60 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Generated data model types.
|
||||
*
|
||||
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||
*
|
||||
* To regenerate, run `npx convex dev`.
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type {
|
||||
DataModelFromSchemaDefinition,
|
||||
DocumentByName,
|
||||
TableNamesInDataModel,
|
||||
SystemTableNames,
|
||||
} from "convex/server";
|
||||
import type { GenericId } from "convex/values";
|
||||
import schema from "../schema.js";
|
||||
|
||||
/**
|
||||
* The names of all of your Convex tables.
|
||||
*/
|
||||
export type TableNames = TableNamesInDataModel<DataModel>;
|
||||
|
||||
/**
|
||||
* The type of a document stored in Convex.
|
||||
*
|
||||
* @typeParam TableName - A string literal type of the table name (like "users").
|
||||
*/
|
||||
export type Doc<TableName extends TableNames> = DocumentByName<
|
||||
DataModel,
|
||||
TableName
|
||||
>;
|
||||
|
||||
/**
|
||||
* An identifier for a document in Convex.
|
||||
*
|
||||
* Convex documents are uniquely identified by their `Id`, which is accessible
|
||||
* on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).
|
||||
*
|
||||
* Documents can be loaded using `db.get(tableName, id)` in query and mutation functions.
|
||||
*
|
||||
* IDs are just strings at runtime, but this type can be used to distinguish them from other
|
||||
* strings when type checking.
|
||||
*
|
||||
* @typeParam TableName - A string literal type of the table name (like "users").
|
||||
*/
|
||||
export type Id<TableName extends TableNames | SystemTableNames> =
|
||||
GenericId<TableName>;
|
||||
|
||||
/**
|
||||
* A type describing your Convex data model.
|
||||
*
|
||||
* This type includes information about what tables you have, the type of
|
||||
* documents stored in those tables, and the indexes defined on them.
|
||||
*
|
||||
* This type is used to parameterize methods like `queryGeneric` and
|
||||
* `mutationGeneric` to make them type-safe.
|
||||
*/
|
||||
export type DataModel = DataModelFromSchemaDefinition<typeof schema>;
|
||||
143
convex/_generated/server.d.ts
vendored
143
convex/_generated/server.d.ts
vendored
@@ -1,143 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Generated utilities for implementing server-side Convex query and mutation functions.
|
||||
*
|
||||
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||
*
|
||||
* To regenerate, run `npx convex dev`.
|
||||
* @module
|
||||
*/
|
||||
|
||||
import {
|
||||
ActionBuilder,
|
||||
HttpActionBuilder,
|
||||
MutationBuilder,
|
||||
QueryBuilder,
|
||||
GenericActionCtx,
|
||||
GenericMutationCtx,
|
||||
GenericQueryCtx,
|
||||
GenericDatabaseReader,
|
||||
GenericDatabaseWriter,
|
||||
} from "convex/server";
|
||||
import type { DataModel } from "./dataModel.js";
|
||||
|
||||
/**
|
||||
* Define a query in this Convex app's public API.
|
||||
*
|
||||
* This function will be allowed to read your Convex database and will be accessible from the client.
|
||||
*
|
||||
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export declare const query: QueryBuilder<DataModel, "public">;
|
||||
|
||||
/**
|
||||
* Define a query that is only accessible from other Convex functions (but not from the client).
|
||||
*
|
||||
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
|
||||
*
|
||||
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export declare const internalQuery: QueryBuilder<DataModel, "internal">;
|
||||
|
||||
/**
|
||||
* Define a mutation in this Convex app's public API.
|
||||
*
|
||||
* This function will be allowed to modify your Convex database and will be accessible from the client.
|
||||
*
|
||||
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export declare const mutation: MutationBuilder<DataModel, "public">;
|
||||
|
||||
/**
|
||||
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
||||
*
|
||||
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
|
||||
*
|
||||
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export declare const internalMutation: MutationBuilder<DataModel, "internal">;
|
||||
|
||||
/**
|
||||
* Define an action in this Convex app's public API.
|
||||
*
|
||||
* An action is a function which can execute any JavaScript code, including non-deterministic
|
||||
* code and code with side-effects, like calling third-party services.
|
||||
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
|
||||
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
|
||||
*
|
||||
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
||||
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export declare const action: ActionBuilder<DataModel, "public">;
|
||||
|
||||
/**
|
||||
* Define an action that is only accessible from other Convex functions (but not from the client).
|
||||
*
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
||||
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export declare const internalAction: ActionBuilder<DataModel, "internal">;
|
||||
|
||||
/**
|
||||
* Define an HTTP action.
|
||||
*
|
||||
* The wrapped function will be used to respond to HTTP requests received
|
||||
* by a Convex deployment if the requests matches the path and method where
|
||||
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
||||
*
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
||||
* and a Fetch API `Request` object as its second.
|
||||
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||
*/
|
||||
export declare const httpAction: HttpActionBuilder;
|
||||
|
||||
/**
|
||||
* A set of services for use within Convex query functions.
|
||||
*
|
||||
* The query context is passed as the first argument to any Convex query
|
||||
* function run on the server.
|
||||
*
|
||||
* This differs from the {@link MutationCtx} because all of the services are
|
||||
* read-only.
|
||||
*/
|
||||
export type QueryCtx = GenericQueryCtx<DataModel>;
|
||||
|
||||
/**
|
||||
* A set of services for use within Convex mutation functions.
|
||||
*
|
||||
* The mutation context is passed as the first argument to any Convex mutation
|
||||
* function run on the server.
|
||||
*/
|
||||
export type MutationCtx = GenericMutationCtx<DataModel>;
|
||||
|
||||
/**
|
||||
* A set of services for use within Convex action functions.
|
||||
*
|
||||
* The action context is passed as the first argument to any Convex action
|
||||
* function run on the server.
|
||||
*/
|
||||
export type ActionCtx = GenericActionCtx<DataModel>;
|
||||
|
||||
/**
|
||||
* An interface to read from the database within Convex query functions.
|
||||
*
|
||||
* The two entry points are {@link DatabaseReader.get}, which fetches a single
|
||||
* document by its {@link Id}, or {@link DatabaseReader.query}, which starts
|
||||
* building a query.
|
||||
*/
|
||||
export type DatabaseReader = GenericDatabaseReader<DataModel>;
|
||||
|
||||
/**
|
||||
* An interface to read from and write to the database within Convex mutation
|
||||
* functions.
|
||||
*
|
||||
* Convex guarantees that all writes within a single mutation are
|
||||
* executed atomically, so you never have to worry about partial writes leaving
|
||||
* your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)
|
||||
* for the guarantees Convex provides your functions.
|
||||
*/
|
||||
export type DatabaseWriter = GenericDatabaseWriter<DataModel>;
|
||||
@@ -1,93 +0,0 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Generated utilities for implementing server-side Convex query and mutation functions.
|
||||
*
|
||||
* THIS CODE IS AUTOMATICALLY GENERATED.
|
||||
*
|
||||
* To regenerate, run `npx convex dev`.
|
||||
* @module
|
||||
*/
|
||||
|
||||
import {
|
||||
actionGeneric,
|
||||
httpActionGeneric,
|
||||
queryGeneric,
|
||||
mutationGeneric,
|
||||
internalActionGeneric,
|
||||
internalMutationGeneric,
|
||||
internalQueryGeneric,
|
||||
} from "convex/server";
|
||||
|
||||
/**
|
||||
* Define a query in this Convex app's public API.
|
||||
*
|
||||
* This function will be allowed to read your Convex database and will be accessible from the client.
|
||||
*
|
||||
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export const query = queryGeneric;
|
||||
|
||||
/**
|
||||
* Define a query that is only accessible from other Convex functions (but not from the client).
|
||||
*
|
||||
* This function will be allowed to read from your Convex database. It will not be accessible from the client.
|
||||
*
|
||||
* @param func - The query function. It receives a {@link QueryCtx} as its first argument.
|
||||
* @returns The wrapped query. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export const internalQuery = internalQueryGeneric;
|
||||
|
||||
/**
|
||||
* Define a mutation in this Convex app's public API.
|
||||
*
|
||||
* This function will be allowed to modify your Convex database and will be accessible from the client.
|
||||
*
|
||||
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export const mutation = mutationGeneric;
|
||||
|
||||
/**
|
||||
* Define a mutation that is only accessible from other Convex functions (but not from the client).
|
||||
*
|
||||
* This function will be allowed to modify your Convex database. It will not be accessible from the client.
|
||||
*
|
||||
* @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.
|
||||
* @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export const internalMutation = internalMutationGeneric;
|
||||
|
||||
/**
|
||||
* Define an action in this Convex app's public API.
|
||||
*
|
||||
* An action is a function which can execute any JavaScript code, including non-deterministic
|
||||
* code and code with side-effects, like calling third-party services.
|
||||
* They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive.
|
||||
* They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.
|
||||
*
|
||||
* @param func - The action. It receives an {@link ActionCtx} as its first argument.
|
||||
* @returns The wrapped action. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export const action = actionGeneric;
|
||||
|
||||
/**
|
||||
* Define an action that is only accessible from other Convex functions (but not from the client).
|
||||
*
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument.
|
||||
* @returns The wrapped function. Include this as an `export` to name it and make it accessible.
|
||||
*/
|
||||
export const internalAction = internalActionGeneric;
|
||||
|
||||
/**
|
||||
* Define an HTTP action.
|
||||
*
|
||||
* The wrapped function will be used to respond to HTTP requests received
|
||||
* by a Convex deployment if the requests matches the path and method where
|
||||
* this action is routed. Be sure to route your httpAction in `convex/http.js`.
|
||||
*
|
||||
* @param func - The function. It receives an {@link ActionCtx} as its first argument
|
||||
* and a Fetch API `Request` object as its second.
|
||||
* @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
|
||||
*/
|
||||
export const httpAction = httpActionGeneric;
|
||||
@@ -1,13 +0,0 @@
|
||||
import { AuthConfig } from "convex/server";
|
||||
|
||||
export default {
|
||||
providers: [
|
||||
{
|
||||
type: "customJwt",
|
||||
applicationID: "convex-app",
|
||||
issuer: "https://convex.kevisual.cn",
|
||||
jwks: "https://api-convex.kevisual.cn/root/convex/jwks.json",
|
||||
algorithm: "RS256",
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import { defineApp } from "convex/server";
|
||||
const app = defineApp();
|
||||
|
||||
// import myComponent from "../component/convex.config.ts";
|
||||
// app.use(myComponent);
|
||||
|
||||
export default app;
|
||||
@@ -1,39 +0,0 @@
|
||||
import { httpRouter } from "convex/server";
|
||||
import { httpAction } from "./_generated/server";
|
||||
const http = httpRouter();
|
||||
|
||||
http.route({
|
||||
path: "/auth",
|
||||
method: "POST",
|
||||
handler: httpAction(async (ctx, request) => {
|
||||
// 处理请求并返回响应
|
||||
return new Response(JSON.stringify({ message: "Hello from custom endpoint!" }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}),
|
||||
})
|
||||
|
||||
// https://api-convex.kevisual.cn/root/convex/jwks.json
|
||||
http.route({
|
||||
path: '/root/convex/jwks.json',
|
||||
method: 'GET',
|
||||
handler: httpAction(async (ctx, request) => {
|
||||
// 返回 JWKS 数据
|
||||
const jwks = {
|
||||
"keys": [
|
||||
{
|
||||
"kty": "RSA",
|
||||
"n": "km4cjJJOMFkl2G5qWMuFmWwF7rmeqRYzYdR8SddKeeMW0e9yIf5pv2Mfwv0aMJUpb-_j3j9M7whx_SEGc_2jx1vxCu1AlYURhnnLTWdsR-ZRPr2LK9UstMrgpWV425R2RliqXTDTYlSxUUlD9nPue_tqbfwN2aM9MCarm67xK_ZCcKRlW9o9L2-9UMfzRA7uiy4VQtOemP0PTXp-E9RxNiMPOQXIRls9wTW_EkDT3dGy7JCZhj7_qib3T8k9m84SwU7wI2R_3IH4DcHSMAn1BRRMXZ1_wPhbP39laNtdJgbDjGCqUccGhLUaoo2WGkZ52eb7NPqamp0K1Dh2jwTIJQ",
|
||||
"e": "AQAB",
|
||||
"kid": "kid-key-1"
|
||||
}
|
||||
]
|
||||
};
|
||||
return new Response(JSON.stringify(jwks), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}),
|
||||
})
|
||||
export default http;
|
||||
@@ -1,30 +0,0 @@
|
||||
import { defineSchema, defineTable } from "convex/server";
|
||||
import { v } from "convex/values";
|
||||
|
||||
export default defineSchema({
|
||||
// Other tables here...
|
||||
|
||||
github_starred: defineTable({
|
||||
author: v.string(),
|
||||
auto: v.string(),
|
||||
description: v.string(),
|
||||
last_updated: v.string(),
|
||||
link: v.string(),
|
||||
repo_id: v.float64(),
|
||||
stars: v.float64(),
|
||||
summary: v.string(),
|
||||
title: v.string(),
|
||||
}),
|
||||
users: defineTable({
|
||||
userId: v.string(), // 外部系统的用户 ID
|
||||
name: v.string(),
|
||||
createdAt: v.string(),
|
||||
lastLoginAt: v.optional(v.string()),
|
||||
}).index("userId", ["userId"]),
|
||||
sessions: defineTable({
|
||||
userId: v.id("users"),
|
||||
createdAt: v.string(),
|
||||
expiresAt: v.optional(v.string()),
|
||||
token: v.optional(v.string()),
|
||||
}).index("token", ["token"]),
|
||||
});
|
||||
26
package.json
26
package.json
@@ -37,7 +37,6 @@
|
||||
"studio": "npx drizzle-kit studio",
|
||||
"drizzle:migrate": "npx drizzle-kit migrate",
|
||||
"drizzle:push": "npx drizzle-kit push",
|
||||
"convex": "bunx convex dev",
|
||||
"pub": "envision pack -p -u -c"
|
||||
},
|
||||
"keywords": [],
|
||||
@@ -54,26 +53,23 @@
|
||||
"@types/busboy": "^1.5.4",
|
||||
"@types/send": "^1.2.1",
|
||||
"@types/ws": "^8.18.1",
|
||||
"bullmq": "^5.67.2",
|
||||
"bullmq": "^5.67.3",
|
||||
"busboy": "^1.6.0",
|
||||
"commander": "^14.0.3",
|
||||
"drizzle-kit": "^0.31.8",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
"drizzle-zod": "^0.8.3",
|
||||
"eventemitter3": "^5.0.4",
|
||||
"ioredis": "^5.9.2",
|
||||
"minio": "^8.0.6",
|
||||
"pg": "^8.18.0",
|
||||
"pm2": "^6.0.14",
|
||||
"send": "^1.2.1",
|
||||
"sequelize": "^6.37.7",
|
||||
"ws": "npm:@kevisual/ws",
|
||||
"xml2js": "^0.6.2",
|
||||
"zod-to-json-schema": "^3.25.1"
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-sdk/client-s3": "^3.981.0",
|
||||
"@kevisual/api": "^0.0.44",
|
||||
"@aws-sdk/client-s3": "^3.984.0",
|
||||
"@kevisual/api": "^0.0.47",
|
||||
"@kevisual/code-center-module": "0.0.24",
|
||||
"@kevisual/context": "^0.0.4",
|
||||
"@kevisual/file-listener": "^0.0.2",
|
||||
@@ -88,16 +84,14 @@
|
||||
"@types/bun": "^1.3.8",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/node": "^25.2.0",
|
||||
"@types/node": "^25.2.1",
|
||||
"@types/pg": "^8.16.0",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
"archiver": "^7.0.1",
|
||||
"better-sqlite3": "^12.6.2",
|
||||
"convex": "^1.31.7",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.19",
|
||||
"dotenv": "^17.2.3",
|
||||
"dotenv": "^17.2.4",
|
||||
"es-toolkit": "^1.44.0",
|
||||
"ioredis": "^5.9.2",
|
||||
"jsonwebtoken": "^9.0.3",
|
||||
@@ -107,7 +101,7 @@
|
||||
"p-queue": "^9.1.0",
|
||||
"pg": "^8.18.0",
|
||||
"pm2": "^6.0.14",
|
||||
"semver": "^7.7.3",
|
||||
"semver": "^7.7.4",
|
||||
"sequelize": "^6.37.7",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
@@ -115,11 +109,5 @@
|
||||
"inflight": "latest",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"esbuild",
|
||||
"better-sqlite3"
|
||||
]
|
||||
},
|
||||
"packageManager": "pnpm@10.28.2"
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
-- =====================================================
|
||||
-- 删除 cf_orgs 表中所有带数字的重复唯一约束
|
||||
-- 保留 cf_orgs_username_key(不带数字的)
|
||||
-- =====================================================
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
constraint_record RECORD;
|
||||
BEGIN
|
||||
FOR constraint_record IN
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'cf_orgs'::regclass
|
||||
AND conname LIKE 'cf_orgs_username_key%'
|
||||
AND conname != 'cf_orgs_username_key'
|
||||
AND conname ~ '[0-9]' -- 包含数字的
|
||||
ORDER BY conname
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE cf_orgs DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
|
||||
RAISE NOTICE '已删除约束: %', constraint_record.conname;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- =====================================================
|
||||
-- 删除 cf_user 表中所有带数字的重复唯一约束
|
||||
-- 保留 cf_user_username_key(不带数字的)
|
||||
-- =====================================================
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
constraint_record RECORD;
|
||||
BEGIN
|
||||
FOR constraint_record IN
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'cf_user'::regclass
|
||||
AND conname LIKE 'cf_user_username_key%'
|
||||
AND conname != 'cf_user_username_key'
|
||||
AND conname ~ '[0-9]' -- 包含数字的
|
||||
ORDER BY conname
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE cf_user DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
|
||||
RAISE NOTICE '已删除约束: %', constraint_record.conname;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- =====================================================
|
||||
-- 验证删除结果
|
||||
-- =====================================================
|
||||
|
||||
-- 查看 cf_orgs 剩余的 username 约束
|
||||
SELECT 'cf_orgs 表剩余的 username 约束:' AS info;
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'cf_orgs'::regclass
|
||||
AND conname LIKE 'cf_orgs_username_key%'
|
||||
ORDER BY conname;
|
||||
|
||||
-- 查看 cf_user 剩余的 username 约束
|
||||
SELECT 'cf_user 表剩余的 username 约束:' AS info;
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'cf_user'::regclass
|
||||
AND conname LIKE 'cf_user_username_key%'
|
||||
ORDER BY conname;
|
||||
-- =====================================================
|
||||
-- 删除 kv_app_domain 表中所有带数字的重复唯一约束
|
||||
-- 保留 kv_app_domain_domain_key(不带数字的)
|
||||
-- =====================================================
|
||||
DO $$
|
||||
DECLARE
|
||||
constraint_record RECORD;
|
||||
BEGIN
|
||||
FOR constraint_record IN
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'kv_app_domain'::regclass
|
||||
AND conname LIKE 'kv_app_domain_domain_key%'
|
||||
AND conname != 'kv_app_domain_domain_key'
|
||||
AND conname ~ '[0-9]' -- 包含数字的
|
||||
ORDER BY conname
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE kv_app_domain DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
|
||||
RAISE NOTICE '已删除约束: %', constraint_record.conname;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- =====================================================
|
||||
-- 删除 prompts 表中所有带数字的重复唯一约束
|
||||
-- 保留 prompts_key_key(不带数字的)
|
||||
-- =====================================================
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
constraint_record RECORD;
|
||||
BEGIN
|
||||
FOR constraint_record IN
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'prompts'::regclass
|
||||
AND conname LIKE 'prompts_key_key%'
|
||||
AND conname != 'prompts_key_key'
|
||||
AND conname ~ '[0-9]' -- 包含数字的
|
||||
ORDER BY conname
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE prompts DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
|
||||
RAISE NOTICE '已删除约束: %', constraint_record.conname;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- =====================================================
|
||||
-- 删除 apps_trades 表中所有带数字的重复唯一约束
|
||||
-- 保留 apps_trades_out_trade_no_key(不带数字的)
|
||||
-- =====================================================
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
constraint_record RECORD;
|
||||
BEGIN
|
||||
FOR constraint_record IN
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'apps_trades'::regclass
|
||||
AND conname LIKE 'apps_trades_out_trade_no_key%'
|
||||
AND conname != 'apps_trades_out_trade_no_key'
|
||||
AND conname ~ '[0-9]' -- 包含数字的
|
||||
ORDER BY conname
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE apps_trades DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
|
||||
RAISE NOTICE '已删除约束: %', constraint_record.conname;
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- =====================================================
|
||||
-- 删除 ai_agent 表中所有带数字的重复唯一约束
|
||||
-- 保留 ai_agent_key_key(不带数字的)
|
||||
-- =====================================================
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
constraint_record RECORD;
|
||||
BEGIN
|
||||
FOR constraint_record IN
|
||||
SELECT conname
|
||||
FROM pg_constraint
|
||||
WHERE conrelid = 'ai_agent'::regclass
|
||||
AND conname LIKE 'ai_agent_key_key%'
|
||||
AND conname != 'ai_agent_key_key'
|
||||
AND conname ~ '[0-9]' -- 包含数字的
|
||||
ORDER BY conname
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE ai_agent DROP CONSTRAINT IF EXISTS %I', constraint_record.conname);
|
||||
RAISE NOTICE '已删除约束: %', constraint_record.conname;
|
||||
END LOOP;
|
||||
END $$;
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
pnpm i -g npm-check-updates
|
||||
ncu -u
|
||||
pnpm install
|
||||
|
||||
# /home/ubuntu/.nvm/versions/node/v22.14.0/bin/ncu -u
|
||||
@@ -1,119 +0,0 @@
|
||||
import { Op } from 'sequelize';
|
||||
import { AppDemoModel } from './models/index.ts';
|
||||
import { app } from '@/app.ts';
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'app-demo',
|
||||
key: 'list',
|
||||
middleware: ['auth'],
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
const { page = 1, pageSize = 20, search, sort = 'DESC' } = ctx.query;
|
||||
const searchWhere = search
|
||||
? {
|
||||
[Op.or]: [{ title: { [Op.like]: `%${search}%` } }, { summary: { [Op.like]: `%${search}%` } }],
|
||||
}
|
||||
: {};
|
||||
|
||||
const { rows: appDemo, count } = await AppDemoModel.findAndCountAll({
|
||||
where: {
|
||||
uid: tokenUser.id,
|
||||
...searchWhere,
|
||||
},
|
||||
offset: (page - 1) * pageSize,
|
||||
limit: pageSize,
|
||||
order: [['updatedAt', sort]],
|
||||
});
|
||||
|
||||
ctx.body = {
|
||||
list: appDemo,
|
||||
pagination: {
|
||||
page,
|
||||
current: page,
|
||||
pageSize,
|
||||
total: count,
|
||||
},
|
||||
};
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'app-demo',
|
||||
key: 'update',
|
||||
middleware: ['auth'],
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
const { id, data, updatedAt: _clear, createdAt: _clear2, ...rest } = ctx.query.data;
|
||||
let appDemo: AppDemoModel;
|
||||
let isNew = false;
|
||||
if (id) {
|
||||
const appDemo = await AppDemoModel.findByPk(id);
|
||||
if (appDemo.uid !== tokenUser.uid) {
|
||||
ctx.throw(403, 'No permission');
|
||||
}
|
||||
} else {
|
||||
appDemo = await AppDemoModel.create({
|
||||
data: data,
|
||||
...rest,
|
||||
uid: tokenUser.uid,
|
||||
});
|
||||
isNew = true;
|
||||
}
|
||||
if (!appDemo) {
|
||||
ctx.throw(404, 'AppDemo not found');
|
||||
}
|
||||
if (!isNew) {
|
||||
appDemo = await appDemo.update({
|
||||
data: { ...appDemo.data, ...data },
|
||||
...rest,
|
||||
});
|
||||
}
|
||||
|
||||
ctx.body = appDemo;
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'app-demo',
|
||||
key: 'delete',
|
||||
middleware: ['auth'],
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
const { id, force = false } = ctx.query.data || {};
|
||||
if (!id) {
|
||||
ctx.throw(400, 'id is required');
|
||||
}
|
||||
const appDemo = await AppDemoModel.findByPk(id);
|
||||
if (appDemo.uid !== tokenUser.id) {
|
||||
ctx.throw(403, 'No permission');
|
||||
}
|
||||
await appDemo.destroy({ force });
|
||||
ctx.body = appDemo;
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'app-demo',
|
||||
key: 'get',
|
||||
middleware: ['auth'],
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const tokenUser = ctx.state.tokenUser;
|
||||
const { id } = ctx.query.data || {};
|
||||
if (!id) {
|
||||
ctx.throw(400, 'id is required');
|
||||
}
|
||||
const appDemo = await AppDemoModel.findByPk(id);
|
||||
if (appDemo.uid !== tokenUser.id) {
|
||||
ctx.throw(403, 'No permission');
|
||||
}
|
||||
ctx.body = appDemo;
|
||||
})
|
||||
.addTo(app);
|
||||
@@ -1,71 +0,0 @@
|
||||
import { sequelize } from '@/modules/sequelize.ts';
|
||||
import { DataTypes, Model } from 'sequelize';
|
||||
|
||||
export interface AppDemoData {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type AppDemo = Partial<InstanceType<typeof AppDemoModel>>;
|
||||
|
||||
export class AppDemoModel extends Model {
|
||||
declare id: string;
|
||||
declare title: string;
|
||||
declare description: string;
|
||||
declare summary: string;
|
||||
|
||||
declare data: AppDemoData;
|
||||
declare tags: string[];
|
||||
declare version: string;
|
||||
|
||||
declare uid: string;
|
||||
|
||||
declare createdAt: Date;
|
||||
declare updatedAt: Date;
|
||||
}
|
||||
|
||||
AppDemoModel.init(
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
primaryKey: true,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
},
|
||||
title: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
},
|
||||
summary: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
},
|
||||
tags: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: [],
|
||||
},
|
||||
version: {
|
||||
type: DataTypes.INTEGER,
|
||||
defaultValue: 0,
|
||||
},
|
||||
data: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: {},
|
||||
},
|
||||
uid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
tableName: 'kv_app_demo',
|
||||
paranoid: true,
|
||||
},
|
||||
);
|
||||
|
||||
// AppDemoModel.sync({ alter: true, logging: false }).catch((e) => {
|
||||
// console.error('AppDemoModel sync', e);
|
||||
// });
|
||||
@@ -1,3 +1 @@
|
||||
export { sequelize } from './sequelize.ts';
|
||||
|
||||
export * from './minio.ts'
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Client, } from 'minio';
|
||||
import { useConfig } from '@kevisual/use-config';
|
||||
const config = useConfig();
|
||||
const minioConfig = {
|
||||
endPoint: config.MINIO_ENDPOINT || 'localhost',
|
||||
// @ts-ignore
|
||||
port: parseInt(config.MINIO_PORT || '9000'),
|
||||
useSSL: config.MINIO_USE_SSL === 'true',
|
||||
accessKey: config.MINIO_ACCESS_KEY,
|
||||
secretKey: config.MINIO_SECRET_KEY,
|
||||
};
|
||||
export const minioClient = new Client(minioConfig);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { program, Command } from 'commander';
|
||||
// import { useContextKey } from '@kevisual/context';
|
||||
// import * as redisLib from './modules/redis.ts';
|
||||
// import * as sequelizeLib from './modules/sequelize.ts';
|
||||
// import * as minioLib from './modules/minio.ts';
|
||||
|
||||
// export const redis = useContextKey('redis', () => redisLib.redis);
|
||||
// export const minioClient = useContextKey('minioClient', () => minioLib.minioClient);
|
||||
// export const sequelize = useContextKey('sequelize', () => sequelizeLib.sequelize);
|
||||
|
||||
export { program, Command };
|
||||
|
||||
program.description('code-center的一部分工具');
|
||||
program.version('1.0.0', '-v, --version');
|
||||
@@ -1,5 +1,4 @@
|
||||
import { app } from '@/app.ts';
|
||||
import { AppModel, AppListModel } from '../module/index.ts';
|
||||
import { AppModel } from '../module/index.ts';
|
||||
export const mvAppFromUserAToUserB = async (userA: string, userB: string) => {
|
||||
const appList = await AppModel.findAll({
|
||||
where: {
|
||||
|
||||
@@ -80,8 +80,4 @@ AppDomainModel.init(
|
||||
tableName: 'kv_app_domain',
|
||||
paranoid: true,
|
||||
},
|
||||
);
|
||||
|
||||
// AppDomainModel.sync({ alter: true, logging: false }).catch((e) => {
|
||||
// console.error('AppDomainModel sync', e);
|
||||
// });
|
||||
);
|
||||
@@ -1,327 +0,0 @@
|
||||
import { useContextKey } from '@kevisual/context';
|
||||
import { nanoid, customAlphabet } from 'nanoid';
|
||||
import { DataTypes, Model, ModelAttributes } from 'sequelize';
|
||||
import type { Sequelize } from 'sequelize';
|
||||
export const random = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
|
||||
export type Mark = Partial<InstanceType<typeof MarkModel>>;
|
||||
export type MarkData = {
|
||||
md?: string; // markdown
|
||||
mdList?: string[]; // markdown list
|
||||
type?: string; // 类型 markdown | json | html | image | video | audio | code | link | file
|
||||
data?: any;
|
||||
key?: string; // 文件的名称, 唯一
|
||||
push?: boolean; // 是否推送到elasticsearch
|
||||
pushTime?: Date; // 推送时间
|
||||
summary?: string; // 摘要
|
||||
nodes?: MarkDataNode[]; // 节点
|
||||
[key: string]: any;
|
||||
};
|
||||
export type MarkFile = {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
size: number;
|
||||
type: 'self' | 'data' | 'generate'; // generate为生成文件
|
||||
query: string; // 'data.nodes[id].content';
|
||||
hash: string;
|
||||
fileKey: string; // 文件的名称, 唯一
|
||||
};
|
||||
export type MarkDataNode = {
|
||||
id?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
export type MarkConfig = {
|
||||
[key: string]: any;
|
||||
};
|
||||
export type MarkAuth = {
|
||||
[key: string]: any;
|
||||
};
|
||||
/**
|
||||
* 隐秘内容
|
||||
* auth
|
||||
* config
|
||||
*
|
||||
*/
|
||||
export class MarkModel extends Model {
|
||||
declare id: string;
|
||||
declare title: string; // 标题,可以ai生成
|
||||
declare description: string; // 描述,可以ai生成
|
||||
declare cover: string; // 封面,可以ai生成
|
||||
declare thumbnail: string; // 缩略图
|
||||
declare key: string; // 文件路径
|
||||
declare markType: string; // markdown | json | html | image | video | audio | code | link | file
|
||||
declare link: string; // 访问链接
|
||||
declare tags: string[]; // 标签
|
||||
declare summary: string; // 摘要, description的简化版
|
||||
declare data: MarkData; // 数据
|
||||
|
||||
declare uid: string; // 操作用户的id
|
||||
declare puid: string; // 父级用户的id, 真实用户
|
||||
declare config: MarkConfig; // mark属于一定不会暴露的内容。
|
||||
|
||||
declare fileList: MarkFile[]; // 文件管理
|
||||
declare uname: string; // 用户的名称, 或者着别名
|
||||
|
||||
declare markedAt: Date; // 标记时间
|
||||
declare createdAt: Date;
|
||||
declare updatedAt: Date;
|
||||
declare version: number;
|
||||
/**
|
||||
* 加锁更新data中的node的节点,通过node的id
|
||||
* @param param0
|
||||
*/
|
||||
static async updateJsonNode(id: string, node: MarkDataNode, opts?: { operate?: 'update' | 'delete'; Model?: any; sequelize?: Sequelize }) {
|
||||
const sequelize = opts?.sequelize || (await useContextKey('sequelize'));
|
||||
const transaction = await sequelize.transaction(); // 开启事务
|
||||
const operate = opts.operate || 'update';
|
||||
const isUpdate = operate === 'update';
|
||||
const Model = opts.Model || MarkModel;
|
||||
try {
|
||||
// 1. 获取当前的 JSONB 字段值(加锁)
|
||||
const mark = await Model.findByPk(id, {
|
||||
transaction,
|
||||
lock: transaction.LOCK.UPDATE, // 加锁,防止其他事务同时修改
|
||||
});
|
||||
if (!mark) {
|
||||
throw new Error('Mark not found');
|
||||
}
|
||||
// 2. 修改特定的数组元素
|
||||
const data = mark.data as MarkData;
|
||||
const items = data.nodes;
|
||||
if (!node.id) {
|
||||
node.id = random(12);
|
||||
}
|
||||
|
||||
// 找到要更新的元素
|
||||
const itemIndex = items.findIndex((item) => item.id === node.id);
|
||||
if (itemIndex === -1) {
|
||||
isUpdate && items.push(node);
|
||||
} else {
|
||||
if (isUpdate) {
|
||||
items[itemIndex] = node;
|
||||
} else {
|
||||
items.splice(itemIndex, 1);
|
||||
}
|
||||
}
|
||||
const version = Number(mark.version) + 1;
|
||||
// 4. 更新 JSONB 字段
|
||||
const result = await mark.update(
|
||||
{
|
||||
data: {
|
||||
...data,
|
||||
nodes: items,
|
||||
},
|
||||
version,
|
||||
},
|
||||
{ transaction },
|
||||
);
|
||||
|
||||
await transaction.commit();
|
||||
return result;
|
||||
} catch (error) {
|
||||
await transaction.rollback();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
static async updateJsonNodes(id: string, nodes: { node: MarkDataNode; operate?: 'update' | 'delete' }[], opts?: { Model?: any; sequelize?: Sequelize }) {
|
||||
const sequelize = opts?.sequelize || (await useContextKey('sequelize'));
|
||||
const transaction = await sequelize.transaction(); // 开启事务
|
||||
const Model = opts?.Model || MarkModel;
|
||||
try {
|
||||
const mark = await Model.findByPk(id, {
|
||||
transaction,
|
||||
lock: transaction.LOCK.UPDATE, // 加锁,防止其他事务同时修改
|
||||
});
|
||||
if (!mark) {
|
||||
throw new Error('Mark not found');
|
||||
}
|
||||
const data = mark.data as MarkData;
|
||||
const _nodes = data.nodes || [];
|
||||
// 过滤不在nodes中的节点
|
||||
const blankNodes = nodes.filter((node) => !_nodes.find((n) => n.id === node.node.id)).map((node) => node.node);
|
||||
// 更新或删除节点
|
||||
const newNodes = _nodes
|
||||
.map((node) => {
|
||||
const nodeOperate = nodes.find((n) => n.node.id === node.id);
|
||||
if (nodeOperate) {
|
||||
if (nodeOperate.operate === 'delete') {
|
||||
return null;
|
||||
}
|
||||
return nodeOperate.node;
|
||||
}
|
||||
return node;
|
||||
})
|
||||
.filter((node) => node !== null);
|
||||
const version = Number(mark.version) + 1;
|
||||
const result = await mark.update(
|
||||
{
|
||||
data: {
|
||||
...data,
|
||||
nodes: [...blankNodes, ...newNodes],
|
||||
},
|
||||
version,
|
||||
},
|
||||
{ transaction },
|
||||
);
|
||||
await transaction.commit();
|
||||
return result;
|
||||
} catch (error) {
|
||||
await transaction.rollback();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
static async updateData(id: string, data: MarkData, opts: { Model?: any; sequelize?: Sequelize }) {
|
||||
const sequelize = opts.sequelize || (await useContextKey('sequelize'));
|
||||
const transaction = await sequelize.transaction(); // 开启事务
|
||||
const Model = opts.Model || MarkModel;
|
||||
const mark = await Model.findByPk(id, {
|
||||
transaction,
|
||||
lock: transaction.LOCK.UPDATE, // 加锁,防止其他事务同时修改
|
||||
});
|
||||
if (!mark) {
|
||||
throw new Error('Mark not found');
|
||||
}
|
||||
const version = Number(mark.version) + 1;
|
||||
const result = await mark.update(
|
||||
{
|
||||
...mark.data,
|
||||
...data,
|
||||
data: {
|
||||
...mark.data,
|
||||
...data,
|
||||
},
|
||||
version,
|
||||
},
|
||||
{ transaction },
|
||||
);
|
||||
await transaction.commit();
|
||||
return result;
|
||||
}
|
||||
static async createNew(data: any, opts: { Model?: any; sequelize?: Sequelize }) {
|
||||
const sequelize = opts.sequelize || (await useContextKey('sequelize'));
|
||||
const transaction = await sequelize.transaction(); // 开启事务
|
||||
const Model = opts.Model || MarkModel;
|
||||
const result = await Model.create({ ...data, version: 1 }, { transaction });
|
||||
await transaction.commit();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
export type MarkInitOpts<T = any> = {
|
||||
tableName: string;
|
||||
sequelize?: Sequelize;
|
||||
callInit?: (attribute: ModelAttributes) => ModelAttributes;
|
||||
Model?: T extends typeof MarkModel ? T : typeof MarkModel;
|
||||
};
|
||||
export type Opts = {
|
||||
sync?: boolean;
|
||||
alter?: boolean;
|
||||
logging?: boolean | ((...args: any) => any);
|
||||
force?: boolean;
|
||||
};
|
||||
export const MarkMInit = async <T = any>(opts: MarkInitOpts<T>, sync?: Opts) => {
|
||||
const sequelize = await useContextKey('sequelize');
|
||||
opts.sequelize = opts.sequelize || sequelize;
|
||||
const { callInit, Model, ...optsRest } = opts;
|
||||
const modelAttribute = {
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
primaryKey: true,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
comment: 'id',
|
||||
},
|
||||
title: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
},
|
||||
key: {
|
||||
type: DataTypes.TEXT, // 对应的minio的文件路径
|
||||
defaultValue: '',
|
||||
},
|
||||
markType: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: 'md', // markdown | json | html | image | video | audio | code | link | file
|
||||
comment: '类型',
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
},
|
||||
cover: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
comment: '封面',
|
||||
},
|
||||
thumbnail: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
comment: '缩略图',
|
||||
},
|
||||
link: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
comment: '链接',
|
||||
},
|
||||
tags: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: [],
|
||||
},
|
||||
summary: {
|
||||
type: DataTypes.TEXT,
|
||||
defaultValue: '',
|
||||
comment: '摘要',
|
||||
},
|
||||
config: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: {},
|
||||
},
|
||||
data: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: {},
|
||||
},
|
||||
fileList: {
|
||||
type: DataTypes.JSONB,
|
||||
defaultValue: [],
|
||||
},
|
||||
uname: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: '',
|
||||
comment: '用户的名称, 更新后的用户的名称',
|
||||
},
|
||||
version: {
|
||||
type: DataTypes.INTEGER, // 更新刷新版本,多人协作
|
||||
defaultValue: 1,
|
||||
},
|
||||
markedAt: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: true,
|
||||
comment: '标记时间',
|
||||
},
|
||||
uid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
},
|
||||
puid: {
|
||||
type: DataTypes.UUID,
|
||||
allowNull: true,
|
||||
},
|
||||
};
|
||||
const InitModel = Model || MarkModel;
|
||||
InitModel.init(callInit ? callInit(modelAttribute) : modelAttribute, {
|
||||
sequelize,
|
||||
paranoid: true,
|
||||
...optsRest,
|
||||
});
|
||||
if (sync && sync.sync) {
|
||||
const { sync: _, ...rest } = sync;
|
||||
MarkModel.sync({ alter: true, logging: false, ...rest }).catch((e) => {
|
||||
console.error('MarkModel sync', e);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const markModelInit = MarkMInit;
|
||||
|
||||
export const syncMarkModel = async (sync?: Opts, tableName = 'micro_mark') => {
|
||||
const sequelize = await useContextKey('sequelize');
|
||||
await MarkMInit({ sequelize, tableName }, sync);
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
export * from '@kevisual/code-center-module/src/mark/mark-model.ts';
|
||||
import { markModelInit, MarkModel, syncMarkModel } from '@kevisual/code-center-module/src/mark/mark-model.ts';
|
||||
export { markModelInit, MarkModel };
|
||||
|
||||
syncMarkModel({ sync: true, alter: true, logging: false });
|
||||
@@ -1,4 +1,4 @@
|
||||
import { app, sequelize } from '@/app.ts';
|
||||
import { app } from '@/app.ts';
|
||||
import { Org } from '@/models/org.ts';
|
||||
import { User } from '@/models/user.ts';
|
||||
import { Op } from 'sequelize';
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import { program, Command } from '../program.ts';
|
||||
import { initUser, logger, close } from './common.ts';
|
||||
const usrCommand = new Command('user').description('用户相关操作');
|
||||
program.addCommand(usrCommand);
|
||||
|
||||
const changePwd = new Command('pwd')
|
||||
.description('修改用户密码')
|
||||
.option('-u, --username <username>', '用户名')
|
||||
.option('-p, --password <password>', '新密码')
|
||||
.action(async (opts) => {
|
||||
const username = opts.username;
|
||||
const password = opts.password;
|
||||
if (!username) {
|
||||
logger.error('用户名不能为空');
|
||||
close();
|
||||
return;
|
||||
}
|
||||
const { User } = await initUser();
|
||||
const newPassword = password || 'kevisual';
|
||||
|
||||
logger.info(`用户名: ${username}`);
|
||||
logger.info(`新密码: ${newPassword}`);
|
||||
const user = await User.findOne({ where: { username: username }, logging: false });
|
||||
if (!user) {
|
||||
logger.error('用户不存在');
|
||||
return;
|
||||
}
|
||||
const newP = await user.createPassword(newPassword);
|
||||
logger.info('新密码加密成功', '新密码: ', newPassword);
|
||||
close();
|
||||
});
|
||||
usrCommand.addCommand(changePwd);
|
||||
|
||||
const list = new Command('list').description('列出所有用户').action(async () => {
|
||||
console.log('列出所有用户 start');
|
||||
const { User } = await initUser();
|
||||
console.log('列出所有用户');
|
||||
const users = await User.findAll({ limit: 10, order: [['createdAt', 'DESC']] });
|
||||
if (users.length === 0) {
|
||||
logger.info('没有用户');
|
||||
return;
|
||||
}
|
||||
users.forEach((user) => {
|
||||
console.log(`用户名: ${user.username}`);
|
||||
});
|
||||
console.log(`用户数量: ${users.length}`);
|
||||
await close();
|
||||
});
|
||||
|
||||
usrCommand.addCommand(list);
|
||||
@@ -1,3 +0,0 @@
|
||||
import * as redisLib from '../modules/redis.ts';
|
||||
import { useContextKey, useContext } from '@kevisual/context';
|
||||
export const redis = useContextKey('redis', () => redisLib.redis);
|
||||
@@ -1,34 +0,0 @@
|
||||
import { config } from '../modules/config.ts';
|
||||
import { sequelize } from '../modules/sequelize.ts';
|
||||
export { program, Command } from '../program.ts';
|
||||
import { User, UserInit, OrgInit, Org, UserSecretInit, UserSecret } from '../auth/index.ts';
|
||||
import { Logger } from '@kevisual/logger';
|
||||
export const close = async () => {
|
||||
process.exit(0);
|
||||
};
|
||||
export { sequelize };
|
||||
export const logger = new Logger({
|
||||
level: (config?.LOG_LEVEL || 'info') as any,
|
||||
showTime: true,
|
||||
});
|
||||
|
||||
export const initUser = async () => {
|
||||
console.log('init user');
|
||||
await UserInit(sequelize, undefined, {
|
||||
alter: true,
|
||||
logging: false,
|
||||
});
|
||||
await OrgInit(sequelize, undefined, {
|
||||
alter: true,
|
||||
logging: false,
|
||||
});
|
||||
await UserSecretInit(sequelize, undefined, {
|
||||
alter: true,
|
||||
logging: false,
|
||||
});
|
||||
return {
|
||||
User: User,
|
||||
Org: Org,
|
||||
UserSecret: UserSecret,
|
||||
};
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
import { AppListModel, AppModel } from '../routes/app-manager/module/index.ts';
|
||||
|
||||
import { program, Command, close } from './common.ts';
|
||||
|
||||
const app = program.command('app');
|
||||
|
||||
const appList = new Command('list').action(async () => {
|
||||
const list = await AppListModel.findAll();
|
||||
console.log(list.map((item) => item.toJSON()));
|
||||
close();
|
||||
});
|
||||
app.addCommand(appList);
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Client } from 'minio'
|
||||
|
||||
export async function createBucket(client: Client, bucketName: string) {
|
||||
const exists = await client.bucketExists(bucketName)
|
||||
if (!exists) {
|
||||
await client.makeBucket(bucketName, '')
|
||||
console.log(`Bucket "${bucketName}" created successfully.`)
|
||||
} else {
|
||||
console.log(`Bucket "${bucketName}" already exists.`)
|
||||
}
|
||||
}
|
||||
|
||||
const minioClient = new Client({
|
||||
endPoint: 'minio.kevisual.cn',
|
||||
port: 9000,
|
||||
useSSL: false,
|
||||
accessKey: 'admin',
|
||||
secretKey: 'xiongxiao',
|
||||
})
|
||||
createBucket(minioClient, 'nocodb').catch((err) => {
|
||||
console.error('Error creating bucket:', err)
|
||||
})
|
||||
@@ -1,62 +0,0 @@
|
||||
import { sequelize } from '../modules/sequelize.ts';
|
||||
import { initUser } from '../scripts/common.ts';
|
||||
import '../scripts/common-redis.ts';
|
||||
import { useContextKey } from '@kevisual/context';
|
||||
|
||||
export const main = async () => {
|
||||
const models = await initUser();
|
||||
|
||||
const username = 'root';
|
||||
const orgname = 'admin';
|
||||
|
||||
const user = await models.User.findOne({ where: { username } });
|
||||
const org = await models.User.findOne({ where: { username: orgname } });
|
||||
|
||||
console.log('user.id', user?.id);
|
||||
console.log('org.id', org?.id);
|
||||
// const userSecret1 = await models.UserSecret.createSecret(user?.id!);
|
||||
// userSecret1.title = 'root secret';
|
||||
// await userSecret1.save();
|
||||
// await models.UserSecret.destroy({
|
||||
// where: {
|
||||
// orgId: '16a496d4-8cd6-4e02-b403-c2adc006a53d',
|
||||
// },
|
||||
// });
|
||||
const userSecret2 = await models.UserSecret.createSecret(user?.id!, org?.id!);
|
||||
userSecret2.title = 'root org secret';
|
||||
await userSecret2.save();
|
||||
|
||||
const secretList = await models.UserSecret.findAll();
|
||||
for (const secret of secretList) {
|
||||
console.log(`\nSecret ID: ${secret.id}, User ID: ${secret.userId}, Org ID: ${secret.orgId}, Token: ${secret.token}, Expired Time: ${secret.expiredTime}`);
|
||||
}
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
export const dropTable = async () => {
|
||||
await sequelize.query('DROP TABLE IF EXISTS "cf_user_secrets"');
|
||||
console.log('UserSecret table dropped');
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
// dropTable()
|
||||
|
||||
const token1 = 'sk_tvwzgp5lky8iupawh0encvd52vji4o8argvd2x668gn15q83xpgo8fe10ny7wfsq';
|
||||
const orgToken2 = 'sk_x37p8iifh6k18c3f121w49nmfy1sbjqpyol9fcsz0lmc5dz493wrfwvtxc4gi9od';
|
||||
|
||||
export const main2 = async () => {
|
||||
const redis = useContextKey('redis');
|
||||
if (!redis) {
|
||||
console.error('Redis is not initialized');
|
||||
return;
|
||||
}
|
||||
const models = await initUser();
|
||||
const UserSecret = models.UserSecret;
|
||||
const v = await models.UserSecret.verifyToken(token1);
|
||||
console.log('verifyToken', v);
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
// main2();
|
||||
@@ -1,46 +0,0 @@
|
||||
import { useContextKey } from '@kevisual/context';
|
||||
import { sequelize } from '../modules/sequelize.ts';
|
||||
import { MarkModel, syncMarkModel } from '../routes/mark/model.ts';
|
||||
export const sequelize2 = useContextKey('sequelize', () => sequelize);
|
||||
|
||||
const main = async () => {
|
||||
// 把所有markmodel的表的source字段的类型改为jsonb
|
||||
// const marks = await MarkModel.findAll();
|
||||
// const mark = marks[0];
|
||||
|
||||
// for (const mark of marks) {
|
||||
// if (mark.source) {
|
||||
// try {
|
||||
// await MarkModel.update({ source: {} }, { where: { id: mark.id } });
|
||||
// } catch (e) {
|
||||
// console.error('update source error:', e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
console.log('update source success');
|
||||
// await MarkModel.sync({ alter: true, logging: true }).catch((e) => {
|
||||
// console.error('MarkModel.sync error:', e);
|
||||
// });
|
||||
await syncMarkModel({ alter: true, logging: true, sync: true });
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
const sql = `ALTER TABLE "micro_mark" ALTER COLUMN "source" DROP NOT NULL;ALTER TABLE "micro_mark" ALTER COLUMN "source" SET DEFAULT '{}';ALTER TABLE "micro_mark" ALTER COLUMN "source" TYPE JSONB ; COMMENT ON COLUMN "micro_mark"."source" IS '需要的数据的来源,作为一个备注使用。';`;
|
||||
|
||||
// sequelize
|
||||
/**
|
||||
* 失败
|
||||
*/
|
||||
const runSql = async () => {
|
||||
sequelize
|
||||
.query(sql)
|
||||
.then(() => {
|
||||
console.log('update source success');
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('update source error:', e);
|
||||
});
|
||||
};
|
||||
|
||||
// runSql();
|
||||
@@ -1,48 +0,0 @@
|
||||
import { sequelize } from '../modules/sequelize.ts';
|
||||
import { User, UserInit, UserServices, Org, OrgInit } from '../auth/index.ts';
|
||||
|
||||
// User.sync({ alter: true, logging: true }).then(() => {
|
||||
// console.log('sync user done');
|
||||
// });
|
||||
|
||||
// class UserChange extends User {
|
||||
// static async syncUser() {
|
||||
// await UserChange.sync({ alter: true, logging: false });
|
||||
// console.log('sync user done');
|
||||
// }
|
||||
// }
|
||||
export const main = async () => {
|
||||
await UserInit(sequelize, null, {
|
||||
alter: true,
|
||||
logging: false,
|
||||
});
|
||||
await OrgInit(sequelize, null, {
|
||||
alter: true,
|
||||
logging: false,
|
||||
});
|
||||
const user = await User.findAll({});
|
||||
for (const u of user) {
|
||||
console.log(u.username, u.type);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
export const changeRootPassword = async () => {
|
||||
await OrgInit(sequelize, null, {
|
||||
alter: true,
|
||||
logging: false,
|
||||
});
|
||||
await UserInit(sequelize, null, {
|
||||
alter: true,
|
||||
logging: false,
|
||||
});
|
||||
const user = await User.findOne({ where: { username: 'root' } });
|
||||
if (user) {
|
||||
await user.createPassword('');
|
||||
await user.save();
|
||||
console.log('change root password done');
|
||||
process.exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
// changeRootPassword();
|
||||
@@ -1,10 +0,0 @@
|
||||
import { sequelize } from '../modules/sequelize.ts';
|
||||
|
||||
console.log('sequelize');
|
||||
|
||||
// 获取所有表名
|
||||
const [tables] = await sequelize.query(
|
||||
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"
|
||||
);
|
||||
|
||||
console.log('tables', tables);
|
||||
Reference in New Issue
Block a user