mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-06 17:57:42 +02:00
UBERF-8425: Global accounts (#7573)
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
import { ClientWorkspaceInfo } from '@hcengineering/account'
|
||||
import config from './config'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function getWorkspaceInfo (token: string, updateLastModified = false): Promise<ClientWorkspaceInfo> {
|
||||
const accountsUrl = config.AccountsURL
|
||||
const workspaceInfo = await (
|
||||
await fetch(accountsUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
method: 'getWorkspaceInfo',
|
||||
params: updateLastModified ? [true] : []
|
||||
})
|
||||
})
|
||||
).json()
|
||||
|
||||
return workspaceInfo.result as ClientWorkspaceInfo
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import client, { ClientSocket } from '@hcengineering/client'
|
||||
import clientResources from '@hcengineering/client-resources'
|
||||
import { Client, ClientConnectEvent, systemAccountEmail } from '@hcengineering/core'
|
||||
import { Client, ClientConnectEvent, systemAccountUuid, WorkspaceUuid } from '@hcengineering/core'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import { getTransactorEndpoint } from '@hcengineering/server-client'
|
||||
import serverToken, { generateToken } from '@hcengineering/server-token'
|
||||
@@ -16,7 +16,7 @@ import config from './config'
|
||||
* @public
|
||||
*/
|
||||
export async function createPlatformClient (
|
||||
workspace: string,
|
||||
workspace: WorkspaceUuid,
|
||||
timeout: number,
|
||||
reconnect?: (event: ClientConnectEvent, data: any) => Promise<void>
|
||||
): Promise<{ client: Client, endpoint: string }> {
|
||||
@@ -29,13 +29,7 @@ export async function createPlatformClient (
|
||||
})
|
||||
|
||||
setMetadata(serverToken.metadata.Secret, config.ServerSecret)
|
||||
const token = generateToken(
|
||||
systemAccountEmail,
|
||||
{
|
||||
name: workspace
|
||||
},
|
||||
{ mode: 'github' }
|
||||
)
|
||||
const token = generateToken(systemAccountUuid, workspace, { service: 'github', mode: 'github' })
|
||||
setMetadata(client.metadata.UseBinaryProtocol, true)
|
||||
setMetadata(client.metadata.UseProtocolCompression, true)
|
||||
setMetadata(client.metadata.ConnectionTimeout, timeout)
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
//
|
||||
|
||||
import { CollaboratorClient, getClient as getCollaboratorClient } from '@hcengineering/collaborator-client'
|
||||
import { systemAccountEmail, WorkspaceId } from '@hcengineering/core'
|
||||
import { systemAccountUuid, WorkspaceUuid } from '@hcengineering/core'
|
||||
import { generateToken } from '@hcengineering/server-token'
|
||||
import config from './config'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function createCollaboratorClient (workspaceId: WorkspaceId): CollaboratorClient {
|
||||
const token = generateToken(systemAccountEmail, workspaceId, { mode: 'github' })
|
||||
export function createCollaboratorClient (workspaceId: WorkspaceUuid): CollaboratorClient {
|
||||
const token = generateToken(systemAccountUuid, workspaceId, { service: 'github', mode: 'github' })
|
||||
return getCollaboratorClient(workspaceId, token, config.CollaboratorURL)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Account, Doc, Ref, TxOperations } from '@hcengineering/core'
|
||||
import { PersonId, Doc, Ref, TxOperations } from '@hcengineering/core'
|
||||
import notification, { DocNotifyContext } from '@hcengineering/notification'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { PersonSpace } from '@hcengineering/contact'
|
||||
@@ -7,7 +7,7 @@ import github from '@hcengineering/github'
|
||||
export async function createNotification (
|
||||
client: TxOperations,
|
||||
forDoc: Doc,
|
||||
data: { user: Ref<Account>, space: Ref<PersonSpace>, message: IntlString, props: Record<string, any> }
|
||||
data: { user: PersonId, space: Ref<PersonSpace>, message: IntlString, props: Record<string, any> }
|
||||
): Promise<void> {
|
||||
let docNotifyContext = await client.findOne(notification.class.DocNotifyContext, { objectId: forDoc._id })
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
//
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
BrandingMap,
|
||||
Client,
|
||||
ClientConnectEvent,
|
||||
@@ -13,28 +13,28 @@ import core, {
|
||||
isActiveMode,
|
||||
MeasureContext,
|
||||
RateLimiter,
|
||||
Ref,
|
||||
systemAccountEmail,
|
||||
TimeRateLimiter,
|
||||
TxOperations
|
||||
TxOperations,
|
||||
systemAccountUuid,
|
||||
WorkspaceUuid,
|
||||
WorkspaceInfoWithStatus
|
||||
} from '@hcengineering/core'
|
||||
import github, { GithubAuthentication, makeQuery, type GithubIntegration } from '@hcengineering/github'
|
||||
import { getMongoClient, MongoClientReference } from '@hcengineering/mongo'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import { buildStorageFromConfig, storageConfigFromEnv } from '@hcengineering/server-storage'
|
||||
import serverToken, { generateToken } from '@hcengineering/server-token'
|
||||
import { getClient as getAccountClient } from '@hcengineering/account-client'
|
||||
import tracker from '@hcengineering/tracker'
|
||||
import { Installation, type InstallationCreatedEvent, type InstallationUnsuspendEvent } from '@octokit/webhooks-types'
|
||||
import { Collection } from 'mongodb'
|
||||
import { App, Octokit } from 'octokit'
|
||||
|
||||
import { ClientWorkspaceInfo } from '@hcengineering/account'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { SplitLogger } from '@hcengineering/analytics-service'
|
||||
import contact, { Person, PersonAccount } from '@hcengineering/contact'
|
||||
import contact, { Person } from '@hcengineering/contact'
|
||||
import { type StorageAdapter } from '@hcengineering/server-core'
|
||||
import { join } from 'path'
|
||||
import { getWorkspaceInfo } from './account'
|
||||
import { createPlatformClient } from './client'
|
||||
import config from './config'
|
||||
import { registerLoaders } from './loaders'
|
||||
@@ -219,7 +219,7 @@ export class PlatformWorker {
|
||||
ctx: MeasureContext,
|
||||
workspace: string,
|
||||
installationId: number,
|
||||
accountId: Ref<Account>
|
||||
accountId: PersonId
|
||||
): Promise<void> {
|
||||
const oldInstallation = this.integrations.find((it) => it.installationId === installationId)
|
||||
if (oldInstallation != null) {
|
||||
@@ -243,7 +243,7 @@ export class PlatformWorker {
|
||||
} else {
|
||||
let client: Client | undefined
|
||||
try {
|
||||
;({ client } = await createPlatformClient(oldWorkspace, 30000))
|
||||
;({ client } = await createPlatformClient(oldWorkspace as WorkspaceUuid, 30000)) // TODO: FIXME
|
||||
await this.removeInstallationFromWorkspace(oldWorker, installationId)
|
||||
await client.close()
|
||||
} catch (err: any) {
|
||||
@@ -315,7 +315,7 @@ export class PlatformWorker {
|
||||
workspace: string
|
||||
code: string
|
||||
state: string
|
||||
accountId: Ref<Account>
|
||||
accountId: PersonId
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const uri =
|
||||
@@ -387,148 +387,150 @@ export class PlatformWorker {
|
||||
}
|
||||
|
||||
private async updateAccountAuthRecord (
|
||||
payload: { workspace: string, accountId: Ref<Account> },
|
||||
payload: { workspace: string, accountId: PersonId },
|
||||
update: DocumentUpdate<GithubAuthentication>,
|
||||
dta: GithubUserRecord | undefined,
|
||||
revoke: boolean
|
||||
): Promise<void> {
|
||||
try {
|
||||
let platformClient: Client | undefined
|
||||
let shouldClose = false
|
||||
try {
|
||||
platformClient = this.clients.get(payload.workspace)?.client
|
||||
if (platformClient === undefined) {
|
||||
shouldClose = true
|
||||
;({ client: platformClient } = await createPlatformClient(payload.workspace, 30000))
|
||||
}
|
||||
const client = new TxOperations(platformClient, payload.accountId)
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// try {
|
||||
// let platformClient: Client | undefined
|
||||
// let shouldClose = false
|
||||
// try {
|
||||
// platformClient = this.clients.get(payload.workspace)?.client
|
||||
// if (platformClient === undefined) {
|
||||
// shouldClose = true
|
||||
// ;({ client: platformClient } = await createPlatformClient(payload.workspace, 30000))
|
||||
// }
|
||||
// const client = new TxOperations(platformClient, payload.accountId)
|
||||
|
||||
let personAuths = await client.findAll(github.class.GithubAuthentication, {
|
||||
attachedTo: payload.accountId
|
||||
})
|
||||
if (personAuths.length > 1) {
|
||||
for (const auth of personAuths.slice(1)) {
|
||||
await client.remove(auth)
|
||||
}
|
||||
personAuths.length = 1
|
||||
}
|
||||
// let personAuths = await client.findAll(github.class.GithubAuthentication, {
|
||||
// attachedTo: payload.accountId
|
||||
// })
|
||||
// if (personAuths.length > 1) {
|
||||
// for (const auth of personAuths.slice(1)) {
|
||||
// await client.remove(auth)
|
||||
// }
|
||||
// personAuths.length = 1
|
||||
// }
|
||||
|
||||
if (revoke) {
|
||||
for (const personAuth of personAuths) {
|
||||
await client.remove(personAuth, Date.now(), payload.accountId)
|
||||
}
|
||||
} else {
|
||||
if (personAuths.length > 0) {
|
||||
await client.update<GithubAuthentication>(personAuths[0], update, false, Date.now(), payload.accountId)
|
||||
} else if (dta !== undefined) {
|
||||
const authId = await client.createDoc<GithubAuthentication>(
|
||||
github.class.GithubAuthentication,
|
||||
core.space.Workspace,
|
||||
{
|
||||
error: null,
|
||||
authRequestTime: Date.now(),
|
||||
createdAt: new Date(),
|
||||
followers: 0,
|
||||
following: 0,
|
||||
nodeId: '',
|
||||
updatedAt: new Date(),
|
||||
url: '',
|
||||
repositories: 0,
|
||||
organizations: { totalCount: 0, nodes: [] },
|
||||
closedIssues: 0,
|
||||
openIssues: 0,
|
||||
mergedPRs: 0,
|
||||
openPRs: 0,
|
||||
closedPRs: 0,
|
||||
repositoryDiscussions: 0,
|
||||
starredRepositories: 0,
|
||||
...update,
|
||||
attachedTo: payload.accountId,
|
||||
login: dta._id
|
||||
},
|
||||
undefined,
|
||||
undefined,
|
||||
payload.accountId
|
||||
)
|
||||
// if (revoke) {
|
||||
// for (const personAuth of personAuths) {
|
||||
// await client.remove(personAuth, Date.now(), payload.accountId)
|
||||
// }
|
||||
// } else {
|
||||
// if (personAuths.length > 0) {
|
||||
// await client.update<GithubAuthentication>(personAuths[0], update, false, Date.now(), payload.accountId)
|
||||
// } else if (dta !== undefined) {
|
||||
// const authId = await client.createDoc<GithubAuthentication>(
|
||||
// github.class.GithubAuthentication,
|
||||
// core.space.Workspace,
|
||||
// {
|
||||
// error: null,
|
||||
// authRequestTime: Date.now(),
|
||||
// createdAt: new Date(),
|
||||
// followers: 0,
|
||||
// following: 0,
|
||||
// nodeId: '',
|
||||
// updatedAt: new Date(),
|
||||
// url: '',
|
||||
// repositories: 0,
|
||||
// organizations: { totalCount: 0, nodes: [] },
|
||||
// closedIssues: 0,
|
||||
// openIssues: 0,
|
||||
// mergedPRs: 0,
|
||||
// openPRs: 0,
|
||||
// closedPRs: 0,
|
||||
// repositoryDiscussions: 0,
|
||||
// starredRepositories: 0,
|
||||
// ...update,
|
||||
// attachedTo: payload.accountId,
|
||||
// login: dta._id
|
||||
// },
|
||||
// undefined,
|
||||
// undefined,
|
||||
// payload.accountId
|
||||
// )
|
||||
|
||||
personAuths = await client.findAll(github.class.GithubAuthentication, {
|
||||
_id: authId
|
||||
})
|
||||
}
|
||||
}
|
||||
// personAuths = await client.findAll(github.class.GithubAuthentication, {
|
||||
// _id: authId
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// We need to re-bind previously created github:login account to a proper person.
|
||||
const account = client.getModel().getObject(payload.accountId) as PersonAccount
|
||||
const person = (await client.findOne(contact.class.Person, { _id: account.person })) as Person
|
||||
if (person !== undefined) {
|
||||
if (!revoke) {
|
||||
const personSpace = await client.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
if (personSpace !== undefined) {
|
||||
await createNotification(client, person, {
|
||||
user: account._id,
|
||||
space: personSpace._id,
|
||||
message: github.string.AuthenticatedWithGithub,
|
||||
props: {
|
||||
login: update.login
|
||||
}
|
||||
})
|
||||
}
|
||||
// // We need to re-bind previously created github:login account to a proper person.
|
||||
// const account = client.getModel().getObject(payload.accountId) as PersonAccount
|
||||
// const person = (await client.findOne(contact.class.Person, { _id: account.person })) as Person
|
||||
// if (person !== undefined) {
|
||||
// if (!revoke) {
|
||||
// const personSpace = await client.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
// if (personSpace !== undefined) {
|
||||
// await createNotification(client, person, {
|
||||
// user: account._id,
|
||||
// space: personSpace._id,
|
||||
// message: github.string.AuthenticatedWithGithub,
|
||||
// props: {
|
||||
// login: update.login
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
const githubAccount = client.getModel().getAccountByEmail('github:' + update.login) as PersonAccount
|
||||
if (githubAccount !== undefined && githubAccount.person !== account.person) {
|
||||
const dummyPerson = githubAccount.person
|
||||
// To add activity entry to dummy person.
|
||||
await client.update(githubAccount, { person: account.person }, false, Date.now(), payload.accountId)
|
||||
// const githubAccount = client.getModel().getAccountByEmail('github:' + update.login) as PersonAccount
|
||||
// if (githubAccount !== undefined && githubAccount.person !== account.person) {
|
||||
// const dummyPerson = githubAccount.person
|
||||
// // To add activity entry to dummy person.
|
||||
// await client.update(githubAccount, { person: account.person }, false, Date.now(), payload.accountId)
|
||||
|
||||
const dPerson = (await client.findOne(contact.class.Person, { _id: dummyPerson })) as Person
|
||||
if (person !== undefined && dPerson !== undefined) {
|
||||
const personSpace = await client.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
if (personSpace !== undefined) {
|
||||
await createNotification(client, dPerson, {
|
||||
user: githubAccount._id,
|
||||
space: personSpace._id,
|
||||
message: github.string.AuthenticatedWithGithubEmployee,
|
||||
props: {
|
||||
login: update.login
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const personSpace = await client.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
if (personSpace !== undefined) {
|
||||
await createNotification(client, person, {
|
||||
user: account._id,
|
||||
space: personSpace._id,
|
||||
message: github.string.AuthenticationRevokedGithub,
|
||||
props: {
|
||||
login: update.login
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
// const dPerson = (await client.findOne(contact.class.Person, { _id: dummyPerson })) as Person
|
||||
// if (person !== undefined && dPerson !== undefined) {
|
||||
// const personSpace = await client.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
// if (personSpace !== undefined) {
|
||||
// await createNotification(client, dPerson, {
|
||||
// user: githubAccount._id,
|
||||
// space: personSpace._id,
|
||||
// message: github.string.AuthenticatedWithGithubEmployee,
|
||||
// props: {
|
||||
// login: update.login
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// const personSpace = await client.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
// if (personSpace !== undefined) {
|
||||
// await createNotification(client, person, {
|
||||
// user: account._id,
|
||||
// space: personSpace._id,
|
||||
// message: github.string.AuthenticationRevokedGithub,
|
||||
// props: {
|
||||
// login: update.login
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (dta !== undefined && personAuths.length === 1) {
|
||||
try {
|
||||
await syncUser(this.ctx, dta, personAuths[0], client, payload.accountId)
|
||||
} catch (err: any) {
|
||||
if (err.response?.data?.message === 'Bad credentials') {
|
||||
await this.revokeUserAuth(dta)
|
||||
} else {
|
||||
this.ctx.error(`Failed to sync user ${dta._id}`, { error: errorToObj(err) })
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (shouldClose) {
|
||||
await platformClient?.close()
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
}
|
||||
// if (dta !== undefined && personAuths.length === 1) {
|
||||
// try {
|
||||
// await syncUser(this.ctx, dta, personAuths[0], client, payload.accountId)
|
||||
// } catch (err: any) {
|
||||
// if (err.response?.data?.message === 'Bad credentials') {
|
||||
// await this.revokeUserAuth(dta)
|
||||
// } else {
|
||||
// this.ctx.error(`Failed to sync user ${dta._id}`, { error: errorToObj(err) })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } finally {
|
||||
// if (shouldClose) {
|
||||
// await platformClient?.close()
|
||||
// }
|
||||
// }
|
||||
// } catch (err: any) {
|
||||
// Analytics.handleError(err)
|
||||
// }
|
||||
}
|
||||
|
||||
async checkRefreshToken (auth: GithubUserRecord, force: boolean = false): Promise<void> {
|
||||
@@ -581,7 +583,7 @@ export class PlatformWorker {
|
||||
return await this.userManager.getAccount(login)
|
||||
}
|
||||
|
||||
async getAccountByRef (workspace: string, ref: Ref<Account>): Promise<GithubUserRecord | undefined> {
|
||||
async getAccountByRef (workspace: string, ref: PersonId): Promise<GithubUserRecord | undefined> {
|
||||
return await this.userManager.getAccountByRef(workspace, ref)
|
||||
}
|
||||
|
||||
@@ -665,7 +667,7 @@ export class PlatformWorker {
|
||||
integeration.enabled = enabled
|
||||
}
|
||||
|
||||
await worker.syncUserData(this.ctx, await this.getUsers(worker.workspace.name))
|
||||
await worker.syncUserData(this.ctx, await this.getUsers(worker.workspace.uuid))
|
||||
await worker.reloadRepositories(install.id)
|
||||
|
||||
worker.triggerUpdate()
|
||||
@@ -706,21 +708,21 @@ export class PlatformWorker {
|
||||
this.triggerCheckWorkspaces()
|
||||
}
|
||||
|
||||
async getWorkspaces (): Promise<string[]> {
|
||||
const workspaces = new Set(this.integrations.map((it) => it.workspace))
|
||||
async getWorkspaces (): Promise<WorkspaceUuid[]> {
|
||||
const workspaces = new Set(this.integrations.map((it) => it.workspace as WorkspaceUuid)) // TODO: FIXME
|
||||
|
||||
return Array.from(workspaces)
|
||||
}
|
||||
|
||||
async checkWorkspaceIsActive (token: string, workspace: string): Promise<ClientWorkspaceInfo | undefined> {
|
||||
let workspaceInfo: ClientWorkspaceInfo | undefined
|
||||
async checkWorkspaceIsActive (token: string, workspace: string): Promise<WorkspaceInfoWithStatus | undefined> {
|
||||
let workspaceInfo: WorkspaceInfoWithStatus | undefined
|
||||
try {
|
||||
workspaceInfo = await getWorkspaceInfo(token)
|
||||
workspaceInfo = await getAccountClient(token).getWorkspaceInfo(true)
|
||||
} catch (err: any) {
|
||||
this.ctx.error('Workspace not found:', { workspace })
|
||||
return
|
||||
}
|
||||
if (workspaceInfo?.workspace === undefined) {
|
||||
if (workspaceInfo?.uuid === undefined) {
|
||||
this.ctx.error('No workspace exists for workspaceId', { workspace })
|
||||
return
|
||||
}
|
||||
@@ -728,16 +730,18 @@ export class PlatformWorker {
|
||||
this.ctx.warn('Workspace is in maitenance, skipping for now.', { workspace })
|
||||
return
|
||||
}
|
||||
if (workspaceInfo?.disabled === true) {
|
||||
if (workspaceInfo?.isDisabled === true) {
|
||||
this.ctx.warn('Workspace is disabled', { workspace })
|
||||
return
|
||||
}
|
||||
const lastVisit = (Date.now() - workspaceInfo.lastVisit) / (3600 * 24 * 1000) // In days
|
||||
|
||||
const lastVisit = (Date.now() - (workspaceInfo.lastVisit ?? 0)) / (3600 * 24 * 1000) // In days
|
||||
|
||||
if (config.WorkspaceInactivityInterval > 0 && lastVisit > config.WorkspaceInactivityInterval) {
|
||||
this.ctx.warn('Workspace is inactive for too long, skipping for now.', { workspace })
|
||||
return
|
||||
}
|
||||
|
||||
return workspaceInfo
|
||||
}
|
||||
|
||||
@@ -747,7 +751,7 @@ export class PlatformWorker {
|
||||
})
|
||||
let workspaces = await this.getWorkspaces()
|
||||
if (process.env.GITHUB_USE_WS !== undefined) {
|
||||
workspaces = [process.env.GITHUB_USE_WS]
|
||||
workspaces = [process.env.GITHUB_USE_WS as WorkspaceUuid]
|
||||
}
|
||||
const toDelete = new Set<string>(this.clients.keys())
|
||||
|
||||
@@ -774,13 +778,7 @@ export class PlatformWorker {
|
||||
continue
|
||||
}
|
||||
await rateLimiter.add(async () => {
|
||||
const token = generateToken(
|
||||
systemAccountEmail,
|
||||
{
|
||||
name: workspace
|
||||
},
|
||||
{ mode: 'github' }
|
||||
)
|
||||
const token = generateToken(systemAccountUuid, workspace, { service: 'github', mode: 'github' })
|
||||
const workspaceInfo = await this.checkWorkspaceIsActive(token, workspace)
|
||||
if (workspaceInfo === undefined) {
|
||||
errors++
|
||||
@@ -788,12 +786,12 @@ export class PlatformWorker {
|
||||
}
|
||||
try {
|
||||
const branding = Object.values(this.brandingMap).find((b) => b.key === workspaceInfo?.branding) ?? null
|
||||
const workerCtx = this.ctx.newChild('worker', { workspace: workspaceInfo.workspace }, {})
|
||||
const workerCtx = this.ctx.newChild('worker', { workspace: workspaceInfo.uuid }, {})
|
||||
|
||||
connecting.set(workspaceInfo.workspace, Date.now())
|
||||
connecting.set(workspaceInfo.uuid, Date.now())
|
||||
workerCtx.info('************************* Register worker ************************* ', {
|
||||
workspaceId: workspaceInfo.workspaceId,
|
||||
workspace: workspaceInfo.workspace,
|
||||
workspaceId: workspaceInfo.uuid,
|
||||
workspaceUrl: workspaceInfo.url,
|
||||
index: widx,
|
||||
total: workspaces.length
|
||||
})
|
||||
@@ -804,9 +802,9 @@ export class PlatformWorker {
|
||||
workerCtx,
|
||||
this.installations,
|
||||
{
|
||||
name: workspace,
|
||||
workspaceUrl: workspaceInfo.workspace,
|
||||
workspaceName: workspace
|
||||
dataId: workspaceInfo.dataId,
|
||||
url: workspaceInfo.url,
|
||||
uuid: workspaceInfo.uuid
|
||||
},
|
||||
branding,
|
||||
this.app,
|
||||
@@ -841,8 +839,8 @@ export class PlatformWorker {
|
||||
if (worker !== undefined) {
|
||||
initialized = true
|
||||
workerCtx.info('************************* Register worker Done ************************* ', {
|
||||
workspaceId: workspaceInfo.workspaceId,
|
||||
workspace: workspaceInfo.workspace,
|
||||
workspaceId: workspaceInfo.uuid,
|
||||
workspaceUrl: workspaceInfo.url,
|
||||
index: widx,
|
||||
total: workspaces.length
|
||||
})
|
||||
@@ -852,8 +850,8 @@ export class PlatformWorker {
|
||||
workerCtx.info(
|
||||
'************************* Failed Register worker, timeout or integrations removed *************************',
|
||||
{
|
||||
workspaceId: workspaceInfo.workspaceId,
|
||||
workspace: workspaceInfo.workspace,
|
||||
workspaceId: workspaceInfo.uuid,
|
||||
workspaceUrl: workspaceInfo.url,
|
||||
index: widx,
|
||||
total: workspaces.length
|
||||
}
|
||||
@@ -866,7 +864,7 @@ export class PlatformWorker {
|
||||
console.error(e)
|
||||
errors++
|
||||
} finally {
|
||||
connecting.delete(workspaceInfo.workspace)
|
||||
connecting.delete(workspaceInfo.uuid)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1091,7 +1089,7 @@ export class PlatformWorker {
|
||||
payload.installation.html_url
|
||||
)
|
||||
const doSyncUsers = async (worker: GithubWorker): Promise<void> => {
|
||||
const users = await this.getUsers(worker.workspace.name)
|
||||
const users = await this.getUsers(worker.workspace.uuid)
|
||||
await worker.syncUserData(this.ctx, users)
|
||||
}
|
||||
catchEventError(doSyncUsers(worker), payload.action, name, id, payload.installation.html_url)
|
||||
|
||||
@@ -9,7 +9,7 @@ import cors from 'cors'
|
||||
import express from 'express'
|
||||
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { Account, BrandingMap, MeasureContext, Ref } from '@hcengineering/core'
|
||||
import { PersonId, BrandingMap, MeasureContext } from '@hcengineering/core'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import serverClient from '@hcengineering/server-client'
|
||||
import serverCore from '@hcengineering/server-core'
|
||||
@@ -73,35 +73,37 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
app.post('/api/v1/installation', async (req, res) => {
|
||||
const payloadData: {
|
||||
installationId: number
|
||||
accountId: Ref<Account>
|
||||
token: string
|
||||
} = req.body
|
||||
try {
|
||||
const decodedToken = decodeToken(payloadData.token)
|
||||
ctx.info('/api/v1/installation', {
|
||||
email: decodedToken.email,
|
||||
workspaceName: decodedToken.workspace.name,
|
||||
body: req.body
|
||||
})
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// const payloadData: {
|
||||
// installationId: number
|
||||
// accountId: PersonId
|
||||
// token: string
|
||||
// } = req.body
|
||||
// try {
|
||||
// const decodedToken = decodeToken(payloadData.token)
|
||||
// ctx.info('/api/v1/installation', {
|
||||
// email: decodedToken.email,
|
||||
// workspaceName: decodedToken.workspace,
|
||||
// body: req.body
|
||||
// })
|
||||
|
||||
await ctx.with('map-installation', {}, (ctx) =>
|
||||
worker.mapInstallation(ctx, decodedToken.workspace.name, payloadData.installationId, payloadData.accountId)
|
||||
)
|
||||
res.status(200)
|
||||
res.json({})
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
const tok = decodeToken(payloadData.token, false)
|
||||
ctx.error('failed to map-installation', {
|
||||
workspace: tok.workspace?.name,
|
||||
installationid: payloadData.installationId,
|
||||
email: tok?.email
|
||||
})
|
||||
res.status(401)
|
||||
res.json({ error: err.message })
|
||||
}
|
||||
// await ctx.with('map-installation', {}, (ctx) =>
|
||||
// worker.mapInstallation(ctx, decodedToken.workspace, payloadData.installationId, payloadData.accountId)
|
||||
// )
|
||||
// res.status(200)
|
||||
// res.json({})
|
||||
// } catch (err: any) {
|
||||
// Analytics.handleError(err)
|
||||
// const tok = decodeToken(payloadData.token, false)
|
||||
// ctx.error('failed to map-installation', {
|
||||
// workspace: tok.workspace,
|
||||
// installationid: payloadData.installationId,
|
||||
// email: tok?.email
|
||||
// })
|
||||
// res.status(401)
|
||||
// res.json({ error: err.message })
|
||||
// }
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
@@ -110,26 +112,26 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
const payloadData: {
|
||||
code: string
|
||||
state: string
|
||||
accountId: Ref<Account>
|
||||
accountId: PersonId
|
||||
token: string
|
||||
} = req.body
|
||||
|
||||
const decodedData: {
|
||||
accountId: Ref<Account>
|
||||
accountId: PersonId
|
||||
token: string
|
||||
op: string
|
||||
} = JSON.parse(atob(payloadData.state))
|
||||
|
||||
const decodedToken = decodeToken(decodedData.token)
|
||||
ctx.info('request github access-token', {
|
||||
workspace: decodedToken.workspace.name,
|
||||
workspace: decodedToken.workspace,
|
||||
accountId: payloadData.accountId,
|
||||
code: payloadData.code,
|
||||
state: payloadData.state
|
||||
})
|
||||
await ctx.with('request-github-access-token', {}, async (ctx) => {
|
||||
await worker.requestGithubAccessToken({
|
||||
workspace: decodedToken.workspace.name,
|
||||
workspace: decodedToken.workspace,
|
||||
accountId: payloadData.accountId,
|
||||
code: payloadData.code,
|
||||
state: payloadData.state
|
||||
@@ -146,33 +148,35 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
app.post('/api/v1/installation-remove', async (req, res) => {
|
||||
try {
|
||||
const payloadData: {
|
||||
installationId: number
|
||||
token: string
|
||||
} = req.body
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// try {
|
||||
// const payloadData: {
|
||||
// installationId: number
|
||||
// token: string
|
||||
// } = req.body
|
||||
|
||||
const decodedToken = decodeToken(payloadData.token)
|
||||
ctx.info('/api/v1/installation-remove', {
|
||||
email: decodedToken.email,
|
||||
workspaceName: decodedToken.workspace.name,
|
||||
body: req.body
|
||||
})
|
||||
// const decodedToken = decodeToken(payloadData.token)
|
||||
// ctx.info('/api/v1/installation-remove', {
|
||||
// email: decodedToken.email,
|
||||
// workspaceName: decodedToken.workspace,
|
||||
// body: req.body
|
||||
// })
|
||||
|
||||
ctx.info('remove-installation', {
|
||||
workspace: decodedToken.workspace.name,
|
||||
installationId: payloadData.installationId
|
||||
})
|
||||
await ctx.with('remove-installation', {}, (ctx) =>
|
||||
worker.removeInstallation(ctx, decodedToken.workspace.name, payloadData.installationId)
|
||||
)
|
||||
res.status(200)
|
||||
res.json({})
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
res.status(401)
|
||||
res.json({ error: err.message })
|
||||
}
|
||||
// ctx.info('remove-installation', {
|
||||
// workspace: decodedToken.workspace,
|
||||
// installationId: payloadData.installationId
|
||||
// })
|
||||
// await ctx.with('remove-installation', {}, (ctx) =>
|
||||
// worker.removeInstallation(ctx, decodedToken.workspace, payloadData.installationId)
|
||||
// )
|
||||
// res.status(200)
|
||||
// res.json({})
|
||||
// } catch (err: any) {
|
||||
// Analytics.handleError(err)
|
||||
// res.status(401)
|
||||
// res.json({ error: err.message })
|
||||
// }
|
||||
})
|
||||
|
||||
const server = app.listen(port, () => {
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
import chunter, { ChatMessage } from '@hcengineering/chunter'
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AttachedData,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
@@ -61,7 +60,7 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
this.ctx.info('comments:handleEvent', {
|
||||
action: event.action,
|
||||
login: event.sender.login,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
|
||||
if (event.sender.type === 'Bot') {
|
||||
@@ -134,8 +133,8 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
return true
|
||||
}
|
||||
|
||||
async deleteGithubDocument (container: ContainerFocus, account: Ref<Account>, id: string): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
async deleteGithubDocument (container: ContainerFocus, account: PersonId, id: string): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account)) ?? container.container.octokit
|
||||
|
||||
const q = `mutation deleteComment($commentID: ID!) {
|
||||
deleteIssueComment(
|
||||
@@ -160,7 +159,7 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
if (repo === undefined) {
|
||||
this.ctx.info('No project for repository', {
|
||||
repository: event.repository,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -305,7 +304,7 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
container: ContainerFocus,
|
||||
parent: DocSyncInfo,
|
||||
comment: CommentExternalData,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const repository = await this.provider.getRepositoryById(info.repository)
|
||||
if (repository === undefined) {
|
||||
@@ -337,8 +336,7 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
|
||||
if (Object.keys(platformUpdate).length > 0) {
|
||||
// Check and update body with external
|
||||
const okit =
|
||||
(await this.provider.getOctokit(existing.modifiedBy as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(existing.modifiedBy)) ?? container.container.octokit
|
||||
await okit?.rest.issues.updateComment({
|
||||
owner: repository.owner?.login as string,
|
||||
repo: repository.name,
|
||||
@@ -364,7 +362,7 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
messageData: MessageData,
|
||||
parent: DocSyncInfo,
|
||||
comment: CommentExternalData,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const _id: Ref<ChatMessage> = info._id as unknown as Ref<ChatMessage>
|
||||
const value: AttachedData<ChatMessage> = {
|
||||
@@ -407,8 +405,7 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
return {}
|
||||
}
|
||||
const chatMessage = existing as ChatMessage
|
||||
const okit =
|
||||
(await this.provider.getOctokit(chatMessage.modifiedBy as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(chatMessage.modifiedBy)) ?? container.container.octokit
|
||||
|
||||
// No external version yet, create it.
|
||||
try {
|
||||
@@ -508,7 +505,7 @@ export class CommentSyncManager implements DocSyncManager {
|
||||
comments: comments.length,
|
||||
used: data.headers['x-ratelimit-used'],
|
||||
limit: data.headers['x-ratelimit-limit'],
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
await this.syncComments(repo, comments, derivedClient)
|
||||
this.provider.sync()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
|
||||
import { Branding, generateId, TxOperations, WorkspaceIdWithUrl } from '@hcengineering/core'
|
||||
import { Branding, generateUuid, PersonUuid, TxOperations, WorkspaceIds, WorkspaceUuid } from '@hcengineering/core'
|
||||
import { MarkupMarkType, MarkupNode, MarkupNodeType, traverseMarkupNode } from '@hcengineering/text'
|
||||
import { getPublicLink } from '@hcengineering/server-guest-resources'
|
||||
import { Task } from '@hcengineering/task'
|
||||
@@ -49,13 +49,13 @@ export async function appendGuestLink (
|
||||
client: TxOperations,
|
||||
doc: Task,
|
||||
markdown: MarkupNode,
|
||||
workspace: WorkspaceIdWithUrl,
|
||||
workspace: WorkspaceIds,
|
||||
branding: Branding | null
|
||||
): Promise<void> {
|
||||
const publicLink = await getPublicLink(doc, client, workspace, false, branding)
|
||||
await stripGuestLink(markdown)
|
||||
appendGuestLinkToModel(markdown, publicLink, doc.identifier)
|
||||
appendGuestLinkToImage(markdown, workspace)
|
||||
appendGuestLinkToImage(markdown, workspace.uuid)
|
||||
}
|
||||
|
||||
export function appendGuestLinkToModel (markdown: MarkupNode, publicLink: string, identifier: string): void {
|
||||
@@ -89,14 +89,14 @@ function findImageTags (node: MarkupNode): MarkupNode[] {
|
||||
return []
|
||||
}
|
||||
|
||||
export function appendGuestLinkToImage (markdown: MarkupNode, workspace: WorkspaceIdWithUrl): void {
|
||||
export function appendGuestLinkToImage (markdown: MarkupNode, workspace: WorkspaceUuid): void {
|
||||
const imageTags: MarkupNode[] = markdown.content?.flatMap(findImageTags) ?? []
|
||||
|
||||
if (imageTags.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const id = generateId()
|
||||
const id = generateUuid() as PersonUuid
|
||||
const token = generateToken(id, workspace, { linkId: id, guest: 'true' })
|
||||
|
||||
for (const imageTag of imageTags) {
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
TODO:
|
||||
* Add since to synchronization
|
||||
*/
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import activity from '@hcengineering/activity'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { CollaboratorClient } from '@hcengineering/collaborator-client'
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AttachedDoc,
|
||||
Class,
|
||||
Doc,
|
||||
@@ -138,17 +138,19 @@ export abstract class IssueSyncManagerBase {
|
||||
this.provider = provider
|
||||
}
|
||||
|
||||
async getAssignees (issue: IssueExternalData): Promise<PersonAccount[]> {
|
||||
async getAssignees (issue: IssueExternalData): Promise<any[]> {
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// Find Assignees and reviewers
|
||||
const assignees: PersonAccount[] = []
|
||||
// const assignees: PersonAccount[] = []
|
||||
|
||||
for (const o of issue.assignees.nodes) {
|
||||
const acc = await this.provider.getAccount(o)
|
||||
if (acc !== undefined) {
|
||||
assignees.push(acc)
|
||||
}
|
||||
}
|
||||
return assignees
|
||||
// for (const o of issue.assignees.nodes) {
|
||||
// const acc = await this.provider.getAccount(o)
|
||||
// if (acc !== undefined) {
|
||||
// assignees.push(acc)
|
||||
// }
|
||||
// }
|
||||
// return assignees
|
||||
}
|
||||
|
||||
async processProjectV2Event (
|
||||
@@ -227,7 +229,7 @@ export abstract class IssueSyncManagerBase {
|
||||
return
|
||||
}
|
||||
|
||||
this.ctx.info('event for issue', { url: syncData.url, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('event for issue', { url: syncData.url, workspace: this.provider.getWorkspaceId() })
|
||||
const externalData = syncData.external as IssueExternalData
|
||||
// We need to replace field values we retrieved
|
||||
target.prjData = externalData.projectItems.nodes.find(
|
||||
@@ -255,7 +257,7 @@ export abstract class IssueSyncManagerBase {
|
||||
})
|
||||
|
||||
if (event.changes.field_value === undefined) {
|
||||
this.ctx.info('No changes for change event', { event, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('No changes for change event', { event, workspace: this.provider.getWorkspaceId() })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -338,7 +340,7 @@ export abstract class IssueSyncManagerBase {
|
||||
external: IssueExternalData,
|
||||
derivedClient: TxOperations,
|
||||
update: IssueUpdate,
|
||||
account: Ref<Account>,
|
||||
account: PersonId,
|
||||
prj: GithubProject,
|
||||
needSync: boolean,
|
||||
syncData?: DocSyncInfo,
|
||||
@@ -639,7 +641,7 @@ export abstract class IssueSyncManagerBase {
|
||||
this.ctx.error('error during field update', {
|
||||
error: err,
|
||||
response,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
errors.push({ error: err, response })
|
||||
}
|
||||
@@ -682,10 +684,10 @@ export abstract class IssueSyncManagerBase {
|
||||
container: ContainerFocus,
|
||||
issueExternal: IssueExternalData,
|
||||
okit: Octokit,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<boolean>
|
||||
|
||||
abstract afterSync (existing: Issue, account: Ref<Account>, issueExternal: any, info: DocSyncInfo): Promise<void>
|
||||
abstract afterSync (existing: Issue, account: PersonId, issueExternal: any, info: DocSyncInfo): Promise<void>
|
||||
|
||||
async handleDiffUpdate (
|
||||
target: IssueSyncTarget,
|
||||
@@ -694,265 +696,267 @@ export abstract class IssueSyncManagerBase {
|
||||
issueData: GithubIssueData,
|
||||
container: ContainerFocus,
|
||||
issueExternal: IssueExternalData,
|
||||
account: Ref<Account>,
|
||||
accountGH: Ref<Account>,
|
||||
account: PersonId,
|
||||
accountGH: PersonId,
|
||||
syncToProject: boolean
|
||||
): Promise<DocumentUpdate<DocSyncInfo>> {
|
||||
let needUpdate = false
|
||||
if (!this.client.getHierarchy().hasMixin(existing, github.mixin.GithubIssue)) {
|
||||
await this.ctx.withLog(
|
||||
'create mixin issue: GithubIssue',
|
||||
{},
|
||||
async () => {
|
||||
await this.client.createMixin<Issue, GithubIssueP>(
|
||||
existing._id as Ref<GithubIssueP>,
|
||||
existing._class,
|
||||
existing.space,
|
||||
github.mixin.GithubIssue,
|
||||
{
|
||||
githubNumber: issueExternal.number,
|
||||
url: issueExternal.url,
|
||||
repository: info.repository as Ref<GithubIntegrationRepository>
|
||||
}
|
||||
)
|
||||
await this.notifyConnected(container, info, existing, issueExternal)
|
||||
},
|
||||
{ identifier: existing.identifier, url: issueExternal.url }
|
||||
)
|
||||
// Re iterate to have existing value with mixin inside.
|
||||
needUpdate = true
|
||||
} else {
|
||||
const ghIssue = this.client.getHierarchy().as(existing, github.mixin.GithubIssue)
|
||||
await this.client.diffUpdate(ghIssue, {
|
||||
githubNumber: issueExternal.number,
|
||||
url: issueExternal.url,
|
||||
repository: info.repository as Ref<GithubIntegrationRepository>
|
||||
})
|
||||
if (ghIssue.url !== issueExternal.url) {
|
||||
await this.notifyConnected(container, info, existing, issueExternal)
|
||||
}
|
||||
}
|
||||
if (!this.client.getHierarchy().hasMixin(existing, container.project.mixinClass)) {
|
||||
await this.ctx.withLog(
|
||||
'create mixin issue',
|
||||
{},
|
||||
() =>
|
||||
this.client.createMixin<Issue, Issue>(
|
||||
existing._id as Ref<GithubIssueP>,
|
||||
existing._class,
|
||||
existing.space,
|
||||
container.project.mixinClass,
|
||||
{}
|
||||
),
|
||||
{ identifier: existing.identifier, url: issueExternal.url }
|
||||
)
|
||||
// Re iterate to have existing value with mixin inside.
|
||||
needUpdate = true
|
||||
}
|
||||
if (needUpdate) {
|
||||
return { needSync: '' }
|
||||
}
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// let needUpdate = false
|
||||
// if (!this.client.getHierarchy().hasMixin(existing, github.mixin.GithubIssue)) {
|
||||
// await this.ctx.withLog(
|
||||
// 'create mixin issue: GithubIssue',
|
||||
// {},
|
||||
// async () => {
|
||||
// await this.client.createMixin<Issue, GithubIssueP>(
|
||||
// existing._id as Ref<GithubIssueP>,
|
||||
// existing._class,
|
||||
// existing.space,
|
||||
// github.mixin.GithubIssue,
|
||||
// {
|
||||
// githubNumber: issueExternal.number,
|
||||
// url: issueExternal.url,
|
||||
// repository: info.repository as Ref<GithubIntegrationRepository>
|
||||
// }
|
||||
// )
|
||||
// await this.notifyConnected(container, info, existing, issueExternal)
|
||||
// },
|
||||
// { identifier: existing.identifier, url: issueExternal.url }
|
||||
// )
|
||||
// // Re iterate to have existing value with mixin inside.
|
||||
// needUpdate = true
|
||||
// } else {
|
||||
// const ghIssue = this.client.getHierarchy().as(existing, github.mixin.GithubIssue)
|
||||
// await this.client.diffUpdate(ghIssue, {
|
||||
// githubNumber: issueExternal.number,
|
||||
// url: issueExternal.url,
|
||||
// repository: info.repository as Ref<GithubIntegrationRepository>
|
||||
// })
|
||||
// if (ghIssue.url !== issueExternal.url) {
|
||||
// await this.notifyConnected(container, info, existing, issueExternal)
|
||||
// }
|
||||
// }
|
||||
// if (!this.client.getHierarchy().hasMixin(existing, container.project.mixinClass)) {
|
||||
// await this.ctx.withLog(
|
||||
// 'create mixin issue',
|
||||
// {},
|
||||
// () =>
|
||||
// this.client.createMixin<Issue, Issue>(
|
||||
// existing._id as Ref<GithubIssueP>,
|
||||
// existing._class,
|
||||
// existing.space,
|
||||
// container.project.mixinClass,
|
||||
// {}
|
||||
// ),
|
||||
// { identifier: existing.identifier, url: issueExternal.url }
|
||||
// )
|
||||
// // Re iterate to have existing value with mixin inside.
|
||||
// needUpdate = true
|
||||
// }
|
||||
// if (needUpdate) {
|
||||
// return { needSync: '' }
|
||||
// }
|
||||
|
||||
const existingIssue = this.client.getHierarchy().as(existing, container.project.mixinClass)
|
||||
const previousData: GithubIssueData = info.current ?? ({} as unknown as GithubIssueData)
|
||||
const type = await this.provider.getTaskTypeOf(container.project.type, existing._class)
|
||||
const stst = await this.provider.getStatuses(type?._id)
|
||||
// const existingIssue = this.client.getHierarchy().as(existing, container.project.mixinClass)
|
||||
// const previousData: GithubIssueData = info.current ?? ({} as unknown as GithubIssueData)
|
||||
// const type = await this.provider.getTaskTypeOf(container.project.type, existing._class)
|
||||
// const stst = await this.provider.getStatuses(type?._id)
|
||||
|
||||
const update = collectUpdate<Issue>(previousData, issueData, Object.keys(issueData))
|
||||
// const update = collectUpdate<Issue>(previousData, issueData, Object.keys(issueData))
|
||||
|
||||
const allAttributes = this.client.getHierarchy().getAllAttributes(container.project.mixinClass)
|
||||
const platformUpdate = collectUpdate<Issue>(previousData, existingIssue, Array.from(allAttributes.keys()))
|
||||
// const allAttributes = this.client.getHierarchy().getAllAttributes(container.project.mixinClass)
|
||||
// const platformUpdate = collectUpdate<Issue>(previousData, existingIssue, Array.from(allAttributes.keys()))
|
||||
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
// const okit = (await this.provider.getOctokit(account as PersonId)) ?? container.container.octokit
|
||||
|
||||
// Remove current same values from update
|
||||
for (const [k, v] of Object.entries(update)) {
|
||||
if ((existingIssue as any)[k] === v) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete (update as any)[k]
|
||||
}
|
||||
}
|
||||
// // Remove current same values from update
|
||||
// for (const [k, v] of Object.entries(update)) {
|
||||
// if ((existingIssue as any)[k] === v) {
|
||||
// // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
// delete (update as any)[k]
|
||||
// }
|
||||
// }
|
||||
|
||||
if (update.description !== undefined) {
|
||||
if (update.description === existingIssue.description) {
|
||||
delete update.description
|
||||
}
|
||||
}
|
||||
// if (update.description !== undefined) {
|
||||
// if (update.description === existingIssue.description) {
|
||||
// delete update.description
|
||||
// }
|
||||
// }
|
||||
|
||||
for (const [k, v] of Object.entries(update)) {
|
||||
let pv = (platformUpdate as any)[k]
|
||||
// for (const [k, v] of Object.entries(update)) {
|
||||
// let pv = (platformUpdate as any)[k]
|
||||
|
||||
if (k === 'description' && pv != null) {
|
||||
const mdown = await this.provider.getMarkdown(pv)
|
||||
pv = await this.provider.getMarkup(container.container, mdown, this.stripGuestLink)
|
||||
}
|
||||
if (pv != null && pv !== v) {
|
||||
// We have conflict of values, assume platform is more proper one.
|
||||
this.ctx.error('conflict', { id: existing.identifier, k })
|
||||
// Assume platform change is more important in case of conflict values.
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete (update as any)[k]
|
||||
continue
|
||||
}
|
||||
}
|
||||
// if (k === 'description' && pv != null) {
|
||||
// const mdown = await this.provider.getMarkdown(pv)
|
||||
// pv = await this.provider.getMarkup(container.container, mdown, this.stripGuestLink)
|
||||
// }
|
||||
// if (pv != null && pv !== v) {
|
||||
// // We have conflict of values, assume platform is more proper one.
|
||||
// this.ctx.error('conflict', { id: existing.identifier, k })
|
||||
// // Assume platform change is more important in case of conflict values.
|
||||
// // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
// delete (update as any)[k]
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
await this.fillBackChanges(update, existingIssue, issueExternal)
|
||||
// await this.fillBackChanges(update, existingIssue, issueExternal)
|
||||
|
||||
let needExternalSync = false
|
||||
// let needExternalSync = false
|
||||
|
||||
if (container !== undefined && okit !== undefined) {
|
||||
// Check and update issue fields.
|
||||
needExternalSync = await this.performIssueFieldsUpdate(
|
||||
info,
|
||||
existing,
|
||||
platformUpdate,
|
||||
issueData,
|
||||
container,
|
||||
issueExternal,
|
||||
okit,
|
||||
account
|
||||
)
|
||||
// if (container !== undefined && okit !== undefined) {
|
||||
// // Check and update issue fields.
|
||||
// needExternalSync = await this.performIssueFieldsUpdate(
|
||||
// info,
|
||||
// existing,
|
||||
// platformUpdate,
|
||||
// issueData,
|
||||
// container,
|
||||
// issueExternal,
|
||||
// okit,
|
||||
// account
|
||||
// )
|
||||
|
||||
const fieldsUpdate: { id: string, value: any, dataType: GithubDataType }[] = []
|
||||
// const fieldsUpdate: { id: string, value: any, dataType: GithubDataType }[] = []
|
||||
|
||||
// Collect field update.
|
||||
for (const [k, v] of Object.entries(platformUpdate)) {
|
||||
const mapping = target.mappings.filter((it) => it != null).find((it) => it.name === k)
|
||||
if (mapping === undefined) {
|
||||
continue
|
||||
}
|
||||
const attr = this.client.getHierarchy().getAttribute(mapping._class, mapping.name)
|
||||
// // Collect field update.
|
||||
// for (const [k, v] of Object.entries(platformUpdate)) {
|
||||
// const mapping = target.mappings.filter((it) => it != null).find((it) => it.name === k)
|
||||
// if (mapping === undefined) {
|
||||
// continue
|
||||
// }
|
||||
// const attr = this.client.getHierarchy().getAttribute(mapping._class, mapping.name)
|
||||
|
||||
if (attr.name === 'status') {
|
||||
// Handle status field
|
||||
const status = stst.find((it) => it._id === v) as Status
|
||||
const optionId = this.findOptionId(container, mapping.githubId, status.name, target)
|
||||
if (optionId !== undefined) {
|
||||
fieldsUpdate.push({
|
||||
id: mapping.githubId,
|
||||
dataType: 'SINGLE_SELECT',
|
||||
value: optionId
|
||||
})
|
||||
this.ctx.info(' => prepare issue status update', {
|
||||
url: issueExternal.url,
|
||||
name: status.name,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (attr.name === 'priority') {
|
||||
const values: Record<IssuePriority, string> = {
|
||||
[IssuePriority.NoPriority]: '',
|
||||
[IssuePriority.High]: 'High',
|
||||
[IssuePriority.Medium]: 'Medium',
|
||||
[IssuePriority.Low]: 'Low',
|
||||
[IssuePriority.Urgent]: 'Urgent'
|
||||
}
|
||||
// Handle priority field TODO: Add clear of field
|
||||
const priorityName = values[v as IssuePriority]
|
||||
const optionId = this.findOptionId(container, mapping.githubId, priorityName, target)
|
||||
if (optionId !== undefined) {
|
||||
fieldsUpdate.push({
|
||||
id: mapping.githubId,
|
||||
dataType: 'SINGLE_SELECT',
|
||||
value: optionId
|
||||
})
|
||||
this.ctx.info(' => prepare issue priority update', {
|
||||
url: issueExternal.url,
|
||||
priority: priorityName,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
// if (attr.name === 'status') {
|
||||
// // Handle status field
|
||||
// const status = stst.find((it) => it._id === v) as Status
|
||||
// const optionId = this.findOptionId(container, mapping.githubId, status.name, target)
|
||||
// if (optionId !== undefined) {
|
||||
// fieldsUpdate.push({
|
||||
// id: mapping.githubId,
|
||||
// dataType: 'SINGLE_SELECT',
|
||||
// value: optionId
|
||||
// })
|
||||
// this.ctx.info(' => prepare issue status update', {
|
||||
// url: issueExternal.url,
|
||||
// name: status.name,
|
||||
// workspace: this.provider.getWorkspaceId()
|
||||
// })
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
// if (attr.name === 'priority') {
|
||||
// const values: Record<IssuePriority, string> = {
|
||||
// [IssuePriority.NoPriority]: '',
|
||||
// [IssuePriority.High]: 'High',
|
||||
// [IssuePriority.Medium]: 'Medium',
|
||||
// [IssuePriority.Low]: 'Low',
|
||||
// [IssuePriority.Urgent]: 'Urgent'
|
||||
// }
|
||||
// // Handle priority field TODO: Add clear of field
|
||||
// const priorityName = values[v as IssuePriority]
|
||||
// const optionId = this.findOptionId(container, mapping.githubId, priorityName, target)
|
||||
// if (optionId !== undefined) {
|
||||
// fieldsUpdate.push({
|
||||
// id: mapping.githubId,
|
||||
// dataType: 'SINGLE_SELECT',
|
||||
// value: optionId
|
||||
// })
|
||||
// this.ctx.info(' => prepare issue priority update', {
|
||||
// url: issueExternal.url,
|
||||
// priority: priorityName,
|
||||
// workspace: this.provider.getWorkspaceId()
|
||||
// })
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
const dataType = getType(attr)
|
||||
if (dataType === 'SINGLE_SELECT') {
|
||||
// Handle status field
|
||||
const optionId = this.findOptionId(container, mapping.githubId, v, target)
|
||||
if (optionId !== undefined) {
|
||||
fieldsUpdate.push({
|
||||
id: mapping.githubId,
|
||||
dataType: 'SINGLE_SELECT',
|
||||
value: optionId
|
||||
})
|
||||
this.ctx.info(` => prepare issue field ${attr.label} update`, {
|
||||
url: issueExternal.url,
|
||||
value: v,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
// const dataType = getType(attr)
|
||||
// if (dataType === 'SINGLE_SELECT') {
|
||||
// // Handle status field
|
||||
// const optionId = this.findOptionId(container, mapping.githubId, v, target)
|
||||
// if (optionId !== undefined) {
|
||||
// fieldsUpdate.push({
|
||||
// id: mapping.githubId,
|
||||
// dataType: 'SINGLE_SELECT',
|
||||
// value: optionId
|
||||
// })
|
||||
// this.ctx.info(` => prepare issue field ${attr.label} update`, {
|
||||
// url: issueExternal.url,
|
||||
// value: v,
|
||||
// workspace: this.provider.getWorkspaceId()
|
||||
// })
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
if (dataType === undefined) {
|
||||
continue
|
||||
}
|
||||
fieldsUpdate.push({
|
||||
id: mapping.githubId,
|
||||
dataType,
|
||||
value: v
|
||||
})
|
||||
this.ctx.info(`=> prepare issue field ${attr.label} update`, {
|
||||
url: issueExternal.url,
|
||||
value: v,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
})
|
||||
}
|
||||
if (fieldsUpdate.length > 0 && syncToProject && target.prjData !== undefined) {
|
||||
const errors = await this.updateIssueValues(target, okit, fieldsUpdate)
|
||||
if (errors.length === 0) {
|
||||
needExternalSync = true
|
||||
}
|
||||
}
|
||||
// TODO: Add support for labels, milestone, assignees
|
||||
}
|
||||
// if (dataType === undefined) {
|
||||
// continue
|
||||
// }
|
||||
// fieldsUpdate.push({
|
||||
// id: mapping.githubId,
|
||||
// dataType,
|
||||
// value: v
|
||||
// })
|
||||
// this.ctx.info(`=> prepare issue field ${attr.label} update`, {
|
||||
// url: issueExternal.url,
|
||||
// value: v,
|
||||
// workspace: this.provider.getWorkspaceId()
|
||||
// })
|
||||
// }
|
||||
// if (fieldsUpdate.length > 0 && syncToProject && target.prjData !== undefined) {
|
||||
// const errors = await this.updateIssueValues(target, okit, fieldsUpdate)
|
||||
// if (errors.length === 0) {
|
||||
// needExternalSync = true
|
||||
// }
|
||||
// }
|
||||
// // TODO: Add support for labels, milestone, assignees
|
||||
// }
|
||||
|
||||
// We need remove all readonly field values
|
||||
for (const k of Object.keys(update)) {
|
||||
// Skip readonly fields
|
||||
const attr = this.client.getHierarchy().findAttribute(target.project.mixinClass, k)
|
||||
if (attr?.readonly === true) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete (update as any)[k]
|
||||
continue
|
||||
}
|
||||
}
|
||||
// // We need remove all readonly field values
|
||||
// for (const k of Object.keys(update)) {
|
||||
// // Skip readonly fields
|
||||
// const attr = this.client.getHierarchy().findAttribute(target.project.mixinClass, k)
|
||||
// if (attr?.readonly === true) {
|
||||
// // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
// delete (update as any)[k]
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
|
||||
// Update collaborative description
|
||||
if (update.description !== undefined) {
|
||||
this.ctx.info(`<= perform ${issueExternal.url} update to collaborator`, {
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
})
|
||||
try {
|
||||
const description = update.description as Markup
|
||||
issueData.description = description
|
||||
const collabId = makeDocCollabId(existingIssue, 'description')
|
||||
await this.collaborator.updateMarkup(collabId, description)
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
this.ctx.error('error during description update', err)
|
||||
}
|
||||
}
|
||||
// // Update collaborative description
|
||||
// if (update.description !== undefined) {
|
||||
// this.ctx.info(`<= perform ${issueExternal.url} update to collaborator`, {
|
||||
// workspace: this.provider.getWorkspaceId()
|
||||
// })
|
||||
// try {
|
||||
// const description = update.description as Markup
|
||||
// issueData.description = description
|
||||
// const collabId = makeDocCollabId(existingIssue, 'description')
|
||||
// await this.collaborator.updateMarkup(collabId, description)
|
||||
// } catch (err: any) {
|
||||
// Analytics.handleError(err)
|
||||
// this.ctx.error('error during description update', err)
|
||||
// }
|
||||
// }
|
||||
|
||||
if (Object.keys(update).length > 0) {
|
||||
// We have some fields to update of existing from external
|
||||
this.ctx.info(`<= perform ${issueExternal.url} update to platform`, {
|
||||
...update,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
})
|
||||
await this.client.update(existingIssue, update, false, new Date().getTime(), accountGH)
|
||||
}
|
||||
// if (Object.keys(update).length > 0) {
|
||||
// // We have some fields to update of existing from external
|
||||
// this.ctx.info(`<= perform ${issueExternal.url} update to platform`, {
|
||||
// ...update,
|
||||
// workspace: this.provider.getWorkspaceId()
|
||||
// })
|
||||
// await this.client.update(existingIssue, update, false, new Date().getTime(), accountGH)
|
||||
// }
|
||||
|
||||
await this.afterSync(existingIssue, accountGH, issueExternal, info)
|
||||
// We need to trigger external version retrieval, via sync or event, to prevent move sync operations from platform before we will be sure all is updated on github.
|
||||
return {
|
||||
current: issueData,
|
||||
needSync: githubSyncVersion,
|
||||
...(needExternalSync ? { externalVersion: '' } : {}),
|
||||
lastGithubUser: null
|
||||
}
|
||||
// await this.afterSync(existingIssue, accountGH, issueExternal, info)
|
||||
// // We need to trigger external version retrieval, via sync or event, to prevent move sync operations from platform before we will be sure all is updated on github.
|
||||
// return {
|
||||
// current: issueData,
|
||||
// needSync: githubSyncVersion,
|
||||
// ...(needExternalSync ? { externalVersion: '' } : {}),
|
||||
// lastGithubUser: null
|
||||
// }
|
||||
}
|
||||
|
||||
private async notifyConnected (
|
||||
@@ -985,81 +989,83 @@ export abstract class IssueSyncManagerBase {
|
||||
issueExternal: IssueExternalData,
|
||||
_class: Ref<Class<Issue>>
|
||||
): Promise<Record<string, any>> {
|
||||
const issueUpdate: {
|
||||
title?: string
|
||||
body?: string
|
||||
stateReason?: string
|
||||
assigneeIds?: string[]
|
||||
} & Record<string, any> = {}
|
||||
if (platformUpdate.title != null) {
|
||||
if (platformUpdate.title !== issueExternal.title) {
|
||||
issueUpdate.title = platformUpdate.title
|
||||
}
|
||||
issueData.title = platformUpdate.title
|
||||
}
|
||||
if (platformUpdate.description != null) {
|
||||
// Need to convert to markdown
|
||||
issueUpdate.body = await this.provider.getMarkdown(platformUpdate.description ?? '')
|
||||
issueData.description = await this.provider.getMarkup(
|
||||
container.container,
|
||||
issueUpdate.body ?? '',
|
||||
this.stripGuestLink
|
||||
)
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// const issueUpdate: {
|
||||
// title?: string
|
||||
// body?: string
|
||||
// stateReason?: string
|
||||
// assigneeIds?: string[]
|
||||
// } & Record<string, any> = {}
|
||||
// if (platformUpdate.title != null) {
|
||||
// if (platformUpdate.title !== issueExternal.title) {
|
||||
// issueUpdate.title = platformUpdate.title
|
||||
// }
|
||||
// issueData.title = platformUpdate.title
|
||||
// }
|
||||
// if (platformUpdate.description != null) {
|
||||
// // Need to convert to markdown
|
||||
// issueUpdate.body = await this.provider.getMarkdown(platformUpdate.description ?? '')
|
||||
// issueData.description = await this.provider.getMarkup(
|
||||
// container.container,
|
||||
// issueUpdate.body ?? '',
|
||||
// this.stripGuestLink
|
||||
// )
|
||||
|
||||
// Of value is same, not need to update.
|
||||
if (compareMarkdown(issueUpdate.body, issueExternal.body)) {
|
||||
delete issueUpdate.body
|
||||
}
|
||||
}
|
||||
if (platformUpdate.assignee !== undefined) {
|
||||
const info =
|
||||
platformUpdate.assignee !== null
|
||||
? await this.provider.getGithubLogin(container.container, platformUpdate.assignee)
|
||||
: undefined
|
||||
// Check external
|
||||
// // Of value is same, not need to update.
|
||||
// if (compareMarkdown(issueUpdate.body, issueExternal.body)) {
|
||||
// delete issueUpdate.body
|
||||
// }
|
||||
// }
|
||||
// if (platformUpdate.assignee !== undefined) {
|
||||
// const info =
|
||||
// platformUpdate.assignee !== null
|
||||
// ? await this.provider.getGithubLogin(container.container, platformUpdate.assignee)
|
||||
// : undefined
|
||||
// // Check external
|
||||
|
||||
const currentAssignees = issueExternal.assignees.nodes.map((it) => it.id)
|
||||
currentAssignees.sort((a, b) => a.localeCompare(b))
|
||||
// const currentAssignees = issueExternal.assignees.nodes.map((it) => it.id)
|
||||
// currentAssignees.sort((a, b) => a.localeCompare(b))
|
||||
|
||||
issueUpdate.assigneeIds = info !== undefined ? [info.id] : []
|
||||
issueUpdate.assigneeIds.sort((a, b) => a.localeCompare(b))
|
||||
// issueUpdate.assigneeIds = info !== undefined ? [info.id] : []
|
||||
// issueUpdate.assigneeIds.sort((a, b) => a.localeCompare(b))
|
||||
|
||||
if (deepEqual(currentAssignees, issueUpdate.assigneeIds)) {
|
||||
// Same ids
|
||||
delete issueUpdate.assigneeIds
|
||||
}
|
||||
issueData.assignee = platformUpdate.assignee
|
||||
}
|
||||
// if (deepEqual(currentAssignees, issueUpdate.assigneeIds)) {
|
||||
// // Same ids
|
||||
// delete issueUpdate.assigneeIds
|
||||
// }
|
||||
// issueData.assignee = platformUpdate.assignee
|
||||
// }
|
||||
|
||||
const status = platformUpdate.status ?? issueData.status
|
||||
const type = await this.provider.getTaskTypeOf(container.project.type, _class)
|
||||
const statuses = await this.provider.getStatuses(type?._id)
|
||||
const st = statuses.find((it) => it._id === status)
|
||||
if (st !== undefined) {
|
||||
// Need to convert to two operations.
|
||||
switch (st.category) {
|
||||
case task.statusCategory.UnStarted:
|
||||
case task.statusCategory.ToDo:
|
||||
case task.statusCategory.Active:
|
||||
if (issueExternal.state !== 'OPEN') {
|
||||
issueUpdate.state = 'OPEN'
|
||||
}
|
||||
break
|
||||
case task.statusCategory.Won:
|
||||
if (issueExternal.state !== 'CLOSED' || issueExternal.stateReason !== 'COMPLETED') {
|
||||
issueUpdate.state = 'CLOSED'
|
||||
issueUpdate.stateReason = 'COMPLETED'
|
||||
}
|
||||
break
|
||||
case task.statusCategory.Lost:
|
||||
if (issueExternal.state !== 'CLOSED' || issueExternal.stateReason !== 'NOT_PLANNED') {
|
||||
issueUpdate.state = 'CLOSED'
|
||||
issueUpdate.stateReason = 'not_planed' // Not supported change to github
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return issueUpdate
|
||||
// const status = platformUpdate.status ?? issueData.status
|
||||
// const type = await this.provider.getTaskTypeOf(container.project.type, _class)
|
||||
// const statuses = await this.provider.getStatuses(type?._id)
|
||||
// const st = statuses.find((it) => it._id === status)
|
||||
// if (st !== undefined) {
|
||||
// // Need to convert to two operations.
|
||||
// switch (st.category) {
|
||||
// case task.statusCategory.UnStarted:
|
||||
// case task.statusCategory.ToDo:
|
||||
// case task.statusCategory.Active:
|
||||
// if (issueExternal.state !== 'OPEN') {
|
||||
// issueUpdate.state = 'OPEN'
|
||||
// }
|
||||
// break
|
||||
// case task.statusCategory.Won:
|
||||
// if (issueExternal.state !== 'CLOSED' || issueExternal.stateReason !== 'COMPLETED') {
|
||||
// issueUpdate.state = 'CLOSED'
|
||||
// issueUpdate.stateReason = 'COMPLETED'
|
||||
// }
|
||||
// break
|
||||
// case task.statusCategory.Lost:
|
||||
// if (issueExternal.state !== 'CLOSED' || issueExternal.stateReason !== 'NOT_PLANNED') {
|
||||
// issueUpdate.state = 'CLOSED'
|
||||
// issueUpdate.stateReason = 'not_planed' // Not supported change to github
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// return issueUpdate
|
||||
}
|
||||
|
||||
async syncIssues (
|
||||
@@ -1086,14 +1092,14 @@ export abstract class IssueSyncManagerBase {
|
||||
for (const issue of issues) {
|
||||
try {
|
||||
if (issue.url === undefined && Object.keys(issue).length === 0) {
|
||||
this.ctx.info('Retrieve empty document', { repo: repo.name, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('Retrieve empty document', { repo: repo.name, workspace: this.provider.getWorkspaceId() })
|
||||
continue
|
||||
}
|
||||
const existing =
|
||||
syncInfo.find((it) => it.url.toLowerCase() === issue.url.toLowerCase()) ??
|
||||
syncInfo.find((it) => (it.external as IssueExternalData)?.id === issue.id)
|
||||
if (existing === undefined && syncDocs === undefined) {
|
||||
this.ctx.info('Create sync doc', { url: issue.url, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('Create sync doc', { url: issue.url, workspace: this.provider.getWorkspaceId() })
|
||||
await ops.createDoc<DocSyncInfo>(github.class.DocSyncInfo, repo.githubProject, {
|
||||
url: issue.url.toLowerCase(),
|
||||
needSync: '',
|
||||
@@ -1112,7 +1118,7 @@ export abstract class IssueSyncManagerBase {
|
||||
}
|
||||
const externalEqual = deepEqual(existing.external, issue)
|
||||
if (!externalEqual || existing.externalVersion !== githubExternalSyncVersion) {
|
||||
this.ctx.info('Update sync doc', { url: issue.url, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('Update sync doc', { url: issue.url, workspace: this.provider.getWorkspaceId() })
|
||||
await ops.diffUpdate(
|
||||
existing,
|
||||
{
|
||||
@@ -1178,7 +1184,7 @@ export abstract class IssueSyncManagerBase {
|
||||
}
|
||||
}
|
||||
|
||||
abstract deleteGithubDocument (container: ContainerFocus, account: Ref<Account>, id: string): Promise<void>
|
||||
abstract deleteGithubDocument (container: ContainerFocus, account: PersonId, id: string): Promise<void>
|
||||
|
||||
async handleDelete (
|
||||
existing: Doc | undefined,
|
||||
@@ -1207,7 +1213,7 @@ export abstract class IssueSyncManagerBase {
|
||||
}
|
||||
const account =
|
||||
existing?.createdBy ?? (await this.provider.getAccount(issueExternal.author))?._id ?? core.account.System
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(account as PersonId)) ?? container.container.octokit
|
||||
|
||||
if (existing !== undefined && issueExternal !== undefined) {
|
||||
let target = await this.getMilestoneIssueTarget(
|
||||
@@ -1324,7 +1330,10 @@ export abstract class IssueSyncManagerBase {
|
||||
const publicLink = await getPublicLink(
|
||||
object,
|
||||
this.client,
|
||||
this.provider.getWorkspaceId(),
|
||||
{
|
||||
uuid: this.provider.getWorkspaceId(),
|
||||
url: this.provider.getWorkspaceUrl()
|
||||
},
|
||||
false,
|
||||
this.provider.getBranding()
|
||||
)
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
* Add since to synchronization
|
||||
*/
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AttachedData,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
@@ -53,17 +52,19 @@ import { getSince, gqlp, guessStatus, isGHWriteAllowed, syncRunner } from './uti
|
||||
export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncManager {
|
||||
createPromise: Promise<IssueExternalData | undefined> | undefined
|
||||
externalDerivedSync = false
|
||||
async getAssigneesI (issue: GithubIssue): Promise<PersonAccount[]> {
|
||||
async getAssigneesI (issue: GithubIssue): Promise<any[]> {
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// Find Assignees and reviewers
|
||||
const assignees: PersonAccount[] = []
|
||||
// const assignees: PersonAccount[] = []
|
||||
|
||||
for (const o of issue.assignees) {
|
||||
const acc = await this.provider.getAccountU(o)
|
||||
if (acc !== undefined) {
|
||||
assignees.push(acc)
|
||||
}
|
||||
}
|
||||
return assignees
|
||||
// for (const o of issue.assignees) {
|
||||
// const acc = await this.provider.getAccountU(o)
|
||||
// if (acc !== undefined) {
|
||||
// assignees.push(acc)
|
||||
// }
|
||||
// }
|
||||
// return assignees
|
||||
}
|
||||
|
||||
async handleEvent<T = IssuesEvent | ProjectsV2ItemEvent>(
|
||||
@@ -80,7 +81,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
login: event.sender.login,
|
||||
type: event.sender.type,
|
||||
url: event.sender.url,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
|
||||
if (event.sender.type === 'Bot') {
|
||||
@@ -112,7 +113,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
if (prj === undefined) {
|
||||
this.ctx.info('Event from unknown v2 project', {
|
||||
nodeId: projectV2Event.projects_v2_item.project_node_id,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -129,7 +130,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
this.ctx.info('No project for repository', {
|
||||
repository: issueEvent.repository.name,
|
||||
nodeId: issueEvent.repository.node_id,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -385,7 +386,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
this.ctx.info('create github issue', {
|
||||
title: (existing as Issue).title,
|
||||
number: (existing as Issue).number,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
const createdIssueData = await this.ctx.withLog(
|
||||
'create github issue',
|
||||
@@ -394,7 +395,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
this.createPromise = this.createGithubIssue(container, { ...(existing as Issue), description }, repository)
|
||||
return await this.createPromise
|
||||
},
|
||||
{ id: (existing as Issue).identifier, workspace: this.provider.getWorkspaceId().name }
|
||||
{ id: (existing as Issue).identifier, workspace: this.provider.getWorkspaceId() }
|
||||
)
|
||||
if (createdIssueData === undefined) {
|
||||
this.ctx.error('Error create issue', { url: info.url })
|
||||
@@ -491,7 +492,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
// A target node id
|
||||
const targetNodeId: string | undefined = info.targetNodeId as string
|
||||
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(account as PersonId)) ?? container.container.octokit
|
||||
|
||||
const type = await this.provider.getTaskTypeOf(container.project.type, tracker.class.Issue)
|
||||
const statuses = await this.provider.getStatuses(type?._id)
|
||||
@@ -547,7 +548,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
try {
|
||||
this.ctx.info('add issue to project v2', {
|
||||
url: issueExternal.url,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
target.prjData = await this.ctx.withLog('add issue to project v2', {}, () =>
|
||||
this.addIssueToProject(container, okit, issueExternal, target.target.projectNodeId as string)
|
||||
@@ -571,7 +572,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
this.ctx.info('create platform issue', {
|
||||
url: issueExternal.url,
|
||||
title: issueExternal.title,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
const { markdownCompatible, markdown } = await this.provider.checkMarkdownConversion(
|
||||
container.container,
|
||||
@@ -664,7 +665,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
}
|
||||
|
||||
async afterSync (existing: Issue, update: DocumentUpdate<Doc>, account: Ref<Account>): Promise<void> {}
|
||||
async afterSync (existing: Issue, update: DocumentUpdate<Doc>, account: PersonId): Promise<void> {}
|
||||
|
||||
async performIssueFieldsUpdate (
|
||||
info: DocSyncInfo,
|
||||
@@ -674,7 +675,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
container: ContainerFocus,
|
||||
issueExternal: IssueExternalData,
|
||||
okit: Octokit,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<boolean> {
|
||||
const { state, stateReason, body, ...issueUpdate } = await this.collectIssueUpdate(
|
||||
info,
|
||||
@@ -686,8 +687,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
tracker.class.Issue
|
||||
)
|
||||
|
||||
const isLocked =
|
||||
info.isDescriptionLocked === true && !(await this.provider.isPlatformUser(account as Ref<PersonAccount>))
|
||||
const isLocked = info.isDescriptionLocked === true && !(await this.provider.isPlatformUser(account))
|
||||
|
||||
const hasFieldStateChanges = Object.keys(issueUpdate).length > 0 || state !== undefined
|
||||
// We should allow modification from user.
|
||||
@@ -737,7 +737,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
url: issueExternal.url,
|
||||
...issueUpdate,
|
||||
body,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
if (isGHWriteAllowed()) {
|
||||
if (state === 'OPEN') {
|
||||
@@ -773,7 +773,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
'==> updateIssue',
|
||||
{},
|
||||
async () => {
|
||||
this.ctx.info('update fields', { ...issueUpdate, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('update fields', { ...issueUpdate, workspace: this.provider.getWorkspaceId() })
|
||||
if (isGHWriteAllowed()) {
|
||||
const hasOtherChanges = Object.keys(issueUpdate).length > 0
|
||||
if (state === 'OPEN') {
|
||||
@@ -817,8 +817,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
): Promise<IssueExternalData | undefined> {
|
||||
const existingIssue = existing
|
||||
|
||||
const okit =
|
||||
(await this.provider.getOctokit(existingIssue.modifiedBy as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(existingIssue.modifiedBy)) ?? container.container.octokit
|
||||
|
||||
const repoId = repository.nodeId
|
||||
|
||||
@@ -858,8 +857,8 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
}
|
||||
|
||||
async deleteGithubDocument (container: ContainerFocus, account: Ref<Account>, id: string): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
async deleteGithubDocument (container: ContainerFocus, account: PersonId, id: string): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account)) ?? container.container.octokit
|
||||
|
||||
const q = `mutation deleteIssue($issueID: ID!) {
|
||||
deleteIssue(
|
||||
@@ -879,7 +878,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
|
||||
private async createNewIssue (
|
||||
info: DocSyncInfo,
|
||||
account: Ref<Account>,
|
||||
account: PersonId,
|
||||
issueData: GithubIssueData & { status: Issue['status'] },
|
||||
issueExternal: IssueExternalData,
|
||||
repo: Ref<GithubIntegrationRepository>,
|
||||
@@ -1020,7 +1019,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
if (issues.some((issue) => issue.url === undefined && Object.keys(issue).length === 0)) {
|
||||
this.ctx.error('empty document content', {
|
||||
repo: repo.name,
|
||||
workspace: this.provider.getWorkspaceId().name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
data: cutObjectArray(response)
|
||||
})
|
||||
}
|
||||
@@ -1033,7 +1032,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
this.ctx.warn('issue external retrieval switch to one by one mode', {
|
||||
errors: err.errors,
|
||||
msg: err.message,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
} else if (partsize === 1) {
|
||||
// We need to update issue, since it is missing on external side.
|
||||
@@ -1043,7 +1042,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
errors: err.errors,
|
||||
msg: err.message,
|
||||
url: syncDoc.url,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
await derivedClient.diffUpdate(
|
||||
syncDoc,
|
||||
@@ -1109,7 +1108,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
const since = await getSince(this.client, tracker.class.Issue, repo)
|
||||
|
||||
this.ctx.info('sync external issues', { repo: repo.name, since, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('sync external issues', { repo: repo.name, since, workspace: this.provider.getWorkspaceId() })
|
||||
|
||||
const i = integration.octokit.graphql.paginate.iterator(
|
||||
`query listIssue($name: String!, $owner: String!, $since: DateTime!, $cursor: String) {
|
||||
@@ -1143,7 +1142,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
if (issues.some((issue) => issue.url === undefined && Object.keys(issue).length === 0)) {
|
||||
this.ctx.error('empty document content', {
|
||||
repo: repo.name,
|
||||
workspace: this.provider.getWorkspaceId().name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
data: cutObjectArray(data)
|
||||
})
|
||||
}
|
||||
@@ -1158,7 +1157,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
this.ctx.info('sync external issues - done', {
|
||||
repo: repo.name,
|
||||
since,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
integration.synchronized.add(syncKey)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
AnyAttribute,
|
||||
Class,
|
||||
@@ -107,10 +106,14 @@ export class ProjectsSyncManager implements DocSyncManager {
|
||||
return { needSync: githubSyncVersion }
|
||||
}
|
||||
|
||||
const okit = await this.provider.getOctokit(container.project.createdBy as Ref<PersonAccount>)
|
||||
if (container.project.createdBy === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const okit = await this.provider.getOctokit(container.project.createdBy)
|
||||
if (okit === undefined) {
|
||||
this.ctx.info('No Authentication for author, waiting for authentication.', {
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return { needSync: githubSyncVersion, error: 'Need authentication for user' }
|
||||
}
|
||||
@@ -270,8 +273,7 @@ export class ProjectsSyncManager implements DocSyncManager {
|
||||
const allAttributes = this.client.getHierarchy().getAllAttributes(tracker.class.Milestone)
|
||||
const platformUpdate = collectUpdate<Milestone>(previousData, existingMilestone, Array.from(allAttributes.keys()))
|
||||
|
||||
const okit =
|
||||
(await this.provider.getOctokit(existing.modifiedBy as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(existing.modifiedBy)) ?? container.container.octokit
|
||||
|
||||
// Remove current same values from update
|
||||
for (const [k, v] of Object.entries(update)) {
|
||||
@@ -322,7 +324,7 @@ export class ProjectsSyncManager implements DocSyncManager {
|
||||
if (project === undefined || repository === undefined) {
|
||||
this.ctx.error('Unable to find project and repository for event', {
|
||||
name: event.repository.name,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -392,10 +394,10 @@ export class ProjectsSyncManager implements DocSyncManager {
|
||||
continue
|
||||
}
|
||||
|
||||
const okit = await this.provider.getOctokit(integration.integration.createdBy as Ref<PersonAccount>)
|
||||
const okit = await this.provider.getOctokit(integration.integration.createdBy)
|
||||
if (okit === undefined) {
|
||||
this.ctx.info('No Authentication for author, waiting for authentication.', {
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { Person, PersonAccount } from '@hcengineering/contact'
|
||||
import { Person } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AttachedData,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
@@ -93,7 +94,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
action: _event.action,
|
||||
login: _event.sender.login,
|
||||
type: _event.sender.type,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
|
||||
const projectV2Event = (_event as any as ProjectsV2ItemEvent).projects_v2_item?.id !== undefined
|
||||
@@ -117,7 +118,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
if (prj === undefined) {
|
||||
this.ctx.info('Event from unknown v2 project', {
|
||||
nodeId: projectV2Event.projects_v2_item.project_node_id,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -134,7 +135,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
if (project === undefined || repository === undefined) {
|
||||
this.ctx.info('No project for repository', {
|
||||
name: event.repository.name,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -321,33 +322,33 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
}
|
||||
}
|
||||
|
||||
async getReviewers (issue: PullRequestExternalData): Promise<PersonAccount[]> {
|
||||
// Find Assignees and reviewers
|
||||
const ids: UserInfo[] = issue.reviewRequests.nodes.map((it: any) => it.requestedReviewer)
|
||||
// async getReviewers (issue: PullRequestExternalData): Promise<PersonAccount[]> {
|
||||
// // Find Assignees and reviewers
|
||||
// const ids: UserInfo[] = issue.reviewRequests.nodes.map((it: any) => it.requestedReviewer)
|
||||
|
||||
const values: PersonAccount[] = []
|
||||
// const values: PersonAccount[] = []
|
||||
|
||||
for (const o of ids) {
|
||||
const acc = await this.provider.getAccount(o)
|
||||
if (acc !== undefined) {
|
||||
values.push(acc)
|
||||
}
|
||||
}
|
||||
// for (const o of ids) {
|
||||
// const acc = await this.provider.getAccount(o)
|
||||
// if (acc !== undefined) {
|
||||
// values.push(acc)
|
||||
// }
|
||||
// }
|
||||
|
||||
for (const n of issue.latestReviews.nodes) {
|
||||
const acc = await this.provider.getAccount(n.author)
|
||||
if (acc !== undefined) {
|
||||
values.push(acc)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
// for (const n of issue.latestReviews.nodes) {
|
||||
// const acc = await this.provider.getAccount(n.author)
|
||||
// if (acc !== undefined) {
|
||||
// values.push(acc)
|
||||
// }
|
||||
// }
|
||||
// return values
|
||||
// }
|
||||
|
||||
private async createSyncData (
|
||||
pullRequestExternal: PullRequestExternalData,
|
||||
derivedClient: TxOperations,
|
||||
repo: GithubIntegrationRepository,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const lastModified = new Date(pullRequestExternal.updatedAt).getTime()
|
||||
await derivedClient.createDoc(github.class.DocSyncInfo, repo.githubProject as Ref<GithubProject>, {
|
||||
@@ -389,7 +390,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
// A target node id
|
||||
const targetNodeId: string | undefined = info.targetNodeId as string
|
||||
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(account as PersonId)) ?? container.container.octokit
|
||||
|
||||
const isProjectProjectTarget = target.target.projectNodeId === target.project.projectNodeId
|
||||
const supportProjects =
|
||||
@@ -447,7 +448,8 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
}
|
||||
|
||||
const assignees = await this.getAssignees(pullRequestExternal)
|
||||
const reviewers = await this.getReviewers(pullRequestExternal)
|
||||
// TODO: FIXME
|
||||
const reviewers: any = [] // await this.getReviewers(pullRequestExternal)
|
||||
|
||||
const latestReviews: LastReviewState[] = []
|
||||
|
||||
@@ -464,7 +466,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
title: pullRequestExternal.title,
|
||||
description: await this.provider.getMarkup(container.container, pullRequestExternal.body, this.stripGuestLink),
|
||||
assignee: assignees[0]?.person ?? null,
|
||||
reviewers: reviewers.map((it) => it.person),
|
||||
reviewers: reviewers.map((it: any) => it.person),
|
||||
draft: pullRequestExternal.isDraft,
|
||||
head: pullRequestExternal.headRef,
|
||||
base: pullRequestExternal.baseRef,
|
||||
@@ -634,7 +636,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
}
|
||||
}
|
||||
|
||||
async afterSync (existing: Issue, account: Ref<Account>, issueExternal: any, info: DocSyncInfo): Promise<void> {
|
||||
async afterSync (existing: Issue, account: PersonId, issueExternal: any, info: DocSyncInfo): Promise<void> {
|
||||
const pullRequest = existing as GithubPullRequest
|
||||
await this.todoSync(this.client, pullRequest, issueExternal as PullRequestExternalData, info, account)
|
||||
}
|
||||
@@ -647,7 +649,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
>,
|
||||
external: PullRequestExternalData,
|
||||
info: DocSyncInfo,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
// Find all todo's related to PR.
|
||||
const allTodos = await client.findAll<GithubTodo>(github.mixin.GithubTodo, { attachedTo: pullRequest._id })
|
||||
@@ -826,7 +828,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
pullRequest: Pick<GithubPullRequest, '_id' | 'identifier' | 'space' | '_class' | 'reviewers' | 'title' | 'state'>,
|
||||
external: PullRequestExternalData,
|
||||
todoUser: Ref<Person>,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const latestTodo = await client.findOne(
|
||||
time.class.ToDo,
|
||||
@@ -879,7 +881,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
>,
|
||||
external: PullRequestExternalData,
|
||||
todoUser: Ref<Person>,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const latestTodo = await client.findOne(
|
||||
time.class.ToDo,
|
||||
@@ -1011,7 +1013,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
container: ContainerFocus,
|
||||
issueExternal: IssueExternalData,
|
||||
okit: Octokit,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<boolean> {
|
||||
let { state, stateReason, body, ...issueUpdate } = await this.collectIssueUpdate(
|
||||
info,
|
||||
@@ -1029,8 +1031,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
}
|
||||
|
||||
const hasFieldsUpdate = Object.keys(issueUpdate).length > 0 || state !== undefined
|
||||
const isLocked =
|
||||
info.isDescriptionLocked === true && !(await this.provider.isPlatformUser(account as Ref<PersonAccount>))
|
||||
const isLocked = info.isDescriptionLocked === true && !(await this.provider.isPlatformUser(account))
|
||||
|
||||
if (hasFieldsUpdate || body !== undefined) {
|
||||
if (body !== undefined && !isLocked) {
|
||||
@@ -1042,7 +1043,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
url: issueExternal.url,
|
||||
...issueUpdate,
|
||||
body,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
if (isGHWriteAllowed()) {
|
||||
await okit?.graphql(
|
||||
@@ -1072,7 +1073,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
this.ctx.info('update-fields', {
|
||||
url: issueExternal.url,
|
||||
...issueUpdate,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
if (isGHWriteAllowed()) {
|
||||
await okit?.graphql(
|
||||
@@ -1105,7 +1106,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
pullRequestExternal: PullRequestExternalData,
|
||||
existingPR: Pick<GithubPullRequest, '_id' | 'space' | '_class'>,
|
||||
lastModified: number,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const repo = await this.provider.getRepositoryById(info.repository)
|
||||
if (repo?.nodeId === undefined) {
|
||||
@@ -1156,7 +1157,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
private async createPullRequest (
|
||||
client: TxOperations,
|
||||
info: DocSyncInfo,
|
||||
account: Ref<Account>,
|
||||
account: PersonId,
|
||||
pullRequestData: GithubPullRequestData & { status: Issue['status'] },
|
||||
pullRequestExternal: PullRequestExternalData,
|
||||
repo: Ref<GithubIntegrationRepository>,
|
||||
@@ -1375,7 +1376,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
if (issues.some((issue) => issue.url === undefined && Object.keys(issue).length === 0)) {
|
||||
this.ctx.error('empty document content updates', {
|
||||
repo: repo.name,
|
||||
workspace: this.provider.getWorkspaceId().name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
data: cutObjectArray(response)
|
||||
})
|
||||
}
|
||||
@@ -1387,7 +1388,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
this.ctx.warn('pull request external retrieval switch to one by one mode', {
|
||||
errors: err.errors,
|
||||
msg: err.message,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
} else if (partsize === 1) {
|
||||
// We need to update issue, since it is missing on external side.
|
||||
@@ -1397,7 +1398,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
errors: err.errors,
|
||||
msg: err.message,
|
||||
url: syncDoc.url,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
await derivedClient.diffUpdate(
|
||||
syncDoc,
|
||||
@@ -1467,7 +1468,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
this.ctx.info('sync external pull requests', {
|
||||
repo: repo.name,
|
||||
since,
|
||||
workspace: this.provider.getWorkspaceId().name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
state: 'OPEN'
|
||||
})
|
||||
await this.performPRSync(integration, repo, 'OPEN', undefined, derivedClient, prj)
|
||||
@@ -1475,7 +1476,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
this.ctx.info('sync external pull requests', {
|
||||
repo: repo.name,
|
||||
since,
|
||||
workspace: this.provider.getWorkspaceId().name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
state: 'CLOSED, MERGED'
|
||||
})
|
||||
await this.performPRSync(integration, repo, 'CLOSED, MERGED', since, derivedClient, prj)
|
||||
@@ -1483,7 +1484,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
this.ctx.info('sync external pull requests - done', {
|
||||
repo: repo.name,
|
||||
since,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
|
||||
this.provider.sync()
|
||||
@@ -1535,7 +1536,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
repo: repo.name,
|
||||
since,
|
||||
len: issues.length,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
|
||||
if (since !== undefined) {
|
||||
@@ -1552,7 +1553,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
if (emptyIndex !== -1) {
|
||||
this.ctx.error('empty document content', {
|
||||
repo: repo.name,
|
||||
workspace: this.provider.getWorkspaceId().name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
data: cutObjectArray(data),
|
||||
emptyIndex,
|
||||
el: JSON.stringify(issues[emptyIndex])
|
||||
@@ -1593,7 +1594,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS
|
||||
return { patch, contentType }
|
||||
}
|
||||
|
||||
async deleteGithubDocument (container: ContainerFocus, account: Ref<Account>, id: string): Promise<void> {
|
||||
async deleteGithubDocument (container: ContainerFocus, account: PersonId, id: string): Promise<void> {
|
||||
// No delete is allowed for pull requests
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export class RepositorySyncMapper implements DocSyncManager {
|
||||
)
|
||||
this.ctx.info('Creating repository info document...', {
|
||||
url: repository.full_name,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ export class RepositorySyncMapper implements DocSyncManager {
|
||||
)
|
||||
this.ctx.info('Creating repository info document...', {
|
||||
url: event.repository.url,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
break
|
||||
}
|
||||
@@ -244,7 +244,7 @@ export class RepositorySyncMapper implements DocSyncManager {
|
||||
): Promise<void> {
|
||||
const inst = integration.octokit
|
||||
if (inst === undefined || integration.octokit === undefined) {
|
||||
this.ctx.info('no installation found', { workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('no installation found', { workspace: this.provider.getWorkspaceId() })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ export class RepositorySyncMapper implements DocSyncManager {
|
||||
}
|
||||
this.ctx.info('Checking github installation repositories...', {
|
||||
installationId: integration.installationId,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
|
||||
const iterable = this.app.eachRepository.iterator({ installationId: integration.installationId })
|
||||
@@ -299,7 +299,7 @@ export class RepositorySyncMapper implements DocSyncManager {
|
||||
)
|
||||
this.ctx.info('Creating repository info document...', {
|
||||
url: repository.url,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
} else {
|
||||
allRepos = allRepos.filter((it) => it._id !== integrationRepo._id)
|
||||
@@ -315,7 +315,7 @@ export class RepositorySyncMapper implements DocSyncManager {
|
||||
this.ctx.info('processing repository diff update...', {
|
||||
repository: repository.name,
|
||||
...diff,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
await this.client.diffUpdate(
|
||||
integrationRepo,
|
||||
@@ -360,7 +360,7 @@ export class RepositorySyncMapper implements DocSyncManager {
|
||||
"https://api.github.com/repos/hcengineering/anticrm/issues/comments/1679316918"
|
||||
"https://github.com/hcengineering/uberflow/pull/195"
|
||||
* */
|
||||
this.ctx.info('handle repository rename', { repo, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('handle repository rename', { repo, workspace: this.provider.getWorkspaceId() })
|
||||
const update = async (): Promise<void> => {
|
||||
while (true) {
|
||||
const docs = await this.client.findAll(
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AttachedData,
|
||||
Doc,
|
||||
DocData,
|
||||
@@ -70,13 +69,13 @@ export class ReviewCommentSyncManager implements DocSyncManager {
|
||||
this.ctx.info('reviewComments:handleEvent', {
|
||||
action: event.action,
|
||||
login: event.sender.login,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
const { project, repository } = await this.provider.getProjectAndRepository(event.repository.node_id)
|
||||
if (project === undefined || repository === undefined) {
|
||||
this.ctx.info('No project for repository', {
|
||||
name: event.repository.name,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -146,12 +145,12 @@ export class ReviewCommentSyncManager implements DocSyncManager {
|
||||
|
||||
async deleteGithubDocument (
|
||||
container: ContainerFocus,
|
||||
account: Ref<Account>,
|
||||
account: PersonId,
|
||||
id: string,
|
||||
derivedClient: TxOperations,
|
||||
parent?: DocSyncInfo
|
||||
): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(account)) ?? container.container.octokit
|
||||
const q = `mutation deleteReviewComment($reviewID: ID!) {
|
||||
deletePullRequestReviewComment(input: {
|
||||
id: $reviewID
|
||||
@@ -382,7 +381,7 @@ export class ReviewCommentSyncManager implements DocSyncManager {
|
||||
container: ContainerFocus,
|
||||
parent: DocSyncInfo,
|
||||
reviewComment: ReviewCommentExternalData,
|
||||
account: Ref<Account>,
|
||||
account: PersonId,
|
||||
derivedClient: TxOperations
|
||||
): Promise<void> {
|
||||
const repository = await this.provider.getRepositoryById(info.repository)
|
||||
@@ -416,7 +415,7 @@ export class ReviewCommentSyncManager implements DocSyncManager {
|
||||
if (Object.keys(platformUpdate).length > 0) {
|
||||
if (platformUpdate.body !== undefined) {
|
||||
const body = await this.provider.getMarkup(container.container, platformUpdate.body)
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(account)) ?? container.container.octokit
|
||||
const q = `mutation updateReviewComment($commentID: ID!, $body: String!) {
|
||||
updatePullRequestReviewComment(input: {
|
||||
threadId: $threadID
|
||||
@@ -450,7 +449,7 @@ export class ReviewCommentSyncManager implements DocSyncManager {
|
||||
messageData: ReviewCommentData,
|
||||
parent: DocSyncInfo,
|
||||
review: ReviewCommentExternalData,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const _id: Ref<GithubReviewComment> = info._id as unknown as Ref<GithubReviewComment>
|
||||
const value: AttachedData<GithubReviewComment> = {
|
||||
@@ -487,8 +486,7 @@ export class ReviewCommentSyncManager implements DocSyncManager {
|
||||
return {}
|
||||
}
|
||||
const existingReview = existing as GithubReviewComment
|
||||
const okit =
|
||||
(await this.provider.getOctokit(existingReview.modifiedBy as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(existingReview.modifiedBy)) ?? container.container.octokit
|
||||
|
||||
// No external version yet, create it.
|
||||
try {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AttachedData,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
@@ -89,13 +88,13 @@ export class ReviewThreadSyncManager implements DocSyncManager {
|
||||
return
|
||||
}
|
||||
}
|
||||
this.ctx.info('reviewThreads:handleEvent', { event, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('reviewThreads:handleEvent', { event, workspace: this.provider.getWorkspaceId() })
|
||||
|
||||
const { project, repository } = await this.provider.getProjectAndRepository(event.repository.node_id)
|
||||
if (project === undefined || repository === undefined) {
|
||||
this.ctx.info('No project for repository', {
|
||||
name: event.repository.name,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -163,7 +162,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
|
||||
return true
|
||||
}
|
||||
|
||||
async deleteGithubDocument (container: ContainerFocus, account: Ref<Account>, id: string): Promise<void> {
|
||||
async deleteGithubDocument (container: ContainerFocus, account: PersonId, id: string): Promise<void> {
|
||||
// Not supported
|
||||
}
|
||||
|
||||
@@ -330,7 +329,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
|
||||
container: ContainerFocus,
|
||||
parent: DocSyncInfo,
|
||||
review: ReviewThreadExternalData,
|
||||
account: Ref<Account>,
|
||||
account: PersonId,
|
||||
derivedClient: TxOperations
|
||||
): Promise<void> {
|
||||
const repository = await this.provider.getRepositoryById(info.repository)
|
||||
@@ -364,7 +363,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
|
||||
if (Object.keys(platformUpdate).length > 0) {
|
||||
// Check and update external
|
||||
if (platformUpdate.isResolved !== undefined && githubConfiguration.ResolveThreadSupported) {
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(account)) ?? container.container.octokit
|
||||
const q = `mutation updateReviewThread($threadID: ID!) {
|
||||
${platformUpdate.isResolved ? 'resolveReviewThread' : 'unresolveReviewThread'} (
|
||||
input: {
|
||||
@@ -401,7 +400,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
|
||||
messageData: ReviewThreadData,
|
||||
parent: DocSyncInfo,
|
||||
review: ReviewThreadExternalData,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const _id: Ref<GithubReviewThread> = info._id as unknown as Ref<GithubReviewThread>
|
||||
const value: AttachedData<GithubReviewThread> = {
|
||||
@@ -438,8 +437,7 @@ export class ReviewThreadSyncManager implements DocSyncManager {
|
||||
return {}
|
||||
}
|
||||
const existingReview = existing as GithubReviewThread
|
||||
const okit =
|
||||
(await this.provider.getOctokit(existingReview.modifiedBy as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(existingReview.modifiedBy)) ?? container.container.octokit
|
||||
|
||||
// No external version yet, create it.
|
||||
// Will be added into pending state.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
import { PersonAccount } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AttachedData,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
@@ -67,13 +66,13 @@ export class ReviewSyncManager implements DocSyncManager {
|
||||
return
|
||||
}
|
||||
}
|
||||
this.ctx.info('reviews:handleEvent', { event, workspace: this.provider.getWorkspaceId().name })
|
||||
this.ctx.info('reviews:handleEvent', { event, workspace: this.provider.getWorkspaceId() })
|
||||
|
||||
const { project, repository } = await this.provider.getProjectAndRepository(event.repository.node_id)
|
||||
if (project === undefined || repository === undefined) {
|
||||
this.ctx.info('No project for repository', {
|
||||
name: event.repository.name,
|
||||
workspace: this.provider.getWorkspaceId().name
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -141,8 +140,8 @@ export class ReviewSyncManager implements DocSyncManager {
|
||||
return true
|
||||
}
|
||||
|
||||
async deleteGithubDocument (container: ContainerFocus, account: Ref<Account>, id: string): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
async deleteGithubDocument (container: ContainerFocus, account: PersonId, id: string): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account)) ?? container.container.octokit
|
||||
const q = `mutation deleteReview($reviewID: ID!) {
|
||||
deletePullRequestReview(input: {
|
||||
pullRequestReviewId: $reviewID
|
||||
@@ -334,7 +333,7 @@ export class ReviewSyncManager implements DocSyncManager {
|
||||
container: ContainerFocus,
|
||||
parent: DocSyncInfo,
|
||||
review: ReviewExternalData,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const repository = await this.provider.getRepositoryById(info.repository)
|
||||
if (repository === undefined) {
|
||||
@@ -378,7 +377,7 @@ export class ReviewSyncManager implements DocSyncManager {
|
||||
messageData: ReviewData,
|
||||
parent: DocSyncInfo,
|
||||
review: ReviewExternalData,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const _id: Ref<GithubReview> = info._id as unknown as Ref<GithubReview>
|
||||
const value: AttachedData<GithubReview> = {
|
||||
@@ -415,8 +414,7 @@ export class ReviewSyncManager implements DocSyncManager {
|
||||
return {}
|
||||
}
|
||||
const existingReview = existing as GithubReview
|
||||
const okit =
|
||||
(await this.provider.getOctokit(existingReview.modifiedBy as Ref<PersonAccount>)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(existingReview.modifiedBy)) ?? container.container.octokit
|
||||
|
||||
// No external version yet, create it.
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AnyAttribute,
|
||||
AttachedDoc,
|
||||
Class,
|
||||
@@ -297,7 +297,7 @@ export async function deleteObjects (
|
||||
ctx: MeasureContext,
|
||||
client: TxOperations,
|
||||
objects: Doc[],
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const ops = client.apply()
|
||||
for (const object of objects) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Person, PersonAccount } from '@hcengineering/contact'
|
||||
import { Person } from '@hcengineering/contact'
|
||||
import {
|
||||
Account,
|
||||
PersonId,
|
||||
Branding,
|
||||
Class,
|
||||
Data,
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Status,
|
||||
TxOperations,
|
||||
WithLookup,
|
||||
WorkspaceIdWithUrl,
|
||||
WorkspaceUuid,
|
||||
type Blob
|
||||
} from '@hcengineering/core'
|
||||
import { LiveQuery } from '@hcengineering/query'
|
||||
@@ -83,9 +83,10 @@ export interface ContainerFocus {
|
||||
export interface IntegrationManager {
|
||||
liveQuery: LiveQuery
|
||||
getContainer: (space: Ref<Space>) => Promise<ContainerFocus | undefined>
|
||||
getAccount: (user?: UserInfo | null) => Promise<PersonAccount | undefined>
|
||||
getAccountU: (user: User) => Promise<PersonAccount | undefined>
|
||||
getOctokit: (account: Ref<PersonAccount>) => Promise<Octokit | undefined>
|
||||
// TODO: FIXME
|
||||
getAccount: (user?: UserInfo | null) => Promise<any | undefined>
|
||||
getAccountU: (user: User) => Promise<any | undefined>
|
||||
getOctokit: (account: PersonId) => Promise<Octokit | undefined>
|
||||
getMarkup: (
|
||||
container: IntegrationContainer,
|
||||
text?: string | null,
|
||||
@@ -112,7 +113,8 @@ export interface IntegrationManager {
|
||||
) => Promise<void>
|
||||
|
||||
doSyncFor: (docs: DocSyncInfo[], project: GithubProject) => Promise<void>
|
||||
getWorkspaceId: () => WorkspaceIdWithUrl
|
||||
getWorkspaceId: () => WorkspaceUuid
|
||||
getWorkspaceUrl: () => string
|
||||
getBranding: () => Branding | null
|
||||
|
||||
getProjectAndRepository: (
|
||||
@@ -124,7 +126,7 @@ export interface IntegrationManager {
|
||||
body: string
|
||||
) => Promise<{ markdownCompatible: boolean, markdown: string }>
|
||||
|
||||
isPlatformUser: (account: Ref<PersonAccount>) => Promise<boolean>
|
||||
isPlatformUser: (account: PersonId) => Promise<boolean>
|
||||
|
||||
getRepositoryById: (ref?: Ref<GithubIntegrationRepository> | null) => Promise<GithubIntegrationRepository | undefined>
|
||||
|
||||
@@ -188,7 +190,7 @@ export interface DocSyncManager {
|
||||
export interface GithubIntegrationRecord {
|
||||
installationId: number
|
||||
workspace: string
|
||||
accountId: Ref<Account>
|
||||
accountId: PersonId
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,5 +208,5 @@ export interface GithubUserRecord {
|
||||
scope?: string
|
||||
error?: string | null
|
||||
|
||||
accounts: Record<string, Ref<Account>>
|
||||
accounts: Record<string, PersonId>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Account, Ref } from '@hcengineering/core'
|
||||
import type { PersonId } from '@hcengineering/core'
|
||||
import type { Collection, FindCursor } from 'mongodb'
|
||||
import type { GithubUserRecord } from './types'
|
||||
|
||||
@@ -31,7 +31,7 @@ export class UserManager {
|
||||
return res
|
||||
}
|
||||
|
||||
async getAccountByRef (workspace: string, ref: Ref<Account>): Promise<GithubUserRecord | undefined> {
|
||||
async getAccountByRef (workspace: string, ref: PersonId): Promise<GithubUserRecord | undefined> {
|
||||
const key = `${workspace}.${ref}`
|
||||
let rec = this.refUserCache.get(key)
|
||||
if (rec !== undefined) {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import chunter from '@hcengineering/chunter'
|
||||
import { CollaboratorClient } from '@hcengineering/collaborator-client'
|
||||
import contact, { AvatarType, Person, PersonAccount } from '@hcengineering/contact'
|
||||
import contact, { AvatarType, Person } from '@hcengineering/contact'
|
||||
import core, {
|
||||
Account,
|
||||
PersonId,
|
||||
AccountRole,
|
||||
AttachedDoc,
|
||||
Branding,
|
||||
@@ -28,7 +29,7 @@ import core, {
|
||||
TxWorkspaceEvent,
|
||||
WithLookup,
|
||||
WorkspaceEvent,
|
||||
WorkspaceIdWithUrl,
|
||||
WorkspaceUuid,
|
||||
concatLink,
|
||||
generateId,
|
||||
groupByArray,
|
||||
@@ -36,7 +37,9 @@ import core, {
|
||||
toIdMap,
|
||||
type Blob,
|
||||
type MigrationState,
|
||||
type TimeRateLimiter
|
||||
type TimeRateLimiter,
|
||||
type WorkspaceIds,
|
||||
type WorkspaceDataId
|
||||
} from '@hcengineering/core'
|
||||
import github, {
|
||||
DocSyncInfo,
|
||||
@@ -86,6 +89,10 @@ import {
|
||||
githubSyncVersion
|
||||
} from './types'
|
||||
import { equalExceptKeys } from './utils'
|
||||
|
||||
// TODO: FIXME
|
||||
type PersonAccount = any
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@@ -97,7 +104,8 @@ export class GithubWorker implements IntegrationManager {
|
||||
|
||||
triggerRequests: number = 0
|
||||
|
||||
authRequestSend = new Set<Ref<Account>>()
|
||||
// TODO: FIXME
|
||||
authRequestSend = new Set<any>()
|
||||
|
||||
triggerSync: () => void = () => {
|
||||
this.triggerRequests++
|
||||
@@ -128,11 +136,11 @@ export class GithubWorker implements IntegrationManager {
|
||||
clearInterval(this.periodicTimer)
|
||||
|
||||
this.closing = true
|
||||
this.ctx.warn('Closing', { workspace: this.workspace.name })
|
||||
this.ctx.warn('Closing', { workspace: this.workspace })
|
||||
this.triggerSync()
|
||||
await Promise.all([await this.syncPromise, new Promise<void>((resolve) => setTimeout(resolve, 5000))])
|
||||
|
||||
this.ctx.warn('Closing Done', { workspace: this.workspace.name })
|
||||
this.ctx.warn('Closing Done', { workspace: this.workspace })
|
||||
await this.client.close()
|
||||
}
|
||||
|
||||
@@ -140,8 +148,12 @@ export class GithubWorker implements IntegrationManager {
|
||||
await this.liveQuery.refreshConnect(clean)
|
||||
}
|
||||
|
||||
getWorkspaceId (): WorkspaceIdWithUrl {
|
||||
return this.workspace
|
||||
getWorkspaceId (): WorkspaceUuid {
|
||||
return this.workspace.uuid
|
||||
}
|
||||
|
||||
getWorkspaceUrl (): string {
|
||||
return this.workspace.url
|
||||
}
|
||||
|
||||
getBranding (): Branding | null {
|
||||
@@ -174,9 +186,9 @@ export class GithubWorker implements IntegrationManager {
|
||||
return ''
|
||||
}
|
||||
const frontUrl = this.getBranding()?.front ?? config.FrontURL
|
||||
const refUrl = concatLink(frontUrl, `/browse/?workspace=${this.workspace.name}`)
|
||||
const refUrl = concatLink(frontUrl, `/browse/?workspace=${this.workspace.uuid}`)
|
||||
// TODO storage URL
|
||||
const imageUrl = concatLink(frontUrl ?? config.FrontURL, `/files?workspace=${this.workspace.name}&file=`)
|
||||
const imageUrl = concatLink(frontUrl ?? config.FrontURL, `/files?workspace=${this.workspace.uuid}&file=`)
|
||||
const guestUrl = getPublicLinkUrl(this.workspace, frontUrl)
|
||||
const json = parseMessageMarkdown(text ?? '', refUrl, imageUrl, guestUrl)
|
||||
await preprocessor?.(json)
|
||||
@@ -189,9 +201,9 @@ export class GithubWorker implements IntegrationManager {
|
||||
}
|
||||
return await markupToMarkdown(
|
||||
text ?? '',
|
||||
concatLink(this.getBranding()?.front ?? config.FrontURL, `/browse/?workspace=${this.workspace.name}`),
|
||||
concatLink(this.getBranding()?.front ?? config.FrontURL, `/browse/?workspace=${this.workspace.uuid}`),
|
||||
// TODO storage URL
|
||||
concatLink(this.getBranding()?.front ?? config.FrontURL, `/files/${this.workspace.name}/`),
|
||||
concatLink(this.getBranding()?.front ?? config.FrontURL, `/files/${this.workspace.uuid}/`),
|
||||
preprocessor
|
||||
)
|
||||
}
|
||||
@@ -251,79 +263,81 @@ export class GithubWorker implements IntegrationManager {
|
||||
}
|
||||
|
||||
async _getAccountRaw (userInfo?: UserInfo | null): Promise<PersonAccount | undefined> {
|
||||
// We need to sync by userInfo id to prevent parallel requests.
|
||||
if (userInfo === null) {
|
||||
// Ghost author.
|
||||
return await this.getAccount({
|
||||
id: 'ghost',
|
||||
login: 'ghost',
|
||||
avatarUrl: 'https://avatars.githubusercontent.com/u/10137?v=4',
|
||||
email: '<EMAIL>',
|
||||
name: 'Ghost'
|
||||
})
|
||||
}
|
||||
if (userInfo?.login == null) {
|
||||
return
|
||||
}
|
||||
const userName = (userInfo.name ?? userInfo.login)
|
||||
.split(' ')
|
||||
.map((it) => it.trim())
|
||||
.reverse()
|
||||
.join(',') // TODO: Convert first, last name
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// // We need to sync by userInfo id to prevent parallel requests.
|
||||
// if (userInfo === null) {
|
||||
// // Ghost author.
|
||||
// return await this.getAccount({
|
||||
// id: 'ghost',
|
||||
// login: 'ghost',
|
||||
// avatarUrl: 'https://avatars.githubusercontent.com/u/10137?v=4',
|
||||
// email: '<EMAIL>',
|
||||
// name: 'Ghost'
|
||||
// })
|
||||
// }
|
||||
// if (userInfo?.login == null) {
|
||||
// return
|
||||
// }
|
||||
// const userName = (userInfo.name ?? userInfo.login)
|
||||
// .split(' ')
|
||||
// .map((it) => it.trim())
|
||||
// .reverse()
|
||||
// .join(',') // TODO: Convert first, last name
|
||||
|
||||
const infos = await this.liveQuery.findOne(github.class.GithubUserInfo, { login: userInfo.login })
|
||||
if (infos === undefined) {
|
||||
await this._client.createDoc(github.class.GithubUserInfo, contact.space.Contacts, {
|
||||
...userInfo
|
||||
})
|
||||
}
|
||||
// const infos = await this.liveQuery.findOne(github.class.GithubUserInfo, { login: userInfo.login })
|
||||
// if (infos === undefined) {
|
||||
// await this._client.createDoc(github.class.GithubUserInfo, contact.space.Contacts, {
|
||||
// ...userInfo
|
||||
// })
|
||||
// }
|
||||
|
||||
const account = await this.client
|
||||
.getModel()
|
||||
.findOne(contact.class.PersonAccount, { email: `github:${userInfo.login}` })
|
||||
if (account !== undefined) {
|
||||
const person = await this.liveQuery.findOne(contact.class.Person, { _id: account.person })
|
||||
// We need to be sure employee are exists.
|
||||
if (person === undefined) {
|
||||
const person: Ref<Person> = await this.findPerson(userInfo, userName)
|
||||
if (account.person !== person) {
|
||||
await this._client.update(account, { person })
|
||||
}
|
||||
}
|
||||
return account
|
||||
} else {
|
||||
// Check authorized users
|
||||
const accountRecord = await this.platform.getAccount(userInfo.login)
|
||||
if (accountRecord !== undefined) {
|
||||
const authorizedId = accountRecord.accounts[this.workspace.name]
|
||||
if (authorizedId !== undefined) {
|
||||
const emp = await this._client.findOne(contact.class.PersonAccount, {
|
||||
_id: authorizedId as Ref<PersonAccount>
|
||||
})
|
||||
if (emp !== undefined) {
|
||||
// We need to create github account
|
||||
const gid = await this._client.createDoc(contact.class.PersonAccount, core.space.Model, {
|
||||
email: `github:${userInfo.login}`,
|
||||
person: emp.person,
|
||||
role: AccountRole.User
|
||||
})
|
||||
const acc = await this._client.findOne(contact.class.PersonAccount, { _id: gid })
|
||||
return acc
|
||||
}
|
||||
}
|
||||
}
|
||||
// const account = await this.client
|
||||
// .getModel()
|
||||
// .findOne(contact.class.PersonAccount, { email: `github:${userInfo.login}` })
|
||||
// if (account !== undefined) {
|
||||
// const person = await this.liveQuery.findOne(contact.class.Person, { _id: account.person })
|
||||
// // We need to be sure employee are exists.
|
||||
// if (person === undefined) {
|
||||
// const person: Ref<Person> = await this.findPerson(userInfo, userName)
|
||||
// if (account.person !== person) {
|
||||
// await this._client.update(account, { person })
|
||||
// }
|
||||
// }
|
||||
// return account
|
||||
// } else {
|
||||
// // Check authorized users
|
||||
// const accountRecord = await this.platform.getAccount(userInfo.login)
|
||||
// if (accountRecord !== undefined) {
|
||||
// const authorizedId = accountRecord.accounts[this.workspace.name]
|
||||
// if (authorizedId !== undefined) {
|
||||
// const emp = await this._client.findOne(contact.class.PersonAccount, {
|
||||
// _id: authorizedId as Ref<PersonAccount>
|
||||
// })
|
||||
// if (emp !== undefined) {
|
||||
// // We need to create github account
|
||||
// const gid = await this._client.createDoc(contact.class.PersonAccount, core.space.Model, {
|
||||
// email: `github:${userInfo.login}`,
|
||||
// person: emp.person,
|
||||
// role: AccountRole.User
|
||||
// })
|
||||
// const acc = await this._client.findOne(contact.class.PersonAccount, { _id: gid })
|
||||
// return acc
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
const person: Ref<Person> | undefined = await this.findPerson(userInfo, userName)
|
||||
// const person: Ref<Person> | undefined = await this.findPerson(userInfo, userName)
|
||||
|
||||
// We need to create email account
|
||||
const id = await this._client.createDoc(contact.class.PersonAccount, core.space.Model, {
|
||||
email: `github:${userInfo.login}`,
|
||||
person,
|
||||
role: AccountRole.User
|
||||
})
|
||||
const acc = await this.client.getModel().findOne(contact.class.PersonAccount, { _id: id })
|
||||
return acc
|
||||
}
|
||||
// // We need to create email account
|
||||
// const id = await this._client.createDoc(contact.class.PersonAccount, core.space.Model, {
|
||||
// email: `github:${userInfo.login}`,
|
||||
// person,
|
||||
// role: AccountRole.User
|
||||
// })
|
||||
// const acc = await this.client.getModel().findOne(contact.class.PersonAccount, { _id: id })
|
||||
// return acc
|
||||
// }
|
||||
}
|
||||
|
||||
private constructor (
|
||||
@@ -334,7 +348,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
readonly client: Client,
|
||||
readonly app: App,
|
||||
readonly storageAdapter: StorageAdapter,
|
||||
readonly workspace: WorkspaceIdWithUrl,
|
||||
readonly workspace: WorkspaceIds,
|
||||
readonly branding: Branding | null,
|
||||
readonly periodicSyncInterval = 60 * 60 * 1000
|
||||
) {
|
||||
@@ -343,7 +357,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
|
||||
this.repositoryManager = new RepositorySyncMapper(this.ctx.newChild('repository', {}), this._client, this.app)
|
||||
|
||||
this.collaborator = createCollaboratorClient(this.workspace)
|
||||
this.collaborator = createCollaboratorClient(this.workspace.uuid)
|
||||
|
||||
this.personMapper = new UsersSyncManager(this.ctx.newChild('users', {}), this._client, this.liveQuery)
|
||||
|
||||
@@ -370,10 +384,11 @@ export class GithubWorker implements IntegrationManager {
|
||||
_class: [chunter.class.ChatMessage],
|
||||
mapper: new CommentSyncManager(this.ctx.newChild('comment', {}), this._client, this.liveQuery)
|
||||
},
|
||||
{
|
||||
_class: [contact.class.PersonAccount],
|
||||
mapper: this.personMapper
|
||||
},
|
||||
// TODO: FIXME
|
||||
// {
|
||||
// _class: [contact.class.PersonAccount],
|
||||
// mapper: this.personMapper
|
||||
// },
|
||||
{
|
||||
_class: [github.class.GithubReview],
|
||||
mapper: new ReviewSyncManager(this.ctx.newChild('review', {}), this._client, this.liveQuery)
|
||||
@@ -407,219 +422,228 @@ export class GithubWorker implements IntegrationManager {
|
||||
this.periodicSyncPromise = undefined
|
||||
}
|
||||
|
||||
private async findPerson (userInfo: UserInfo, userName: string): Promise<Ref<Person>> {
|
||||
let person: Ref<Person> | undefined
|
||||
// try to find by account.
|
||||
if (userInfo.email != null && userInfo.email.trim().length > 0) {
|
||||
const personAccount = await this.client.getModel().findOne(contact.class.PersonAccount, { email: userInfo.email })
|
||||
person = personAccount?.person
|
||||
}
|
||||
// private async findPerson (userInfo: UserInfo, userName: string): Promise<Ref<Person>> {
|
||||
// let person: Ref<Person> | undefined
|
||||
// // try to find by account.
|
||||
// if (userInfo.email != null && userInfo.email.trim().length > 0) {
|
||||
// const personAccount = await this.client.getModel().findOne(contact.class.PersonAccount, { email: userInfo.email })
|
||||
// person = personAccount?.person
|
||||
// }
|
||||
|
||||
if (person === undefined) {
|
||||
const channel = await this.liveQuery.findOne(contact.class.Channel, {
|
||||
provider: contact.channelProvider.GitHub,
|
||||
value: userInfo.login
|
||||
})
|
||||
person = channel?.attachedTo as Ref<Person>
|
||||
}
|
||||
// if (person === undefined) {
|
||||
// const channel = await this.liveQuery.findOne(contact.class.Channel, {
|
||||
// provider: contact.channelProvider.GitHub,
|
||||
// value: userInfo.login
|
||||
// })
|
||||
// person = channel?.attachedTo as Ref<Person>
|
||||
// }
|
||||
|
||||
if (person === undefined) {
|
||||
// We need to create some person to identify this account.
|
||||
person = await this._client.createDoc(contact.class.Person, contact.space.Contacts, {
|
||||
name: userName,
|
||||
avatarType: AvatarType.EXTERNAL,
|
||||
avatarProps: { url: userInfo.avatarUrl },
|
||||
city: '',
|
||||
comments: 0,
|
||||
channels: 0,
|
||||
attachments: 0
|
||||
})
|
||||
await this._client.addCollection(
|
||||
contact.class.Channel,
|
||||
contact.space.Contacts,
|
||||
person,
|
||||
contact.class.Person,
|
||||
'channels',
|
||||
{
|
||||
provider: contact.channelProvider.GitHub,
|
||||
value: userInfo.login
|
||||
}
|
||||
)
|
||||
if (userInfo.email != null && userInfo.email.trim() !== '') {
|
||||
await this._client.addCollection(
|
||||
contact.class.Channel,
|
||||
contact.space.Contacts,
|
||||
person,
|
||||
contact.class.Person,
|
||||
'channels',
|
||||
{
|
||||
provider: contact.channelProvider.Email,
|
||||
value: userInfo.email
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
return person
|
||||
}
|
||||
// if (person === undefined) {
|
||||
// // We need to create some person to identify this account.
|
||||
// person = await this._client.createDoc(contact.class.Person, contact.space.Contacts, {
|
||||
// name: userName,
|
||||
// avatarType: AvatarType.EXTERNAL,
|
||||
// avatarProps: { url: userInfo.avatarUrl },
|
||||
// city: '',
|
||||
// comments: 0,
|
||||
// channels: 0,
|
||||
// attachments: 0
|
||||
// })
|
||||
// await this._client.addCollection(
|
||||
// contact.class.Channel,
|
||||
// contact.space.Contacts,
|
||||
// person,
|
||||
// contact.class.Person,
|
||||
// 'channels',
|
||||
// {
|
||||
// provider: contact.channelProvider.GitHub,
|
||||
// value: userInfo.login
|
||||
// }
|
||||
// )
|
||||
// if (userInfo.email != null && userInfo.email.trim() !== '') {
|
||||
// await this._client.addCollection(
|
||||
// contact.class.Channel,
|
||||
// contact.space.Contacts,
|
||||
// person,
|
||||
// contact.class.Person,
|
||||
// 'channels',
|
||||
// {
|
||||
// provider: contact.channelProvider.Email,
|
||||
// value: userInfo.email
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// return person
|
||||
// }
|
||||
|
||||
async getGithubLogin (container: IntegrationContainer, person: Ref<Person>): Promise<UserInfo | undefined> {
|
||||
const accounts = this.client.getModel().findAllSync(contact.class.PersonAccount, {})
|
||||
const acc = accounts.find((it) => it.person === person && it.email.startsWith('github:'))
|
||||
if (acc === undefined) {
|
||||
return // Nobody, will use system account.
|
||||
}
|
||||
const login = acc.email.substring(7)
|
||||
let info = await this.liveQuery.findOne(github.class.GithubUserInfo, { login })
|
||||
if (info === undefined) {
|
||||
// We need to retrieve info for login
|
||||
const response: any = await container.octokit?.graphql(
|
||||
`query($login: String!) {
|
||||
user(login: $login) {
|
||||
id
|
||||
email
|
||||
login
|
||||
name
|
||||
avatarUrl
|
||||
}
|
||||
}`,
|
||||
{
|
||||
login
|
||||
}
|
||||
)
|
||||
|
||||
info = response.user
|
||||
await this._client.createDoc(github.class.GithubUserInfo, contact.space.Contacts, info as Data<GithubUserInfo>)
|
||||
}
|
||||
return info
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// const accounts = this.client.getModel().findAllSync(contact.class.PersonAccount, {})
|
||||
// const acc = accounts.find((it) => it.person === person && it.email.startsWith('github:'))
|
||||
// if (acc === undefined) {
|
||||
// return // Nobody, will use system account.
|
||||
// }
|
||||
// const login = acc.email.substring(7)
|
||||
// let info = await this.liveQuery.findOne(github.class.GithubUserInfo, { login })
|
||||
// if (info === undefined) {
|
||||
// // We need to retrieve info for login
|
||||
// const response: any = await container.octokit?.graphql(
|
||||
// `query($login: String!) {
|
||||
// user(login: $login) {
|
||||
// id
|
||||
// email
|
||||
// login
|
||||
// name
|
||||
// avatarUrl
|
||||
// }
|
||||
// }`,
|
||||
// {
|
||||
// login
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// info = response.user
|
||||
// await this._client.createDoc(github.class.GithubUserInfo, contact.space.Contacts, info as Data<GithubUserInfo>)
|
||||
// }
|
||||
// return info
|
||||
}
|
||||
|
||||
async syncUserData (ctx: MeasureContext, users: GithubUserRecord[]): Promise<void> {
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// Let's sync information about users and send some details
|
||||
const accounts = await this._client.findAll(contact.class.PersonAccount, {
|
||||
email: { $in: users.map((it) => `github:${it._id}`) }
|
||||
})
|
||||
const userAuths = await this._client.findAll(github.class.GithubAuthentication, {})
|
||||
const persons = await this._client.findAll(contact.class.Person, { _id: { $in: accounts.map((it) => it.person) } })
|
||||
for (const record of users) {
|
||||
if (record.error !== undefined) {
|
||||
// Skip accounts with error
|
||||
continue
|
||||
}
|
||||
const account = accounts.find((it) => it.email === `github:${record._id}`)
|
||||
const userAuth = userAuths.find((it) => it.login === record._id)
|
||||
const person = persons.find((it) => account?.person)
|
||||
if (account === undefined || userAuth === undefined || person === undefined) {
|
||||
continue
|
||||
}
|
||||
const accountRef = record.accounts[this.workspace.name]
|
||||
try {
|
||||
await this.platform.checkRefreshToken(record, true)
|
||||
// const accounts = await this._client.findAll(contact.class.PersonAccount, {
|
||||
// email: { $in: users.map((it) => `github:${it._id}`) }
|
||||
// })
|
||||
// const userAuths = await this._client.findAll(github.class.GithubAuthentication, {})
|
||||
// const persons = await this._client.findAll(contact.class.Person, { _id: { $in: accounts.map((it) => it.person) } })
|
||||
// for (const record of users) {
|
||||
// if (record.error !== undefined) {
|
||||
// // Skip accounts with error
|
||||
// continue
|
||||
// }
|
||||
// const account = accounts.find((it) => it.email === `github:${record._id}`)
|
||||
// const userAuth = userAuths.find((it) => it.login === record._id)
|
||||
// const person = persons.find((it) => account?.person)
|
||||
// if (account === undefined || userAuth === undefined || person === undefined) {
|
||||
// continue
|
||||
// }
|
||||
// const accountRef = record.accounts[this.workspace.name]
|
||||
// try {
|
||||
// await this.platform.checkRefreshToken(record, true)
|
||||
|
||||
const ops = new TxOperations(this.client, accountRef)
|
||||
await syncUser(ctx, record, userAuth, ops, accountRef)
|
||||
} catch (err: any) {
|
||||
try {
|
||||
await this.platform.revokeUserAuth(record)
|
||||
} catch (err: any) {
|
||||
ctx.error(`Failed to revoke user ${record._id}`, err)
|
||||
}
|
||||
if (err.response?.data?.message !== 'Bad credentials') {
|
||||
ctx.error(`Failed to sync user ${record._id}`, err)
|
||||
Analytics.handleError(err)
|
||||
}
|
||||
if (userAuth !== undefined) {
|
||||
await this._client.update<GithubAuthentication>(
|
||||
userAuth,
|
||||
{
|
||||
error: errorToObj(err)
|
||||
},
|
||||
undefined,
|
||||
Date.now(),
|
||||
accountRef
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// const ops = new TxOperations(this.client, accountRef)
|
||||
// await syncUser(ctx, record, userAuth, ops, accountRef)
|
||||
// } catch (err: any) {
|
||||
// try {
|
||||
// await this.platform.revokeUserAuth(record)
|
||||
// } catch (err: any) {
|
||||
// ctx.error(`Failed to revoke user ${record._id}`, err)
|
||||
// }
|
||||
// if (err.response?.data?.message !== 'Bad credentials') {
|
||||
// ctx.error(`Failed to sync user ${record._id}`, err)
|
||||
// Analytics.handleError(err)
|
||||
// }
|
||||
// if (userAuth !== undefined) {
|
||||
// await this._client.update<GithubAuthentication>(
|
||||
// userAuth,
|
||||
// {
|
||||
// error: errorToObj(err)
|
||||
// },
|
||||
// undefined,
|
||||
// Date.now(),
|
||||
// accountRef
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
async getOctokit (account: Ref<PersonAccount>): Promise<Octokit | undefined> {
|
||||
let record = await this.platform.getAccountByRef(this.workspace.name, account)
|
||||
async getOctokit (account: PersonId): Promise<Octokit | undefined> {
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// let record = await this.platform.getAccountByRef(this.workspace.name, account)
|
||||
|
||||
// const accountRef = this.accounts.find((it) => it._id === account)
|
||||
const [accountRef] = this.client.getModel().findAllSync(contact.class.PersonAccount, { _id: account })
|
||||
if (record === undefined) {
|
||||
if (accountRef !== undefined) {
|
||||
const accounts = this._client.getModel().getAccountByPersonId(accountRef.person)
|
||||
for (const aa of accounts) {
|
||||
record = await this.platform.getAccountByRef(this.workspace.name, aa._id)
|
||||
if (record !== undefined) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check and refresh token if required.
|
||||
if (record !== undefined) {
|
||||
this.ctx.info('get octokit', { account, recordId: record._id, workspace: this.workspace.name })
|
||||
await this.platform.checkRefreshToken(record)
|
||||
return new Octokit({
|
||||
auth: record.token,
|
||||
client_id: config.ClientID,
|
||||
client_secret: config.ClientSecret
|
||||
})
|
||||
}
|
||||
// const [accountRef] = this.client.getModel().findAllSync(contact.class.PersonAccount, { _id: account })
|
||||
// if (record === undefined) {
|
||||
// if (accountRef !== undefined) {
|
||||
// const accounts = this._client.getModel().getAccountByPersonId(accountRef.person)
|
||||
// for (const aa of accounts) {
|
||||
// record = await this.platform.getAccountByRef(this.workspace.name, aa._id)
|
||||
// if (record !== undefined) {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Check and refresh token if required.
|
||||
// if (record !== undefined) {
|
||||
// this.ctx.info('get octokit', { account, recordId: record._id, workspace: this.workspace.name })
|
||||
// await this.platform.checkRefreshToken(record)
|
||||
// return new Octokit({
|
||||
// auth: record.token,
|
||||
// client_id: config.ClientID,
|
||||
// client_secret: config.ClientSecret
|
||||
// })
|
||||
// }
|
||||
|
||||
// We need to inform user, he need to authorize this account with github.
|
||||
if (accountRef !== undefined && !this.authRequestSend.has(accountRef._id)) {
|
||||
this.authRequestSend.add(accountRef._id)
|
||||
const person = await this.liveQuery.findOne(contact.class.Person, { _id: accountRef.person })
|
||||
if (person !== undefined) {
|
||||
const personSpace = await this.liveQuery.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
if (personSpace !== undefined) {
|
||||
// We need to remove if user has authentication in workspace but doesn't have a record.
|
||||
// // We need to inform user, he need to authorize this account with github.
|
||||
// if (accountRef !== undefined && !this.authRequestSend.has(accountRef._id)) {
|
||||
// this.authRequestSend.add(accountRef._id)
|
||||
// const person = await this.liveQuery.findOne(contact.class.Person, { _id: accountRef.person })
|
||||
// if (person !== undefined) {
|
||||
// const personSpace = await this.liveQuery.findOne(contact.class.PersonSpace, { person: person._id })
|
||||
// if (personSpace !== undefined) {
|
||||
// // We need to remove if user has authentication in workspace but doesn't have a record.
|
||||
|
||||
const accounts = this._client.getModel().getAccountByPersonId(accountRef.person)
|
||||
const authentications = await this.liveQuery.findAll(github.class.GithubAuthentication, {
|
||||
createdBy: { $in: accounts.map((it) => it._id) }
|
||||
})
|
||||
for (const auth of authentications) {
|
||||
await this._client.remove(auth)
|
||||
}
|
||||
// const accounts = this._client.getModel().getAccountByPersonId(accountRef.person)
|
||||
// const authentications = await this.liveQuery.findAll(github.class.GithubAuthentication, {
|
||||
// createdBy: { $in: accounts.map((it) => it._id) }
|
||||
// })
|
||||
// for (const auth of authentications) {
|
||||
// await this._client.remove(auth)
|
||||
// }
|
||||
|
||||
await createNotification(this._client, person, {
|
||||
user: account,
|
||||
space: personSpace._id,
|
||||
message: github.string.AuthenticatedWithGithubRequired,
|
||||
props: {}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
this.ctx.info('get octokit: return bot', { account, workspace: this.workspace.name })
|
||||
// await createNotification(this._client, person, {
|
||||
// user: account,
|
||||
// space: personSpace._id,
|
||||
// message: github.string.AuthenticatedWithGithubRequired,
|
||||
// props: {}
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// this.ctx.info('get octokit: return bot', { account, workspace: this.workspace.name })
|
||||
}
|
||||
|
||||
async isPlatformUser (account: Ref<PersonAccount>): Promise<boolean> {
|
||||
let record = await this.platform.getAccountByRef(this.workspace.name, account)
|
||||
const accountRef = await this.liveQuery.findOne(contact.class.PersonAccount, { _id: account })
|
||||
if (record === undefined) {
|
||||
if (accountRef !== undefined) {
|
||||
const accounts = this._client.getModel().getAccountByPersonId(accountRef.person)
|
||||
for (const aa of accounts) {
|
||||
record = await this.platform.getAccountByRef(this.workspace.name, aa._id)
|
||||
if (record !== undefined) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check and refresh token if required.
|
||||
return record !== undefined && accountRef !== undefined
|
||||
async isPlatformUser (account: PersonId): Promise<boolean> {
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// let record = await this.platform.getAccountByRef(this.workspace.name, account)
|
||||
// const accountRef = await this.liveQuery.findOne(contact.class.PersonAccount, { _id: account })
|
||||
// if (record === undefined) {
|
||||
// if (accountRef !== undefined) {
|
||||
// const accounts = this._client.getModel().getAccountByPersonId(accountRef.person)
|
||||
// for (const aa of accounts) {
|
||||
// record = await this.platform.getAccountByRef(this.workspace.name, aa._id)
|
||||
// if (record !== undefined) {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Check and refresh token if required.
|
||||
// return record !== undefined && accountRef !== undefined
|
||||
}
|
||||
|
||||
async uploadFile (patch: string, file?: string, contentType?: string): Promise<Blob | undefined> {
|
||||
const id: string = file ?? generateId()
|
||||
await this.storageAdapter.put(this.ctx, this.workspace, id, patch, contentType ?? 'text/x-patch')
|
||||
return await this.storageAdapter.stat(this.ctx, this.workspace, id)
|
||||
const dataId = this.workspace.dataId ?? (this.workspace.uuid as unknown as WorkspaceDataId)
|
||||
await this.storageAdapter.put(this.ctx, dataId, id, patch, contentType ?? 'text/x-patch')
|
||||
return await this.storageAdapter.stat(this.ctx, dataId, id)
|
||||
}
|
||||
|
||||
integrationRepositories: WithLookup<GithubIntegrationRepository>[] = []
|
||||
@@ -729,7 +753,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
this.updateRequests = 1
|
||||
this.syncPromise = this.syncAndWait()
|
||||
|
||||
const userRecords = await this.platform.getUsers(this.workspace.name)
|
||||
const userRecords = await this.platform.getUsers(this.workspace.uuid)
|
||||
try {
|
||||
await this.syncUserData(this.ctx, userRecords)
|
||||
} catch (err: any) {
|
||||
@@ -850,57 +874,59 @@ export class GithubWorker implements IntegrationManager {
|
||||
}
|
||||
|
||||
private async queryAccounts (): Promise<void> {
|
||||
const updateAccounts = async (accounts: PersonAccount[]): Promise<void> => {
|
||||
const persons = await this.liveQuery.findAll(contact.class.Person, {
|
||||
_id: { $in: accounts.map((it) => it.person) }
|
||||
})
|
||||
const h = this.client.getHierarchy()
|
||||
for (const a of accounts) {
|
||||
if (a.email.startsWith('github:')) {
|
||||
const login = a.email.substring(7)
|
||||
const person = persons.find((it) => it._id === a.person)
|
||||
if (person !== undefined) {
|
||||
// #1 check if person has GithubUser mixin.
|
||||
if (!h.hasMixin(person, github.mixin.GithubUser)) {
|
||||
await this._client.createMixin(person._id, person._class, person.space, github.mixin.GithubUser, {
|
||||
url: `https://github.com/${login}`
|
||||
})
|
||||
} else {
|
||||
const ghu = h.as(person, github.mixin.GithubUser)
|
||||
if (ghu.url !== `https://github.com/${login}`) {
|
||||
await this._client.updateMixin(person._id, person._class, person.space, github.mixin.GithubUser, {
|
||||
url: `https://github.com/${login}`
|
||||
})
|
||||
}
|
||||
}
|
||||
// #2 check if person has contact github and if not add it.
|
||||
const channel = await this._client.findOne(contact.class.Channel, {
|
||||
provider: contact.channelProvider.GitHub,
|
||||
value: login,
|
||||
attachedTo: person._id
|
||||
})
|
||||
if (channel === undefined) {
|
||||
await this._client.addCollection(
|
||||
contact.class.Channel,
|
||||
person.space,
|
||||
person._id,
|
||||
contact.class.Person,
|
||||
'channels',
|
||||
{
|
||||
provider: contact.channelProvider.GitHub,
|
||||
value: login
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
this.liveQuery.query(contact.class.PersonAccount, {}, (res) => {
|
||||
void updateAccounts(res).then(resolve).catch(reject)
|
||||
})
|
||||
})
|
||||
// TODO: FIXME
|
||||
throw new Error('Not implemented')
|
||||
// const updateAccounts = async (accounts: PersonAccount[]): Promise<void> => {
|
||||
// const persons = await this.liveQuery.findAll(contact.class.Person, {
|
||||
// _id: { $in: accounts.map((it) => it.person) }
|
||||
// })
|
||||
// const h = this.client.getHierarchy()
|
||||
// for (const a of accounts) {
|
||||
// if (a.email.startsWith('github:')) {
|
||||
// const login = a.email.substring(7)
|
||||
// const person = persons.find((it) => it._id === a.person)
|
||||
// if (person !== undefined) {
|
||||
// // #1 check if person has GithubUser mixin.
|
||||
// if (!h.hasMixin(person, github.mixin.GithubUser)) {
|
||||
// await this._client.createMixin(person._id, person._class, person.space, github.mixin.GithubUser, {
|
||||
// url: `https://github.com/${login}`
|
||||
// })
|
||||
// } else {
|
||||
// const ghu = h.as(person, github.mixin.GithubUser)
|
||||
// if (ghu.url !== `https://github.com/${login}`) {
|
||||
// await this._client.updateMixin(person._id, person._class, person.space, github.mixin.GithubUser, {
|
||||
// url: `https://github.com/${login}`
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// // #2 check if person has contact github and if not add it.
|
||||
// const channel = await this._client.findOne(contact.class.Channel, {
|
||||
// provider: contact.channelProvider.GitHub,
|
||||
// value: login,
|
||||
// attachedTo: person._id
|
||||
// })
|
||||
// if (channel === undefined) {
|
||||
// await this._client.addCollection(
|
||||
// contact.class.Channel,
|
||||
// person.space,
|
||||
// person._id,
|
||||
// contact.class.Person,
|
||||
// 'channels',
|
||||
// {
|
||||
// provider: contact.channelProvider.GitHub,
|
||||
// value: login
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// await new Promise<void>((resolve, reject) => {
|
||||
// this.liveQuery.query(contact.class.PersonAccount, {}, (res) => {
|
||||
// void updateAccounts(res).then(resolve).catch(reject)
|
||||
// })
|
||||
// })
|
||||
}
|
||||
|
||||
async performExternalSync (
|
||||
@@ -960,7 +986,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
field,
|
||||
version,
|
||||
docs: docs.length,
|
||||
workspace: this.workspace.name
|
||||
workspace: this.workspace.uuid
|
||||
})
|
||||
|
||||
const byClass = this.groupByClass(docs)
|
||||
@@ -1128,7 +1154,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
|
||||
if (!hadExternalChanges && !hadSyncChanges && !hadDerivedChanges) {
|
||||
if (this.previousWait !== 0) {
|
||||
this.ctx.info('Wait for changes:', { previousWait: this.previousWait, workspace: this.workspace.name })
|
||||
this.ctx.info('Wait for changes:', { previousWait: this.previousWait, workspace: this.workspace.uuid })
|
||||
this.previousWait = 0
|
||||
}
|
||||
// Wait until some sync documents will be modified, updated.
|
||||
@@ -1170,7 +1196,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
|
||||
if (docs.length > 0) {
|
||||
this.previousWait += docs.length
|
||||
this.ctx.info('Syncing', { docs: docs.length, workspace: this.workspace.name })
|
||||
this.ctx.info('Syncing', { docs: docs.length, workspace: this.workspace.uuid })
|
||||
|
||||
const bySpace = groupByArray(docs, (it) => it.space)
|
||||
for (const [k, v] of bySpace.entries()) {
|
||||
@@ -1232,7 +1258,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
}
|
||||
|
||||
async checkMapping (): Promise<void> {
|
||||
for (const intgr of this.platform.integrations.filter((it) => it.workspace === this.workspace.name)) {
|
||||
for (const intgr of this.platform.integrations.filter((it) => it.workspace === this.workspace.uuid)) {
|
||||
const integration = await this._client.findOne(github.class.GithubIntegration, {
|
||||
installationId: intgr.installationId
|
||||
})
|
||||
@@ -1298,7 +1324,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
const existing = externalDocs.find((it) => it._id === info._id)
|
||||
const mapper = this.mappers.find((it) => it._class.includes(info.objectClass))?.mapper
|
||||
if (mapper === undefined) {
|
||||
this.ctx.info('No mapper for class', { objectClass: info.objectClass, workspace: this.workspace.name })
|
||||
this.ctx.info('No mapper for class', { objectClass: info.objectClass, workspace: this.workspace.uuid })
|
||||
await derivedClient.update<DocSyncInfo>(info, {
|
||||
needSync: githubSyncVersion
|
||||
})
|
||||
@@ -1371,7 +1397,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
'sync doc',
|
||||
{},
|
||||
(ctx) => mapper.sync(existing, info, parent, derivedClient),
|
||||
{ url: info.url.toLowerCase(), workspace: this.workspace.name }
|
||||
{ url: info.url.toLowerCase(), workspace: this.workspace.uuid }
|
||||
)
|
||||
if (docUpdate !== undefined) {
|
||||
await derivedClient.update(info, docUpdate)
|
||||
@@ -1398,7 +1424,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
this.ctx.info('Trigger check pending:', {
|
||||
requests: this.triggerRequests,
|
||||
updates: this.updateRequests,
|
||||
workspace: this.workspace.name
|
||||
workspace: this.workspace.uuid
|
||||
})
|
||||
this.triggerRequests = 0
|
||||
return
|
||||
@@ -1413,7 +1439,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
triggerTimeout = setTimeout(() => {
|
||||
triggerTimeout = undefined
|
||||
if (was0) {
|
||||
this.ctx.info('Sync triggered', { request: this.triggerRequests, workspace: this.workspace.name })
|
||||
this.ctx.info('Sync triggered', { request: this.triggerRequests, workspace: this.workspace.uuid })
|
||||
}
|
||||
resolve()
|
||||
}, 50) // Small timeout to aggregate few bulk changes.
|
||||
@@ -1427,7 +1453,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
updateTimeout = setTimeout(() => {
|
||||
updateTimeout = undefined
|
||||
if (was0) {
|
||||
this.ctx.info('Sync update triggered', { requests: this.updateRequests, workspace: this.workspace.name })
|
||||
this.ctx.info('Sync update triggered', { requests: this.updateRequests, workspace: this.workspace.uuid })
|
||||
}
|
||||
resolve()
|
||||
}, 50) // Small timeout to aggregate few bulk changes.
|
||||
@@ -1452,7 +1478,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
}
|
||||
await this.ctx.withLog(
|
||||
'external sync',
|
||||
{ installation: integration.installationName, workspace: this.workspace.name },
|
||||
{ installation: integration.installationName, workspace: this.workspace.uuid },
|
||||
async () => {
|
||||
const enabled = integration.enabled && integration.octokit !== undefined
|
||||
|
||||
@@ -1515,7 +1541,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
}
|
||||
await this.ctx.withLog(
|
||||
'external sync',
|
||||
{ _class: _class.join(', '), workspace: this.workspace.name },
|
||||
{ _class: _class.join(', '), workspace: this.workspace.uuid },
|
||||
async () => {
|
||||
await mapper.externalFullSync(integration, derivedClient, _projects, _repositories)
|
||||
}
|
||||
@@ -1565,18 +1591,18 @@ export class GithubWorker implements IntegrationManager {
|
||||
platformWorker: PlatformWorker,
|
||||
ctx: MeasureContext,
|
||||
installations: Map<number, InstallationRecord>,
|
||||
workspace: WorkspaceIdWithUrl,
|
||||
workspace: WorkspaceIds,
|
||||
branding: Branding | null,
|
||||
app: App,
|
||||
storageAdapter: StorageAdapter,
|
||||
reconnect: (workspaceId: string, event: ClientConnectEvent) => void
|
||||
): Promise<GithubWorker | undefined> {
|
||||
ctx.info('Connecting to', { workspace: workspace.workspaceUrl, workspaceId: workspace.workspaceName })
|
||||
ctx.info('Connecting to', { workspace })
|
||||
let client: Client | undefined
|
||||
let endpoint: string | undefined
|
||||
try {
|
||||
;({ client, endpoint } = await createPlatformClient(workspace.name, 30000, async (event: ClientConnectEvent) => {
|
||||
reconnect(workspace.name, event)
|
||||
;({ client, endpoint } = await createPlatformClient(workspace.uuid, 30000, async (event: ClientConnectEvent) => {
|
||||
reconnect(workspace.uuid, event)
|
||||
}))
|
||||
|
||||
await GithubWorker.checkIntegrations(client, installations)
|
||||
@@ -1592,14 +1618,8 @@ export class GithubWorker implements IntegrationManager {
|
||||
workspace,
|
||||
branding
|
||||
)
|
||||
ctx.info('Init worker', { workspace: workspace.workspaceUrl, workspaceId: workspace.workspaceName })
|
||||
void worker.init().catch((err) => {
|
||||
ctx.error('Failed to init worker', {
|
||||
workspace: workspace.workspaceUrl,
|
||||
workspaceId: workspace.workspaceName,
|
||||
error: err
|
||||
})
|
||||
})
|
||||
ctx.info('Init worker', { workspace: workspace.url, workspaceId: workspace.uuid })
|
||||
void worker.init()
|
||||
return worker
|
||||
} catch (err: any) {
|
||||
ctx.error('timeout during to connect', { workspace, error: err })
|
||||
@@ -1624,7 +1644,7 @@ export async function syncUser (
|
||||
record: GithubUserRecord,
|
||||
userAuth: WithLookup<GithubAuthentication>,
|
||||
client: TxOperations,
|
||||
account: Ref<Account>
|
||||
account: PersonId
|
||||
): Promise<void> {
|
||||
const okit = new Octokit({
|
||||
auth: record.token,
|
||||
|
||||
Reference in New Issue
Block a user