feat: wip

This commit is contained in:
Devessier
2026-02-25 11:04:45 +01:00
parent b8d798f302
commit e68b9c7062
9 changed files with 100 additions and 82493 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,71 +0,0 @@
{
"application": {
"universalIdentifier": "0fac8de4-9d11-492b-9e6a-577e11e1c442",
"displayName": "Twenty for Twenty",
"description": "",
"defaultRoleUniversalIdentifier": "4bd740cc-f6a1-40c5-b46b-e2a4dbf5af04",
"applicationVariables": {
"CLICKHOUSE_URL": {
"universalIdentifier": "b204304f-d3d3-4ae2-aafa-24b21c159181",
"description": "The URL of the ClickHouse server, including the protocol and port (e.g., http://localhost:8123)",
"isSecret": true
},
"CLICKHOUSE_USERNAME": {
"universalIdentifier": "711e8ea8-8b19-4cf0-82ab-ab44417312bd",
"description": "The username for authenticating with the ClickHouse server",
"isSecret": true
},
"CLICKHOUSE_PASSWORD": {
"universalIdentifier": "faba7ed7-9f94-4202-944b-c25c683e9504",
"description": "The password for authenticating with the ClickHouse server",
"isSecret": true
},
"CLICKHOUSE_DATABASE": {
"universalIdentifier": "3e6698fa-0c00-49e5-9c4d-34d5b177bff3",
"description": "The name of the ClickHouse database to connect to",
"isSecret": true
}
},
"yarnLockChecksum": "31c83d74119b810f2c956d41c2ee3576",
"packageJsonChecksum": "1807c41d2a51ee36385ece5d35b3ef4f",
"apiClientChecksum": "6893d8ff050e58aa9fff038f6e0efae7"
},
"objects": [],
"fields": [],
"roles": [
{
"universalIdentifier": "4bd740cc-f6a1-40c5-b46b-e2a4dbf5af04",
"label": "Twenty for Twenty default function role",
"description": "Twenty for Twenty default function role",
"canReadAllObjectRecords": true,
"canUpdateAllObjectRecords": true,
"canSoftDeleteAllObjectRecords": true,
"canDestroyAllObjectRecords": false
}
],
"skills": [],
"logicFunctions": [
{
"universalIdentifier": "3897e059-715e-4a4b-b165-c44f17d2e30a",
"name": "product-data-create-users",
"description": "A simple logic function",
"timeoutSeconds": 5,
"cronTriggerSettings": {
"pattern": "*/10 * * * *"
},
"toolInputSchema": {
"type": "object",
"properties": {}
},
"handlerName": "default.config.handler",
"sourceHandlerPath": "src/logic-functions/create-users.ts",
"builtHandlerPath": "src/logic-functions/create-users.mjs",
"builtHandlerChecksum": "f6c7eafb1b70e06599bb79ef382e773a"
}
],
"frontComponents": [],
"publicAssets": [],
"views": [],
"navigationMenuItems": [],
"pageLayouts": []
}
@@ -44952,6 +44952,9 @@ var Twenty = class {
}
};
// src/logic-functions/create-users.ts
import { isDefined } from "twenty-shared/utils";
// node_modules/zod/v4/classic/external.js
var external_exports = {};
__export(external_exports, {
@@ -58790,8 +58793,10 @@ var fetchUsersFromClickHouse = async () => {
*
FROM
${clickHouseDatabase}.user
LIMIT
20
WHERE
lastActivityDate >= now() - INTERVAL 500 MINUTE
AND
lastActivityDate <= now()
FORMAT
JSONEachRow;
`;
@@ -58839,10 +58844,19 @@ var fetchAllPeopleFromTwentyByEmail = async (emails) => {
return allPeople.people?.edges.map((edge) => edge.node) ?? [];
};
var handler = async () => {
const now = /* @__PURE__ */ new Date();
try {
const { users } = await fetchUsersFromClickHouse();
const emails = users.map((user) => user.email);
const people = await fetchAllPeopleFromTwentyByEmail(emails);
for (const user of users) {
const matchingPerson = people.find(
(person) => isDefined(person.emails?.primaryEmail) && person.emails.primaryEmail.toLowerCase() === user.email.toLowerCase()
);
if (isDefined(matchingPerson)) {
} else {
}
}
return {
message: `Successfully fetched ${users.length} users from ClickHouse`
};
File diff suppressed because one or more lines are too long
@@ -1,8 +1,14 @@
import { defineLogicFunction } from 'twenty-sdk';
import Twenty from 'twenty-sdk/generated';
import { isDefined } from 'twenty-shared/utils';
import { z } from 'zod';
const client = new Twenty();
const client = new Twenty({
url: 'https://twentyfortwenty.twenty.com',
headers: {
Authorization: `Bearer ${'lol'}`,
}
});
const applicationConfigSchema = z.object({
CLICKHOUSE_DATABASE: z.string().nonempty(),
@@ -81,8 +87,10 @@ const fetchUsersFromClickHouse = async (): Promise<{
*
FROM
${clickHouseDatabase}.user
LIMIT
20
WHERE
lastActivityDate >= now() - INTERVAL 500 MINUTE
AND
lastActivityDate <= now()
FORMAT
JSONEachRow;
`;
@@ -148,6 +156,8 @@ const fetchAllPeopleFromTwentyByEmail = async (emails: string[]) => {
};
const handler = async (): Promise<{ message: string }> => {
const now = new Date();
try {
const { users } = await fetchUsersFromClickHouse();
@@ -155,6 +165,21 @@ const handler = async (): Promise<{ message: string }> => {
const people = await fetchAllPeopleFromTwentyByEmail(emails);
for (const user of users) {
const matchingPerson = people.find(
(person) =>
isDefined(person.emails?.primaryEmail) &&
person.emails.primaryEmail.toLowerCase() === user.email.toLowerCase(),
);
if (isDefined(matchingPerson)) {
// update cloud user
} else {
// create people
// create or update cloud user
}
}
return {
message: `Successfully fetched ${users.length} users from ClickHouse`,
};
@@ -0,0 +1,9 @@
import { defineNavigationMenuItem } from 'twenty-sdk';
export default defineNavigationMenuItem({
universalIdentifier: '156c42d2-a60b-414e-a6f1-cd4c0c8f5d05',
name: 'cloud-user',
icon: 'IconList',
position: 0,
viewUniversalIdentifier: 'ef3a4ba5-c542-4511-bb09-db35195cc85a',
});
@@ -0,0 +1,20 @@
import { defineObject } from 'twenty-sdk';
export default defineObject({
universalIdentifier: '8c53efa7-c6b2-44f5-9d85-3c2d8928a9c0',
nameSingular: 'cloudUser',
namePlural: 'cloudUsers',
labelSingular: 'Cloud User',
labelPlural: 'Cloud Users',
icon: 'IconBox',
fields: [
// Add your fields here using defineField helper
// Example:
// {
// universalIdentifier: '...',
// type: FieldMetadataType.TEXT,
// name: 'description',
// label: 'Description',
// },
],
});
@@ -0,0 +1,25 @@
import { defineView } from 'twenty-sdk';
export default defineView({
universalIdentifier: 'ef3a4ba5-c542-4511-bb09-db35195cc85a',
name: 'all-cloud-user',
objectUniversalIdentifier: '8c53efa7-c6b2-44f5-9d85-3c2d8928a9c0',
icon: 'IconList',
position: 0,
// fields: [
// {
// universalIdentifier: '...',
// fieldMetadataUniversalIdentifier: '...',
// position: 0,
// isVisible: true,
// },
// ],
// filters: [
// {
// universalIdentifier: '...',
// fieldMetadataUniversalIdentifier: '...',
// operand: 'Contains',
// value: '',
// },
// ],
});