1111use OC \Files \SetupManager ;
1212use OCA \Files_Sharing \ShareTargetValidator ;
1313use OCP \DB \QueryBuilder \IQueryBuilder ;
14+ use OCP \Files \IRootFolder ;
1415use OCP \Files \Mount \IMountManager ;
1516use OCP \IDBConnection ;
1617use OCP \IUserManager ;
1718use OCP \Migration \IOutput ;
1819use OCP \Migration \IRepairStep ;
19- use OCP \Share \IManager ;
20- use OCP \Share \IProviderFactory ;
2120use OCP \Share \IShare ;
21+ use Psr \Log \LoggerInterface ;
2222
23+ /**
24+ * @psalm-type ShareInfo = array{id: string|int, share_type: string, share_with: string, file_source: string, file_target: string}
25+ */
2326class CleanupShareTarget implements IRepairStep {
2427 /** we only care about shares with a user target,
2528 * since the underling group/deck/talk share doesn't get moved
@@ -33,12 +36,12 @@ class CleanupShareTarget implements IRepairStep {
3336
3437 public function __construct (
3538 private readonly IDBConnection $ connection ,
36- private readonly IManager $ shareManager ,
37- private readonly IProviderFactory $ shareProviderFactory ,
3839 private readonly ShareTargetValidator $ shareTargetValidator ,
3940 private readonly IUserManager $ userManager ,
4041 private readonly SetupManager $ setupManager ,
4142 private readonly IMountManager $ mountManager ,
43+ private readonly IRootFolder $ rootFolder ,
44+ private readonly LoggerInterface $ logger ,
4245 ) {
4346 }
4447
@@ -57,12 +60,13 @@ public function run(IOutput $output) {
5760
5861 $ lastUser = '' ;
5962 $ userMounts = [];
63+ $ userFolder = null ;
6064
6165 foreach ($ this ->getProblemShares () as $ shareInfo ) {
6266 $ recipient = $ this ->userManager ->getExistingUser ($ shareInfo ['share_with ' ]);
63- $ share = $ this -> shareProviderFactory
64- -> getProviderForType (( int ) $ shareInfo [ ' share_type ' ])
65- -> getShareById ( $ shareInfo [ ' id ' ], $ recipient -> getUID ());
67+ if (! $ recipient -> isEnabled ()) {
68+ continue ;
69+ }
6670
6771 // since we ordered the share by user, we can reuse the last data until we get to the next user
6872 if ($ lastUser !== $ recipient ->getUID ()) {
@@ -71,24 +75,34 @@ public function run(IOutput $output) {
7175 $ this ->setupManager ->tearDown ();
7276 $ this ->setupManager ->setupForUser ($ recipient );
7377 $ userMounts = $ this ->mountManager ->getAll ();
78+ $ userFolder = $ this ->rootFolder ->getUserFolder ($ recipient ->getUID ());
7479 }
7580
76- $ oldTarget = $ share -> getTarget () ;
81+ $ oldTarget = $ shareInfo [ ' file_target ' ] ;
7782 $ newTarget = $ this ->cleanTarget ($ oldTarget );
78- $ share ->setTarget ($ newTarget );
79- $ this ->shareManager ->moveShare ($ share , $ recipient ->getUID ());
80-
81- $ this ->shareTargetValidator ->verifyMountPoint (
82- $ recipient ,
83- $ share ,
84- $ userMounts ,
85- [$ share ],
86- );
87-
88- $ oldMountPoint = "/ {$ recipient ->getUID ()}/files $ oldTarget/ " ;
89- $ newMountPoint = "/ {$ recipient ->getUID ()}/files $ newTarget/ " ;
90- $ userMounts [$ newMountPoint ] = $ userMounts [$ oldMountPoint ];
91- unset($ userMounts [$ oldMountPoint ]);
83+ $ absoluteNewTarget = $ userFolder ->getFullPath ($ newTarget );
84+ $ targetParentNode = $ this ->rootFolder ->get (dirname ($ absoluteNewTarget ));
85+
86+ try {
87+ $ absoluteNewTarget = $ this ->shareTargetValidator ->generateUniqueTarget (
88+ (int )$ shareInfo ['file_source ' ],
89+ $ absoluteNewTarget ,
90+ $ targetParentNode ->getMountPoint (),
91+ $ userMounts ,
92+ );
93+ $ newTarget = $ userFolder ->getRelativePath ($ absoluteNewTarget );
94+
95+ $ this ->moveShare ((string )$ shareInfo ['id ' ], $ newTarget );
96+
97+ $ oldMountPoint = "/ {$ recipient ->getUID ()}/files $ oldTarget/ " ;
98+ $ newMountPoint = "/ {$ recipient ->getUID ()}/files $ newTarget/ " ;
99+ $ userMounts [$ newMountPoint ] = $ userMounts [$ oldMountPoint ];
100+ unset($ userMounts [$ oldMountPoint ]);
101+ } catch (\Exception $ e ) {
102+ $ msg = 'error cleaning up share target: ' . $ e ->getMessage ();
103+ $ this ->logger ->error ($ msg , ['exception ' => $ e , 'app ' => 'files_sharing ' ]);
104+ $ output ->warning ($ msg );
105+ }
92106
93107 $ output ->advance ();
94108 }
@@ -105,19 +119,29 @@ private function countProblemShares(): int {
105119 return (int )$ query ->executeQuery ()->fetchOne ();
106120 }
107121
122+ private function moveShare (string $ id , string $ target ) {
123+ // since we only process user-specific shares, we can just move them
124+ // without having to check if we need to create a user-specific override
125+ $ query = $ this ->connection ->getQueryBuilder ();
126+ $ query ->update ('share ' )
127+ ->set ('file_target ' , $ query ->createNamedParameter ($ target ))
128+ ->where ($ query ->expr ()->eq ('id ' , $ query ->createNamedParameter ($ id )))
129+ ->executeStatement ();
130+ }
131+
108132 /**
109- * @return \Traversable<array{id: string, share_type: string, share_with: string} >
133+ * @return \Traversable<ShareInfo >
110134 */
111135 private function getProblemShares (): \Traversable {
112136 $ query = $ this ->connection ->getQueryBuilder ();
113- $ query ->select ('id ' , 'share_type ' , 'share_with ' )
137+ $ query ->select ('id ' , 'share_type ' , 'share_with ' , ' file_source ' , ' file_target ' )
114138 ->from ('share ' )
115139 ->where ($ query ->expr ()->like ('file_target ' , $ query ->createNamedParameter ('% (_) (_)% ' )))
116140 ->andWhere ($ query ->expr ()->in ('share_type ' , $ query ->createNamedParameter (self ::USER_SHARE_TYPES , IQueryBuilder::PARAM_INT_ARRAY ), IQueryBuilder::PARAM_INT_ARRAY ))
117141 ->orderBy ('share_with ' )
118142 ->addOrderBy ('id ' );
119143 $ result = $ query ->executeQuery ();
120- /** @var \Traversable<array{id: string, share_type: string, share_with: string} > $rows */
144+ /** @var \Traversable<ShareInfo > $rows */
121145 $ rows = $ result ->iterateAssociative ();
122146 return $ rows ;
123147 }
0 commit comments