@@ -18,6 +18,7 @@ import contact from '@hcengineering/contact'
18
18
import core , {
19
19
DOMAIN_TX ,
20
20
getWorkspaceId ,
21
+ TxOperations ,
21
22
type BackupClient ,
22
23
type BaseWorkspaceInfo ,
23
24
type Class ,
@@ -161,3 +162,66 @@ export async function backupRestore (
161
162
await storageAdapter . close ( )
162
163
}
163
164
}
165
+
166
+ export async function restoreRemovedDoc (
167
+ ctx : MeasureContext ,
168
+ workspaceId : WorkspaceId ,
169
+ transactorUrl : string ,
170
+ idsVal : string
171
+ ) : Promise < void > {
172
+ const ids = idsVal . split ( ';' ) . map ( ( it ) => it . trim ( ) ) as Ref < Doc > [ ]
173
+ const connection = ( await connect ( transactorUrl , workspaceId , undefined , {
174
+ mode : 'backup' ,
175
+ model : 'upgrade' , // Required for force all clients reload after operation will be complete.
176
+ admin : 'true'
177
+ } ) ) as unknown as CoreClient & BackupClient
178
+ try {
179
+ for ( const id of ids ) {
180
+ try {
181
+ ctx . info ( 'start restoring' , { id } )
182
+ const ops = new TxOperations ( connection , core . account . System )
183
+ const processed = new Set < Ref < Doc > > ( )
184
+ const txes = await getObjectTxesAndRelatedTxes ( ctx , ops , id , processed , true )
185
+ txes . filter ( ( p ) => p . _class !== core . class . TxRemoveDoc ) . sort ( ( a , b ) => a . modifiedOn - b . modifiedOn )
186
+ for ( const tx of txes ) {
187
+ tx . space = core . space . DerivedTx
188
+ await ops . tx ( tx )
189
+ }
190
+ ctx . info ( 'success restored' , { id } )
191
+ } catch ( err ) {
192
+ ctx . error ( 'error restoring' , { id, err } )
193
+ }
194
+ }
195
+ } finally {
196
+ await connection . sendForceClose ( )
197
+ await connection . close ( )
198
+ }
199
+ }
200
+
201
+ async function getObjectTxesAndRelatedTxes (
202
+ ctx : MeasureContext ,
203
+ client : TxOperations ,
204
+ objectId : Ref < Doc > ,
205
+ processed : Set < Ref < Doc > > ,
206
+ filterRemoved = false
207
+ ) : Promise < Tx [ ] > {
208
+ ctx . info ( 'Find txes for' , { objectId } )
209
+ const result : Tx [ ] = [ ]
210
+ if ( processed . has ( objectId ) ) {
211
+ return result
212
+ }
213
+ processed . add ( objectId )
214
+ let txes = ( await client . findAll ( core . class . TxCUD , { objectId } ) ) as Tx [ ]
215
+ if ( filterRemoved ) {
216
+ txes = txes . filter ( ( it ) => it . _class !== core . class . TxRemoveDoc )
217
+ }
218
+ result . push ( ...txes )
219
+ const relatedTxes = await client . findAll ( core . class . TxCUD , { attachedTo : objectId } )
220
+ result . push ( ...relatedTxes )
221
+ const relatedIds = new Set ( relatedTxes . map ( ( it ) => it . objectId ) )
222
+ for ( const relatedId of relatedIds ) {
223
+ const rel = await getObjectTxesAndRelatedTxes ( ctx , client , relatedId , processed )
224
+ result . push ( ...rel )
225
+ }
226
+ return result
227
+ }
0 commit comments