Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
UserMigrator
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 7
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getEstimatedExportSize
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 export
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
42
 import
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
72
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisplayName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace OCA\Cospend\UserMigration;
6
7use OCA\Cospend\AppInfo\Application;
8use OCA\Cospend\Db\Project;
9use OCA\Cospend\Db\ProjectMapper;
10use OCA\Cospend\Service\ProjectService;
11use OCP\IConfig;
12use OCP\IL10N;
13use OCP\IUser;
14use OCP\UserMigration\IExportDestination;
15use OCP\UserMigration\IImportSource;
16use OCP\UserMigration\IMigrator;
17use OCP\UserMigration\ISizeEstimationMigrator;
18use OCP\UserMigration\TMigratorBasicVersionHandling;
19use OCP\UserMigration\UserMigrationException;
20use Symfony\Component\Console\Output\OutputInterface;
21use Throwable;
22
23class UserMigrator implements IMigrator, ISizeEstimationMigrator {
24    use TMigratorBasicVersionHandling;
25
26    private const PATH_ROOT = Application::APP_ID;
27    private const PROJECTS_PATH = self::PATH_ROOT . '/projects';
28    private const SETTINGS_PATH = self::PATH_ROOT . '/settings.json';
29    private ProjectService $projectService;
30    private IL10N $l10n;
31    private ProjectMapper $projectMapper;
32    private IConfig $config;
33
34    public function __construct(
35        ProjectService $projectService,
36        ProjectMapper $projectMapper,
37        IConfig $config,
38        IL10N $l10n
39    ) {
40        $this->l10n = $l10n;
41        $this->projectService = $projectService;
42        $this->projectMapper = $projectMapper;
43        $this->config = $config;
44    }
45
46    /**
47     * Returns an estimate of the exported data size in KiB.
48     * Should be fast, favor performance over accuracy.
49     *
50     * @since 25.0.0
51     */
52    public function getEstimatedExportSize(IUser $user): int {
53        $size = 100; // 100KiB for user data JSON
54        return $size;
55    }
56
57    /**
58     * Export user data
59     *
60     * @throws UserMigrationException
61     * @since 24.0.0
62     */
63    public function export(IUser $user, IExportDestination $exportDestination, OutputInterface $output): void {
64        $output->writeln('Exporting Cospend projects in ' . self::PROJECTS_PATH . '…');
65        $userId = $user->getUID();
66        /** @var Project[] $projects */
67        $projects = $this->projectMapper->getProjects($userId);
68        foreach ($projects as $project) {
69            try {
70                $exportFilePath = self::PROJECTS_PATH . '/' . $project->getId() . '.csv';
71                $content = '';
72                foreach ($this->projectService->getJsonProject($project->getId()) as $chunk) {
73                    $content .= $chunk;
74                }
75                $exportDestination->addFileContents($exportFilePath, $content);
76            } catch (Throwable $e) {
77                throw new UserMigrationException('Could not export Cospend projects', 0, $e);
78            }
79        }
80
81        // settings
82        $userSettings = [];
83        foreach ($this->config->getUserKeys($userId, Application::APP_ID) as $key) {
84            $value = $this->config->getUserValue($userId, Application::APP_ID, $key, null);
85            if ($value !== null) {
86                $userSettings[$key] = $value;
87            }
88        }
89        $exportDestination->addFileContents(self::SETTINGS_PATH, json_encode($userSettings));
90    }
91
92    /**
93     * Import user data
94     *
95     * @throws UserMigrationException
96     * @since 24.0.0
97     */
98    public function import(IUser $user, IImportSource $importSource, OutputInterface $output): void {
99        if ($importSource->getMigratorVersion($this->getId()) === null) {
100            $output->writeln('No version for ' . static::class . ', skipping import…');
101            return;
102        }
103
104        $output->writeln('Importing Cospend projects from ' . self::PROJECTS_PATH . '…');
105        // no idea why this does not work
106        // zip->locateName($path) works with the trashbin app but not here
107        /*
108        if (!$importSource->pathExists(self::PATH_ROOT)) {
109            $output->writeln('No Cospend directory, skipping import…');
110            return;
111        }
112        if (!$importSource->pathExists(self::PROJECTS_PATH)) {
113            $output->writeln('No "projects" directory for Cospend, skipping import…');
114            return;
115        }
116        */
117
118        $userId = $user->getUID();
119        $fileList = $importSource->getFolderListing(self::PROJECTS_PATH . '/');
120        foreach ($fileList as $fileName) {
121            try {
122                $handler = $importSource->getFileAsStream(self::PROJECTS_PATH . '/' . $fileName);
123                $projectName = preg_replace('/\.csv$/', '', $fileName);
124                $this->projectService->importCsvProjectAtomicWrapper($handler, $userId, $projectName);
125            } catch (Throwable $e) {
126                // throw new UserMigrationException('Could not import Cospend project in ' . $fileName, 0, $e);
127                $output->writeln('Error when importing Cospend project in ' . $fileName);
128            }
129        }
130
131        // settings
132        if ($importSource->pathExists(self::SETTINGS_PATH)) {
133            $settingsFileContent = $importSource->getFileContents(self::SETTINGS_PATH);
134            $settings = json_decode($settingsFileContent, true);
135            if ($settings !== false && is_array($settings)) {
136                foreach ($settings as $key => $value) {
137                    $this->config->setUserValue($userId, Application::APP_ID, $key, $value);
138                }
139            }
140        }
141    }
142
143    /**
144     * Returns the unique ID
145     *
146     * @since 24.0.0
147     */
148    public function getId(): string {
149        return 'cospend';
150    }
151
152    /**
153     * Returns the display name
154     *
155     * @since 24.0.0
156     */
157    public function getDisplayName(): string {
158        return $this->l10n->t('Cospend');
159    }
160
161    /**
162     * Returns the description
163     *
164     * @since 24.0.0
165     */
166    public function getDescription(): string {
167        return $this->l10n->t('Cospend projects and user settings');
168    }
169}