Passed
Push — master ( 927130...9d89f8 )
by Roeland
35:01 queued 22:12
created

SetVcardDatabaseUID::repair()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nc 2
nop 0
dl 0
loc 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2018 John Molakvoæ <[email protected]>
4
 *
5
 * @author John Molakvoæ <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OC\Repair\NC15;
25
26
use OCP\IConfig;
27
use OCP\IDBConnection;
28
use OCP\Migration\IOutput;
29
use OCP\Migration\IRepairStep;
30
use Sabre\VObject\Reader;
31
32
class SetVcardDatabaseUID implements IRepairStep {
33
	const MAX_ROWS = 1000;
34
35
	/** @var IDBConnection */
36
	private $connection;
37
38
	/** @var IConfig */
39
	private $config;
40
41
	private $updateQuery;
42
43
	public function __construct(IDBConnection $connection, IConfig $config) {
44
		$this->connection = $connection;
45
		$this->config     = $config;
46
	}
47
48
	public function getName() {
49
		return 'Extract the vcard uid and store it in the db';
50
	}
51
52
	/**
53
	 * @return \Generator
54
	 * @suppress SqlInjectionChecker
55
	 */
56
	private function getInvalidEntries() {
57
		$builder = $this->connection->getQueryBuilder();
58
59
		$builder->select('id', 'carddata')
60
		        ->from('cards')
61
		        ->where($builder->expr()->isNull('uid'))
62
		        ->setMaxResults(self::MAX_ROWS);
63
64
		do {
65
			$result = $builder->execute();
66
			$rows   = $result->fetchAll();
67
			foreach ($rows as $row) {
68
				yield $row;
69
			}
70
			$result->closeCursor();
71
		} while (count($rows) > 0);
72
	}
73
74
	/**
75
	 * Extract UID from vcard
76
	 *
77
	 * @param string $cardData the vcard raw data
78
	 * @return string the uid or empty if none
79
	 */
80
	private function getUID(string $cardData): string {
81
		$vCard = Reader::read($cardData);
82
		if ($vCard->UID) {
83
			$uid = $vCard->UID->getValue();
84
			return $uid;
85
		}
86
87
		return '';
88
	}
89
90
	/**
91
	 * @param int $id
92
	 * @param string $uid
93
	 */
94
	private function update(int $id, string $uid) {
95
		if (!$this->updateQuery) {
96
			$builder = $this->connection->getQueryBuilder();
97
98
			$this->updateQuery = $builder->update('cards')
99
			                             ->set('uid', $builder->createParameter('uid'))
100
			                             ->where($builder->expr()->eq('id', $builder->createParameter('id')));
101
		}
102
103
		$this->updateQuery->setParameter('id', $id);
104
		$this->updateQuery->setParameter('uid', $uid);
105
106
		$this->updateQuery->execute();
107
	}
108
109
	private function repair(): int {
110
		$this->connection->beginTransaction();
111
		$entries = $this->getInvalidEntries();
112
		$count   = 0;
113
		foreach ($entries as $entry) {
114
			$count++;
115
			$uid = $this->getUID($entry['carddata']);
116
			$this->update($entry['id'], $uid);
117
		}
118
		$this->connection->commit();
119
120
		return $count;
121
	}
122
123
	private function shouldRun() {
124
		$versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
125
126
		// was added to 15.0.0.2
127
		return version_compare($versionFromBeforeUpdate, '15.0.0.2', '<=');
128
	}
129
130
	public function run(IOutput $output) {
131
		if ($this->shouldRun()) {
132
			$count = $this->repair();
133
134
			$output->info('Fixed ' . $count . ' vcards');
135
		}
136
	}
137
}
138