Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
c0d6c1a
something like this, now with logging
cdriesler May 5, 2025
f4a45ce
skip already-moved
cdriesler May 7, 2025
520c0ee
log
cdriesler May 7, 2025
68970a9
give victor more power
cdriesler May 7, 2025
ea37c4a
pool stuff
cdriesler May 7, 2025
e014f86
no first projects
cdriesler May 7, 2025
5257e9f
large project trx
cdriesler May 13, 2025
fd19f4f
large project db
cdriesler May 13, 2025
1a1243c
please please please
cdriesler May 14, 2025
e578240
fine
cdriesler May 14, 2025
1cd70d9
Merge branch 'main' into charles/ily-victor
cdriesler May 23, 2025
2b468f2
user provisioning
cdriesler May 23, 2025
54844c4
changes from droplet
cdriesler May 23, 2025
390635f
seat type handling
cdriesler May 24, 2025
4115d51
user provisioning but actually
cdriesler May 31, 2025
df98f68
invite-based provisioning
cdriesler May 31, 2025
31f0163
don't make users twice
cdriesler May 31, 2025
b72d0ff
try-catch user provisioning
cdriesler May 31, 2025
6c907b0
brackets
cdriesler May 31, 2025
743fcfa
replication stuff
cdriesler May 31, 2025
d28a426
add wait
cdriesler May 31, 2025
7c62287
smaller batch
cdriesler May 31, 2025
3f70575
feat(dataMigration): add stream acl fix script
gjedlicska Jun 2, 2025
05b050f
feat(moveProjects): add new sync acls script
gjedlicska Jun 2, 2025
f2bdf81
feat(moveProjects): import bootstrap
gjedlicska Jun 2, 2025
d966d40
feat(moveProjects): fix empty
gjedlicska Jun 2, 2025
f0f38c9
feat(moveProjects): do not migrate acl for not found projects
gjedlicska Jun 2, 2025
81271ee
Merge branch 'main' into charles/ily-victor
cdriesler Jun 20, 2025
0bb3c29
fix(migration): use new visibility, drop implicit role sync
cdriesler Jun 20, 2025
4a5385e
add better user provisioning
cdriesler Jun 21, 2025
4a90de9
set workspace values
cdriesler Jun 21, 2025
a9e5022
use mapping
cdriesler Jun 21, 2025
4f7b627
upsert
cdriesler Jun 21, 2025
9c5f604
order
cdriesler Jun 21, 2025
bc59c23
add existing users to workspace
cdriesler Jun 21, 2025
97615f1
classic
cdriesler Jun 21, 2025
3adfd31
provision verified emails
cdriesler Jun 21, 2025
2c2b6c3
larger batches
cdriesler Jun 22, 2025
88b518c
fix(migration): prevent role downgrade
cdriesler Jul 12, 2025
482c288
fig(migration): skip speckle.systems
cdriesler Jul 12, 2025
85e0c36
fix(migration): do not try to assign stream roles to non-workspace me…
cdriesler Jul 12, 2025
8ef9b83
fix(migration): actually skip
cdriesler Jul 12, 2025
711c9c4
fix(migration): update role if necessary
cdriesler Jul 12, 2025
2386557
fix(migration): do not use table prefix in onConflict
cdriesler Jul 12, 2025
8e09b81
fmt
cdriesler Nov 22, 2025
21d30d9
regionsss
cdriesler Nov 22, 2025
b03d1b0
replicate users
cdriesler Nov 22, 2025
b6e1b57
skip legacy comments
cdriesler Nov 23, 2025
6155b68
order by updated
cdriesler Nov 23, 2025
879a9df
do not skip comments
cdriesler Nov 23, 2025
ba901e9
skip comments
cdriesler Nov 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/server/modules/core/repositories/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const getStreamObjectCountFactory =
export const insertObjectsFactory =
(deps: { db: Knex }): StoreObjects =>
async (objects: ObjectRecord[], options?: Partial<{ trx: Knex.Transaction }>) => {
const q = tables.objects(deps.db).insert(objects)
const q = tables.objects(deps.db).insert(objects).onConflict().ignore()
if (options?.trx) q.transacting(options.trx)
return await q
}
Expand Down
147 changes: 147 additions & 0 deletions packages/server/scripts/fixStreamAcl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// eslint-disable-next-line no-restricted-imports
import '../bootstrap'

import {
getAvailableRegionConfig,
getMainRegionConfig
} from '@/modules/multiregion/regionConfig'
import { getStringFromEnv } from '@/modules/shared/helpers/envHelper'
import { getWorkspaceFactory } from '@/modules/workspaces/repositories/workspaces'
import knex from 'knex'
import { configureClient } from '@/knexfile'
import { getDefaultRegionFactory } from '@/modules/workspaces/repositories/regions'
import { executeBatchedSelect } from '@/modules/shared/helpers/dbHelper'
import { UserEmail } from '@/modules/core/domain/userEmails/types'
import { findEmailFactory } from '@/modules/core/repositories/userEmails'
import { StreamAclRecord, StreamRecord } from '@/modules/core/helpers/types'
import { getProjectFactory } from '@/modules/core/repositories/projects'

const TARGET_WORKSPACE_ID = '725392a6d1'

const getSourceServerConnection = async () => {
const sourceDbConnection = getStringFromEnv('SOURCE_DB_CONNECTION')
const sourceDb = knex(sourceDbConnection)
return { sourceDb }
}

const getTargetServerConnection = async (targetWorkspaceId: string) => {
const targetMainDbConfig = await getMainRegionConfig()
const targetMainDb = configureClient(targetMainDbConfig).public

const workspace = await getWorkspaceFactory({ db: targetMainDb })({
workspaceId: targetWorkspaceId
})
if (!workspace) throw Error('Target workspace not found')

let targetRegionDb = targetMainDb

const workspaceRegion = await getDefaultRegionFactory({ db: targetMainDb })({
workspaceId: targetWorkspaceId
})
if (workspaceRegion) {
const targetWorkspaceRegionConfig = (await getAvailableRegionConfig())[
workspaceRegion.key
]
targetRegionDb = configureClient(targetWorkspaceRegionConfig).public
}

return {
targetMainDb,
targetRegionDb,
targetWorkspaceRegionKey: workspaceRegion?.key ?? null
}
}

const userIdMapping: Record<string, string> = {}

const main = async () => {
const { sourceDb } = await getSourceServerConnection()
const { targetMainDb } = await getTargetServerConnection(TARGET_WORKSPACE_ID)
console.log('remapping users from old userId to new')
for await (const userEmails of executeBatchedSelect(
sourceDb.table<UserEmail>('user_emails').select('*')
)) {
for (const userEmail of userEmails) {
const sourceUserId = userEmail.userId
const targetEmail = await findEmailFactory({ db: targetMainDb })({
email: userEmail.email.toLowerCase(),
verified: true
})
if (!targetEmail) {
console.log(`Source user email ${userEmail.email} not found in target server`)
continue
}
userIdMapping[sourceUserId] = targetEmail.userId
}
}

let count = 0

for await (const sourceProjects of executeBatchedSelect(
sourceDb.table<StreamRecord>('streams').select('*')
)) {
for (const sourceProject of sourceProjects) {
count++
console.log(`${count}/x Migrating project acl for ${sourceProject.name}`)
const targetProject = await getProjectFactory({ db: targetMainDb })({
projectId: sourceProject.id
})
if (!targetProject) {
console.log(`target project ${sourceProject.name} not found in target server`)
continue
}
if (!(targetProject.workspaceId === TARGET_WORKSPACE_ID)) {
throw new Error(`target project is not in the target workspace`)
}

console.log(` target project found and is in the right workspace`)

const streamAcl = await sourceDb
.table<StreamAclRecord>('stream_acl')
.where({ resourceId: sourceProject.id })
.select('*')

const newAcl = streamAcl.flatMap((acl) => {
const newItem = { ...acl }
if (!(acl.userId in userIdMapping)) return []
const newId = userIdMapping[acl.userId]
newItem.userId = newId
return newItem
})

console.log(
` remapped stream_acls ignored ${streamAcl.length - newAcl.length}/${
newAcl.length
}`
)

const deleted = await targetMainDb
.table<StreamAclRecord>('stream_acl')
.delete('*')
.where({ resourceId: targetProject.id })

console.log(` deleted ${deleted.length} old acl records`)

if (!newAcl.length) {
console.log(` no new acl records to insert`)
continue
}
await targetMainDb.table<StreamAclRecord>('stream_acl').insert(newAcl)

console.log(` inserted ${newAcl.length} new acl records`)
}
}

// for stream in source server streams:
// 1. get all stream_acl-s from source DB
// 2. remap each stream_acl record with the new target user id
// if new target user id not found, ignore.
// 3. find project by id from target db, to make sure it exists
// also verify that new target project is in the target workspace
// 4. delete all stream_acl redords from target db, that belongs to this project
// 5. insert the remapped acl records with the original roles
}

main()
.then(() => console.log('done'))
.catch((e) => console.log(e))
Loading