##// END OF EJS Templates
Addd save methods. Fix bug with work repository suffix handling
perrinel -
r1279:4e7a8f2af91d
parent child
Show More
@@ -1,306 +1,338
1 #include <Catalogue/CatalogueController.h>
1 #include <Catalogue/CatalogueController.h>
2
2
3 #include <Variable/Variable.h>
3 #include <Variable/Variable.h>
4
4
5 #include <CatalogueDao.h>
5 #include <CatalogueDao.h>
6
6
7 #include <ComparaisonPredicate.h>
7 #include <ComparaisonPredicate.h>
8 #include <CompoundPredicate.h>
8 #include <CompoundPredicate.h>
9 #include <DBCatalogue.h>
9 #include <DBCatalogue.h>
10 #include <DBEvent.h>
10 #include <DBEvent.h>
11 #include <DBEventProduct.h>
11 #include <DBEventProduct.h>
12 #include <DBTag.h>
12 #include <DBTag.h>
13 #include <IRequestPredicate.h>
13 #include <IRequestPredicate.h>
14
14
15 #include <QMutex>
15 #include <QMutex>
16 #include <QThread>
16 #include <QThread>
17
17
18 #include <QDir>
18 #include <QDir>
19 #include <QStandardPaths>
19 #include <QStandardPaths>
20
20
21 Q_LOGGING_CATEGORY(LOG_CatalogueController, "CatalogueController")
21 Q_LOGGING_CATEGORY(LOG_CatalogueController, "CatalogueController")
22
22
23 namespace {
23 namespace {
24
24
25 static QString REPOSITORY_WORK_SUFFIX = QString{"work"};
25 static QString REPOSITORY_WORK_SUFFIX = QString{"_work"};
26 static QString REPOSITORY_TRASH_SUFFIX = QString{"trash"};
26 static QString REPOSITORY_TRASH_SUFFIX = QString{"_trash"};
27 }
27 }
28
28
29 class CatalogueController::CatalogueControllerPrivate {
29 class CatalogueController::CatalogueControllerPrivate {
30
30
31 public:
31 public:
32 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
32 explicit CatalogueControllerPrivate(CatalogueController *parent) : m_Q{parent} {}
33
33
34 QMutex m_WorkingMutex;
34 QMutex m_WorkingMutex;
35 CatalogueDao m_CatalogueDao;
35 CatalogueDao m_CatalogueDao;
36
36
37 QStringList m_RepositoryList;
37 QStringList m_RepositoryList;
38 CatalogueController *m_Q;
38 CatalogueController *m_Q;
39
39
40 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
40 void copyDBtoDB(const QString &dbFrom, const QString &dbTo);
41 QString toWorkRepository(QString repository);
41 QString toWorkRepository(QString repository);
42 QString toSyncRepository(QString repository);
42 QString toSyncRepository(QString repository);
43 void savAllDB();
44
45 void saveEvent(std::shared_ptr<DBEvent> event, bool persist = true);
46 void saveCatalogue(std::shared_ptr<DBCatalogue> catalogue, bool persist = true);
43 };
47 };
44
48
45 CatalogueController::CatalogueController(QObject *parent)
49 CatalogueController::CatalogueController(QObject *parent)
46 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
50 : impl{spimpl::make_unique_impl<CatalogueControllerPrivate>(this)}
47 {
51 {
48 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
52 qCDebug(LOG_CatalogueController()) << tr("CatalogueController construction")
49 << QThread::currentThread();
53 << QThread::currentThread();
50 }
54 }
51
55
52 CatalogueController::~CatalogueController()
56 CatalogueController::~CatalogueController()
53 {
57 {
54 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
58 qCDebug(LOG_CatalogueController()) << tr("CatalogueController destruction")
55 << QThread::currentThread();
59 << QThread::currentThread();
56 this->waitForFinish();
60 this->waitForFinish();
57 }
61 }
58
62
59 QStringList CatalogueController::getRepositories() const
63 QStringList CatalogueController::getRepositories() const
60 {
64 {
61 return impl->m_RepositoryList;
65 return impl->m_RepositoryList;
62 }
66 }
63
67
64 void CatalogueController::addDB(const QString &dbPath)
68 void CatalogueController::addDB(const QString &dbPath)
65 {
69 {
66 QDir dbDir(dbPath);
70 QDir dbDir(dbPath);
67 if (dbDir.exists()) {
71 if (dbDir.exists()) {
68 auto dirName = dbDir.dirName();
72 auto dirName = dbDir.dirName();
69
73
70 if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName)
74 if (std::find(impl->m_RepositoryList.cbegin(), impl->m_RepositoryList.cend(), dirName)
71 != impl->m_RepositoryList.cend()) {
75 != impl->m_RepositoryList.cend()) {
72 qCCritical(LOG_CatalogueController())
76 qCCritical(LOG_CatalogueController())
73 << tr("Impossible to addDB that is already loaded");
77 << tr("Impossible to addDB that is already loaded");
74 }
78 }
75
79
76 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
80 if (!impl->m_CatalogueDao.addDB(dbPath, dirName)) {
77 qCCritical(LOG_CatalogueController())
81 qCCritical(LOG_CatalogueController())
78 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
82 << tr("Impossible to addDB %1 from %2 ").arg(dirName, dbPath);
79 }
83 }
80 else {
84 else {
81 impl->m_RepositoryList << dirName;
85 impl->m_RepositoryList << dirName;
82 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
86 impl->copyDBtoDB(dirName, impl->toWorkRepository(dirName));
83 }
87 }
84 }
88 }
85 else {
89 else {
86 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
90 qCCritical(LOG_CatalogueController()) << tr("Impossible to addDB that not exists: ")
87 << dbPath;
91 << dbPath;
88 }
92 }
89 }
93 }
90
94
91 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
95 void CatalogueController::saveDB(const QString &destinationPath, const QString &repository)
92 {
96 {
93 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
97 if (!impl->m_CatalogueDao.saveDB(destinationPath, repository)) {
94 qCCritical(LOG_CatalogueController())
98 qCCritical(LOG_CatalogueController())
95 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
99 << tr("Impossible to saveDB %1 from %2 ").arg(repository, destinationPath);
96 }
100 }
97 }
101 }
98
102
99 std::list<std::shared_ptr<DBEvent> >
103 std::list<std::shared_ptr<DBEvent> >
100 CatalogueController::retrieveEvents(const QString &repository) const
104 CatalogueController::retrieveEvents(const QString &repository) const
101 {
105 {
102 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
106 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
103
107
104 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
108 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
105 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
109 auto events = impl->m_CatalogueDao.getEvents(impl->toWorkRepository(dbDireName));
106 for (auto event : events) {
110 for (auto event : events) {
107 eventsShared.push_back(std::make_shared<DBEvent>(event));
111 eventsShared.push_back(std::make_shared<DBEvent>(event));
108 }
112 }
109 return eventsShared;
113 return eventsShared;
110 }
114 }
111
115
112 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
116 std::list<std::shared_ptr<DBEvent> > CatalogueController::retrieveAllEvents() const
113 {
117 {
114 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
118 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
115 for (auto repository : impl->m_RepositoryList) {
119 for (auto repository : impl->m_RepositoryList) {
116 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
120 eventsShared.splice(eventsShared.end(), retrieveEvents(repository));
117 }
121 }
118
122
119 return eventsShared;
123 return eventsShared;
120 }
124 }
121
125
122 std::list<std::shared_ptr<DBEvent> >
126 std::list<std::shared_ptr<DBEvent> >
123 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
127 CatalogueController::retrieveEventsFromCatalogue(std::shared_ptr<DBCatalogue> catalogue) const
124 {
128 {
125 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
129 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
126 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
130 auto events = impl->m_CatalogueDao.getCatalogueEvents(*catalogue);
127 for (auto event : events) {
131 for (auto event : events) {
128 eventsShared.push_back(std::make_shared<DBEvent>(event));
132 eventsShared.push_back(std::make_shared<DBEvent>(event));
129 }
133 }
130 return eventsShared;
134 return eventsShared;
131 }
135 }
132
136
133 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
137 void CatalogueController::updateEvent(std::shared_ptr<DBEvent> event)
134 {
138 {
135 event->setRepository(impl->toSyncRepository(event->getRepository()));
139 event->setRepository(impl->toWorkRepository(event->getRepository()));
136
140
137 impl->m_CatalogueDao.updateEvent(*event);
141 impl->m_CatalogueDao.updateEvent(*event);
138 }
142 }
139
143
140 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
144 void CatalogueController::removeEvent(std::shared_ptr<DBEvent> event)
141 {
145 {
142 // Remove it from both repository and repository_work
146 // Remove it from both repository and repository_work
143 event->setRepository(impl->toWorkRepository(event->getRepository()));
147 event->setRepository(impl->toWorkRepository(event->getRepository()));
144 impl->m_CatalogueDao.removeEvent(*event);
148 impl->m_CatalogueDao.removeEvent(*event);
145 event->setRepository(impl->toSyncRepository(event->getRepository()));
149 event->setRepository(impl->toSyncRepository(event->getRepository()));
146 impl->m_CatalogueDao.removeEvent(*event);
150 impl->m_CatalogueDao.removeEvent(*event);
147 }
151 }
148
152
149 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
153 void CatalogueController::addEvent(std::shared_ptr<DBEvent> event)
150 {
154 {
151 event->setRepository(impl->toWorkRepository(event->getRepository()));
155 event->setRepository(impl->toWorkRepository(event->getRepository()));
152
156
153 auto eventTemp = *event;
157 auto eventTemp = *event;
154 impl->m_CatalogueDao.addEvent(eventTemp);
158 impl->m_CatalogueDao.addEvent(eventTemp);
155
159
156 // Call update is necessary at the creation of add Event if it has some tags or some event
160 // Call update is necessary at the creation of add Event if it has some tags or some event
157 // products
161 // products
158 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
162 if (!event->getEventProducts().empty() || !event->getTags().empty()) {
159
163
160 auto eventProductsTemp = eventTemp.getEventProducts();
164 auto eventProductsTemp = eventTemp.getEventProducts();
161 auto eventProductTempUpdated = std::list<DBEventProduct>{};
165 auto eventProductTempUpdated = std::list<DBEventProduct>{};
162 for (auto eventProductTemp : eventProductsTemp) {
166 for (auto eventProductTemp : eventProductsTemp) {
163 eventProductTemp.setEvent(eventTemp);
167 eventProductTemp.setEvent(eventTemp);
164 eventProductTempUpdated.push_back(eventProductTemp);
168 eventProductTempUpdated.push_back(eventProductTemp);
165 }
169 }
166 eventTemp.setEventProducts(eventProductTempUpdated);
170 eventTemp.setEventProducts(eventProductTempUpdated);
167
171
168 impl->m_CatalogueDao.updateEvent(eventTemp);
172 impl->m_CatalogueDao.updateEvent(eventTemp);
169 }
173 }
170 }
174 }
171
175
172 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
176 void CatalogueController::saveEvent(std::shared_ptr<DBEvent> event)
173 {
177 {
174 impl->m_CatalogueDao.moveEvent(*event, impl->toSyncRepository(event->getRepository()), true);
178 impl->saveEvent(event, true);
175 }
179 }
176
180
177 std::list<std::shared_ptr<DBCatalogue> >
181 std::list<std::shared_ptr<DBCatalogue> >
178 CatalogueController::retrieveCatalogues(const QString &repository) const
182 CatalogueController::retrieveCatalogues(const QString &repository) const
179 {
183 {
180 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
184 QString dbDireName = repository.isEmpty() ? REPOSITORY_DEFAULT : repository;
181
185
182 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
186 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
183 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
187 auto catalogues = impl->m_CatalogueDao.getCatalogues(impl->toWorkRepository(dbDireName));
184 for (auto catalogue : catalogues) {
188 for (auto catalogue : catalogues) {
185 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
189 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
186 }
190 }
187 return cataloguesShared;
191 return cataloguesShared;
188 }
192 }
189
193
190 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
194 void CatalogueController::updateCatalogue(std::shared_ptr<DBCatalogue> catalogue)
191 {
195 {
192 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
196 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
193
197
194 impl->m_CatalogueDao.updateCatalogue(*catalogue);
198 impl->m_CatalogueDao.updateCatalogue(*catalogue);
195 }
199 }
196
200
197 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
201 void CatalogueController::removeCatalogue(std::shared_ptr<DBCatalogue> catalogue)
198 {
202 {
199 // Remove it from both repository and repository_work
203 // Remove it from both repository and repository_work
200 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
204 catalogue->setRepository(impl->toWorkRepository(catalogue->getRepository()));
201 impl->m_CatalogueDao.removeCatalogue(*catalogue);
205 impl->m_CatalogueDao.removeCatalogue(*catalogue);
202 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
206 catalogue->setRepository(impl->toSyncRepository(catalogue->getRepository()));
203 impl->m_CatalogueDao.removeCatalogue(*catalogue);
207 impl->m_CatalogueDao.removeCatalogue(*catalogue);
204 }
208 }
205
209
206 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
210 void CatalogueController::saveCatalogue(std::shared_ptr<DBCatalogue> catalogue)
207 {
211 {
208 impl->m_CatalogueDao.moveCatalogue(*catalogue,
212 impl->saveCatalogue(catalogue, true);
209 impl->toSyncRepository(catalogue->getRepository()), true);
210 }
213 }
211
214
212 void CatalogueController::saveAll()
215 void CatalogueController::saveAll()
213 {
216 {
214 for (auto repository : impl->m_RepositoryList) {
217 for (auto repository : impl->m_RepositoryList) {
215 // Save Event
218 // Save Event
216 auto events = this->retrieveEvents(repository);
219 auto events = this->retrieveEvents(repository);
217 for (auto event : events) {
220 for (auto event : events) {
218 this->saveEvent(event);
221 impl->saveEvent(event, false);
219 }
222 }
220
223
221 // Save Catalogue
224 // Save Catalogue
222 auto catalogues = this->retrieveCatalogues(repository);
225 auto catalogues = this->retrieveCatalogues(repository);
223 for (auto catalogue : catalogues) {
226 for (auto catalogue : catalogues) {
224 this->saveCatalogue(catalogue);
227 impl->saveCatalogue(catalogue, false);
225 }
228 }
226 }
229 }
230
231 impl->savAllDB();
227 }
232 }
228
233
229 void CatalogueController::initialize()
234 void CatalogueController::initialize()
230 {
235 {
231 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
236 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init")
232 << QThread::currentThread();
237 << QThread::currentThread();
233 impl->m_WorkingMutex.lock();
238 impl->m_WorkingMutex.lock();
234 impl->m_CatalogueDao.initialize();
239 impl->m_CatalogueDao.initialize();
235 auto defaultRepositoryLocation
240 auto defaultRepositoryLocation
236 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
241 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
237
242
238 QDir defaultRepositoryLocationDir;
243 QDir defaultRepositoryLocationDir;
239 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
244 if (defaultRepositoryLocationDir.mkpath(defaultRepositoryLocation)) {
240 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
245 defaultRepositoryLocationDir.cd(defaultRepositoryLocation);
241 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
246 auto defaultRepository = defaultRepositoryLocationDir.absoluteFilePath(REPOSITORY_DEFAULT);
242 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
247 qCInfo(LOG_CatalogueController()) << tr("Persistant data loading from: ")
243 << defaultRepository;
248 << defaultRepository;
244 this->addDB(defaultRepository);
249 this->addDB(defaultRepository);
245 }
250 }
246 else {
251 else {
247 qCWarning(LOG_CatalogueController())
252 qCWarning(LOG_CatalogueController())
248 << tr("Cannot load the persistent default repository from ")
253 << tr("Cannot load the persistent default repository from ")
249 << defaultRepositoryLocation;
254 << defaultRepositoryLocation;
250 }
255 }
251
256
252 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
257 qCDebug(LOG_CatalogueController()) << tr("CatalogueController init END");
253 }
258 }
254
259
255 void CatalogueController::finalize()
260 void CatalogueController::finalize()
256 {
261 {
257 impl->m_WorkingMutex.unlock();
262 impl->m_WorkingMutex.unlock();
258 }
263 }
259
264
260 void CatalogueController::waitForFinish()
265 void CatalogueController::waitForFinish()
261 {
266 {
262 QMutexLocker locker{&impl->m_WorkingMutex};
267 QMutexLocker locker{&impl->m_WorkingMutex};
263 }
268 }
264
269
265 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
270 void CatalogueController::CatalogueControllerPrivate::copyDBtoDB(const QString &dbFrom,
266 const QString &dbTo)
271 const QString &dbTo)
267 {
272 {
268 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
273 auto cataloguesShared = std::list<std::shared_ptr<DBCatalogue> >{};
269 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
274 auto catalogues = m_CatalogueDao.getCatalogues(dbFrom);
270 for (auto catalogue : catalogues) {
275 for (auto catalogue : catalogues) {
271 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
276 cataloguesShared.push_back(std::make_shared<DBCatalogue>(catalogue));
272 }
277 }
273
278
274 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
279 auto eventsShared = std::list<std::shared_ptr<DBEvent> >{};
275 auto events = m_CatalogueDao.getEvents(dbFrom);
280 auto events = m_CatalogueDao.getEvents(dbFrom);
276 for (auto event : events) {
281 for (auto event : events) {
277 eventsShared.push_back(std::make_shared<DBEvent>(event));
282 eventsShared.push_back(std::make_shared<DBEvent>(event));
278 }
283 }
279
284
280 for (auto catalogue : cataloguesShared) {
285 for (auto catalogue : cataloguesShared) {
281 m_CatalogueDao.copyCatalogue(*catalogue, dbTo, true);
286 m_CatalogueDao.copyCatalogue(*catalogue, dbTo, true);
282 }
287 }
283
288
284 for (auto event : eventsShared) {
289 for (auto event : eventsShared) {
285 m_CatalogueDao.copyEvent(*event, dbTo, true);
290 m_CatalogueDao.copyEvent(*event, dbTo, true);
286 }
291 }
287 }
292 }
288
293
289 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
294 QString CatalogueController::CatalogueControllerPrivate::toWorkRepository(QString repository)
290 {
295 {
291 auto syncRepository = toSyncRepository(repository);
296 auto syncRepository = toSyncRepository(repository);
292
297
293 return QString("%1_%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
298 return QString("%1%2").arg(syncRepository, REPOSITORY_WORK_SUFFIX);
294 }
299 }
295
300
296 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
301 QString CatalogueController::CatalogueControllerPrivate::toSyncRepository(QString repository)
297 {
302 {
298 auto syncRepository = repository;
303 auto syncRepository = repository;
299 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
304 if (repository.endsWith(REPOSITORY_WORK_SUFFIX)) {
300 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
305 syncRepository.remove(REPOSITORY_WORK_SUFFIX);
301 }
306 }
302 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
307 else if (repository.endsWith(REPOSITORY_TRASH_SUFFIX)) {
303 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
308 syncRepository.remove(REPOSITORY_TRASH_SUFFIX);
304 }
309 }
305 return syncRepository;
310 return syncRepository;
306 }
311 }
312
313 void CatalogueController::CatalogueControllerPrivate::savAllDB()
314 {
315 for (auto repository : m_RepositoryList) {
316 auto defaultRepositoryLocation
317 = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
318 m_CatalogueDao.saveDB(defaultRepositoryLocation, repository);
319 }
320 }
321
322 void CatalogueController::CatalogueControllerPrivate::saveEvent(std::shared_ptr<DBEvent> event,
323 bool persist)
324 {
325 m_CatalogueDao.moveEvent(*event, toSyncRepository(event->getRepository()), true);
326 if (persist) {
327 savAllDB();
328 }
329 }
330
331 void CatalogueController::CatalogueControllerPrivate::saveCatalogue(
332 std::shared_ptr<DBCatalogue> catalogue, bool persist)
333 {
334 m_CatalogueDao.moveCatalogue(*catalogue, toSyncRepository(catalogue->getRepository()), true);
335 if (persist) {
336 savAllDB();
337 }
338 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

Status change > Approved

You need to be logged in to leave comments. Login now