+
+bool Core::changeUserPass(const QString &username)
+{
+ QTextStream out(stdout);
+ QTextStream in(stdin);
+ UserId userId = _storage->getUserId(username);
+ if (!userId.isValid()) {
+ out << "User " << username << " does not exist." << endl;
+ return false;
+ }
+
+ if (!canChangeUserPassword(userId))
+ {
+ out << "User " << username << " is configured through an auth provider that has forbidden manual password changing." << endl;
+ return false;
+ }
+
+ out << "Change password for user: " << username << endl;
+
+ disableStdInEcho();
+ out << "New Password: ";
+ out.flush();
+ QString password = in.readLine().trimmed();
+ out << endl;
+ out << "Repeat Password: ";
+ out.flush();
+ QString password2 = in.readLine().trimmed();
+ out << endl;
+ enableStdInEcho();
+
+ if (password != password2) {
+ qWarning() << "Passwords don't match!";
+ return false;
+ }
+ if (password.isEmpty()) {
+ qWarning() << "Password is empty!";
+ return false;
+ }
+
+ if (_configured && _storage->updateUser(userId, password)) {
+ out << "Password changed successfully!" << endl;
+ return true;
+ }
+ else {
+ qWarning() << "Failed to change password!";
+ return false;
+ }
+}
+
+
+bool Core::changeUserPassword(UserId userId, const QString &password)
+{
+ if (!isConfigured() || !userId.isValid())
+ return false;
+
+ if (!canChangeUserPassword(userId))
+ return false;
+
+ return instance()->_storage->updateUser(userId, password);
+}
+
+// TODO: this code isn't currently 100% optimal because the core
+// doesn't know it can have multiple auth providers configured (there aren't
+// multiple auth providers at the moment anyway) and we have hardcoded the
+// Database provider to be always allowed.
+bool Core::canChangeUserPassword(UserId userId)
+{
+ QString authProvider = instance()->_storage->getUserAuthenticator(userId);
+ if (authProvider != "Database")
+ {
+ if (authProvider != instance()->_authenticator->backendId()) {
+ return false;
+ } else if (instance()->_authenticator->canChangePassword()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+AbstractSqlMigrationReader *Core::getMigrationReader(Storage *storage)
+{
+ if (!storage)
+ return 0;
+
+ AbstractSqlStorage *sqlStorage = qobject_cast<AbstractSqlStorage *>(storage);
+ if (!sqlStorage) {
+ qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
+ return 0;
+ }
+
+ return sqlStorage->createMigrationReader();
+}
+
+
+AbstractSqlMigrationWriter *Core::getMigrationWriter(Storage *storage)
+{
+ if (!storage)
+ return 0;
+
+ AbstractSqlStorage *sqlStorage = qobject_cast<AbstractSqlStorage *>(storage);
+ if (!sqlStorage) {
+ qDebug() << "Core::migrateDb(): only SQL based backends can be migrated!";
+ return 0;
+ }
+
+ return sqlStorage->createMigrationWriter();
+}
+
+
+bool Core::saveBackendSettings(const QString &backend, const QVariantMap &settings)
+{
+ QVariantMap dbsettings;
+ dbsettings["Backend"] = backend;
+ dbsettings["ConnectionProperties"] = settings;
+ CoreSettings s = CoreSettings();
+ s.setStorageSettings(dbsettings);
+ return s.sync();
+}
+
+void Core::saveAuthenticatorSettings(const QString &backend, const QVariantMap &settings)
+{
+ QVariantMap dbsettings;
+ dbsettings["Authenticator"] = backend;
+ dbsettings["ConnectionProperties"] = settings;
+ CoreSettings().setAuthSettings(dbsettings);
+}
+
+// Generic version of promptForSettings that doesn't care what *type* of
+// backend it runs over.
+QVariantMap Core::promptForSettings(QStringList keys, QVariantMap defaults)
+{
+ QVariantMap settings;
+
+ if (keys.isEmpty())
+ return settings;
+
+ QTextStream out(stdout);
+ QTextStream in(stdin);
+ out << "Default values are in brackets" << endl;
+
+ QString value;
+ foreach(QString key, keys) {
+ QVariant val;
+ if (defaults.contains(key)) {
+ val = defaults[key];
+ }
+ out << key;
+ if (!val.toString().isEmpty()) {
+ out << " (" << val.toString() << ")";
+ }
+ out << ": ";
+ out.flush();
+
+ bool noEcho = QString("password").toLower().startsWith(key.toLower());
+ if (noEcho) {
+ disableStdInEcho();
+ }
+ value = in.readLine().trimmed();
+ if (noEcho) {
+ out << endl;
+ enableStdInEcho();
+ }
+
+ if (!value.isEmpty()) {
+ switch (defaults[key].type()) {
+ case QVariant::Int:
+ val = QVariant(value.toInt());
+ break;
+ default:
+ val = QVariant(value);
+ }
+ }
+ settings[key] = val;
+ }
+ return settings;
+}
+
+// Since an auth and storage backend work basically the same way,
+// use polymorphism here on this routine.
+QVariantMap Core::promptForSettings(const Storage *storage)
+{
+ QStringList keys = storage->setupKeys();
+ QVariantMap defaults = storage->setupDefaults();
+ return Core::promptForSettings(keys, defaults);