1313use OCP \DB \QueryBuilder \IQueryBuilder ;
1414use OCP \Files \Config \ICachedMountInfo ;
1515use OCP \Files \Config \IUserMountCache ;
16+ use OCP \Files \IRootFolder ;
1617use OCP \IDBConnection ;
1718use OCP \IUserManager ;
1819use OCP \Migration \IOutput ;
1920use OCP \Migration \IRepairStep ;
20- use OCP \Share \IManager ;
21- use OCP \Share \IProviderFactory ;
2221use OCP \Share \IShare ;
2322
23+ /**
24+ * @psalm-type ShareInfo = array{id: string|int, share_type: string, share_with: string, file_source: string, file_target: string};
25+ */
2426class CleanupShareTarget implements IRepairStep {
2527 /** we only care about shares with a user target,
2628 * since the underling group/deck/talk share doesn't get moved
@@ -34,12 +36,11 @@ class CleanupShareTarget implements IRepairStep {
3436
3537 public function __construct (
3638 private readonly IDBConnection $ connection ,
37- private readonly IManager $ shareManager ,
38- private readonly IProviderFactory $ shareProviderFactory ,
3939 private readonly ShareTargetValidator $ shareTargetValidator ,
4040 private readonly IUserManager $ userManager ,
4141 private readonly SetupManager $ setupManager ,
4242 private readonly IUserMountCache $ userMountCache ,
43+ private readonly IRootFolder $ rootFolder ,
4344 ) {
4445 }
4546
@@ -58,12 +59,10 @@ public function run(IOutput $output) {
5859
5960 $ lastUser = '' ;
6061 $ userMounts = [];
62+ $ userFolder = null ;
6163
6264 foreach ($ this ->getProblemShares () as $ shareInfo ) {
6365 $ recipient = $ this ->userManager ->getExistingUser ($ shareInfo ['share_with ' ]);
64- $ share = $ this ->shareProviderFactory
65- ->getProviderForType ((int )$ shareInfo ['share_type ' ])
66- ->getShareById ($ shareInfo ['id ' ], $ recipient ->getUID ());
6766
6867 // since we ordered the share by user, we can reuse the last data until we get to the next user
6968 if ($ lastUser !== $ recipient ->getUID ()) {
@@ -74,19 +73,23 @@ public function run(IOutput $output) {
7473 $ mounts = $ this ->userMountCache ->getMountsForUser ($ recipient );
7574 $ mountPoints = array_map (fn (ICachedMountInfo $ mount ) => $ mount ->getMountPoint (), $ mounts );
7675 $ userMounts = array_combine ($ mountPoints , $ mounts );
76+ $ userFolder = $ this ->rootFolder ->getUserFolder ($ recipient ->getUID ());
7777 }
7878
79- $ oldTarget = $ share -> getTarget () ;
79+ $ oldTarget = $ shareInfo [ ' file_target ' ] ;
8080 $ newTarget = $ this ->cleanTarget ($ oldTarget );
81- $ share -> setTarget ($ newTarget );
82- $ this ->shareManager -> moveShare ( $ share , $ recipient -> getUID ( ));
81+ $ absoluteNewTarget = $ userFolder -> getFullPath ($ newTarget );
82+ $ targetParentNode = $ this ->rootFolder -> get ( dirname ( $ absoluteNewTarget ));
8383
84- $ this ->shareTargetValidator ->verifyMountPoint (
85- $ recipient ,
86- $ share ,
84+ $ absoluteNewTarget = $ this ->shareTargetValidator ->generateUniqueTarget (
85+ $ shareInfo ['file_source ' ],
86+ $ absoluteNewTarget ,
87+ $ targetParentNode ->getMountPoint (),
8788 $ userMounts ,
88- [$ share ],
8989 );
90+ $ newTarget = $ userFolder ->getRelativePath ($ absoluteNewTarget );
91+
92+ $ this ->moveShare ((string )$ shareInfo ['id ' ], $ newTarget );
9093
9194 $ oldMountPoint = "/ {$ recipient ->getUID ()}/files $ oldTarget/ " ;
9295 $ newMountPoint = "/ {$ recipient ->getUID ()}/files $ newTarget/ " ;
@@ -108,12 +111,22 @@ private function countProblemShares(): int {
108111 return (int )$ query ->executeQuery ()->fetchOne ();
109112 }
110113
114+ private function moveShare (string $ id , string $ target ) {
115+ // since we only process user-specific shares, we can just move them
116+ // without having to check if we need to create a user-specific override
117+ $ query = $ this ->connection ->getQueryBuilder ();
118+ $ query ->update ('share ' )
119+ ->set ('file_target ' , $ query ->createNamedParameter ($ target ))
120+ ->where ($ query ->expr ()->eq ('id ' , $ query ->createNamedParameter ($ id )))
121+ ->executeStatement ();
122+ }
123+
111124 /**
112- * @return \Traversable<array{id: string, share_type: string, share_with: string} >
125+ * @return \Traversable<ShareInfo >
113126 */
114127 private function getProblemShares (): \Traversable {
115128 $ query = $ this ->connection ->getQueryBuilder ();
116- $ query ->select ('id ' , 'share_type ' , 'share_with ' )
129+ $ query ->select ('id ' , 'share_type ' , 'share_with ' , ' file_source ' , ' file_target ' )
117130 ->from ('share ' )
118131 ->where ($ query ->expr ()->like ('file_target ' , $ query ->createNamedParameter ('% (_) (_)% ' )))
119132 ->andWhere ($ query ->expr ()->in ('share_type ' , $ query ->createNamedParameter (self ::USER_SHARE_TYPES , IQueryBuilder::PARAM_INT_ARRAY ), IQueryBuilder::PARAM_INT_ARRAY ))
0 commit comments