diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 8e57a9b683..9c220b740e 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -414,6 +414,7 @@ "name": "group_permissions", "type": "table", "caption": "Permissions for Users in Groups", + "help": "For groups that are provided from WordPress you need to denote them by putting an \"@\" symbol in front of each item, e.g., \"@silver\"". "categorize_by_key": "permissions_id", "can_add_new_categories": true, "can_add_new_rows": false, @@ -542,6 +543,7 @@ "name": "group_forbiddens", "type": "table", "caption": "Permissions Denied to Users in Groups", + "help": "For groups that are provided from WordPress you need to denote them by putting an \"@\" symbol in front of each item, e.g., \"@silver\"". "categorize_by_key": "permissions_id", "can_add_new_categories": true, "can_add_new_rows": false, diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 810a8a37dd..694fd6158f 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -45,6 +45,7 @@ Item { property bool lostFocus: false readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() + // If not logging into domain, then we must be logging into the metaverse... readonly property bool isLoggingInToDomain: loginDialog.getDomainLoginRequested() readonly property string domainLoginDomain: loginDialog.getDomainLoginDomain() @@ -94,7 +95,7 @@ Item { } bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus, - "displayName":displayNameField.text, "isLoggingInToDomain": linkAccountBody.isLoggingInToDomain }); + "displayName":displayNameField.text, "isLoggingInToDomain": linkAccountBody.isLoggingInToDomain, "domainLoginDomain": linkAccountBody.domainLoginDomain }); } function init() { @@ -105,13 +106,15 @@ Item { loginErrorMessage.wrapMode = Text.WordWrap; errorContainer.height = (loginErrorMessageTextMetrics.width / displayNameField.width) * loginErrorMessageTextMetrics.height; } + var domainLoginText = "Log In to Domain\n" + domainLoginDomain; + loginDialogText.text = (!isLoggingInToDomain) ? "Log In to Metaverse" : domainLoginText; loginButton.text = (!linkAccountBody.linkSteam && !linkAccountBody.linkOculus) ? "Log In" : "Link Account"; - loginButton.text = (!isLoggingInToDomain) ? "Log In" : "Log In to Domain"; + loginButton.text = (!isLoggingInToDomain) ? "Log In to Metaverse" : "Log In to Domain"; loginButton.color = hifi.buttons.blue; displayNameField.placeholderText = "Display Name (optional)"; var savedDisplayName = Settings.getValue("Avatar/displayName", ""); displayNameField.text = savedDisplayName; - emailField.placeholderText = "Username or Email"; + emailField.placeholderText = (!isLoggingInToDomain) ? "Username or Email" : "Username"; if (!isLoggingInToDomain) { var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", ""); emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : ""; @@ -144,7 +147,7 @@ Item { Item { id: loginContainer width: displayNameField.width - height: errorContainer.height + displayNameField.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y + + height: errorContainer.height + loginDialogTextContainer.height + displayNameField.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y + keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height anchors { top: parent.top @@ -158,9 +161,10 @@ Item { width: parent.width height: loginErrorMessageTextMetrics.height anchors { - bottom: displayNameField.top; - bottomMargin: hifi.dimensions.contentSpacing.y; - left: displayNameField.left; + bottom: loginDialogTextContainer.top + bottomMargin: hifi.dimensions.contentSpacing.y + left: loginDialogTextContainer.left + right: loginDialogTextContainer.right } TextMetrics { id: loginErrorMessageTextMetrics @@ -173,12 +177,45 @@ Item { font.family: linkAccountBody.fontFamily font.pixelSize: linkAccountBody.textFieldFontSize font.bold: linkAccountBody.fontBold + anchors { + top: parent.top + left: parent.left + right: parent.right + } verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter text: "" visible: false } } + + Item { + id: loginDialogTextContainer + height: 56 + anchors { + top: parent.top + left: parent.left + right: parent.right + topMargin: 1.5 * hifi.dimensions.contentSpacing.y + } + + Text { + id: loginDialogText + text: qsTr("Log In") + lineHeight: 1 + color: "white" + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.family: linkAccountBody.fontFamily + font.pixelSize: 24 + font.bold: linkAccountBody.fontBold + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + } + } HifiControlsUit.TextField { id: displayNameField @@ -187,8 +224,8 @@ Item { font.pixelSize: linkAccountBody.textFieldFontSize styleRenderType: Text.QtRendering anchors { - top: parent.top - topMargin: errorContainer.height + top: loginDialogTextContainer.bottom + topMargin: 1.5 * hifi.dimensions.contentSpacing.y } placeholderText: "Display Name (optional)" activeFocusOnPress: true @@ -352,6 +389,7 @@ Item { labelFontFamily: linkAccountBody.fontFamily labelFontSize: 18; color: hifi.colors.white; + visible: !isLoggingInToDomain anchors { top: passwordField.bottom; topMargin: hifi.dimensions.contentSpacing.y; @@ -436,7 +474,7 @@ Item { font.pixelSize: linkAccountBody.textFieldFontSize font.bold: linkAccountBody.fontBold - text: " Can't access your account?" + text: " Can't access your account?" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter @@ -562,7 +600,7 @@ Item { leftMargin: hifi.dimensions.contentSpacing.x } - text: "Sign Up" + text: "Sign Up" linkColor: hifi.colors.blueAccent onLinkActivated: { diff --git a/interface/resources/qml/LoginDialog/LoggingInBody.qml b/interface/resources/qml/LoginDialog/LoggingInBody.qml index 796798a2de..757c8b7449 100644 --- a/interface/resources/qml/LoginDialog/LoggingInBody.qml +++ b/interface/resources/qml/LoginDialog/LoggingInBody.qml @@ -33,6 +33,7 @@ Item { property bool linkOculus: linkOculus property bool createOculus: createOculus property bool isLoggingInToDomain: isLoggingInToDomain + property string domainLoginDomain: domainLoginDomain property string displayName: "" readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() @@ -109,7 +110,7 @@ Item { loggingInText.text = "Logging in to Oculus"; loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2; } else if (loggingInBody.isLoggingInToDomain) { - loggingInText.text = "Logging in to Domain"; + loggingInText.text = "Logging in to " + domainLoginDomain; loggingInText.anchors.centerIn = loggingInHeader; } else { loggingInText.text = "Logging in"; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2c6702fbfc..eec7d8a5f7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1355,7 +1355,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto domainAccountManager = DependencyManager::get(); connect(domainAccountManager.data(), &DomainAccountManager::authRequired, dialogsManager.data(), &DialogsManager::showDomainLoginDialog); - + + connect(domainAccountManager.data(), &DomainAccountManager::loginComplete, this, + &Application::updateWindowTitle); // ####### TODO: Connect any other signals from domainAccountManager. @@ -1582,7 +1584,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Do not show login dialog if requested not to on the command line QString hifiNoLoginCommandLineKey = QString("--").append(HIFI_NO_LOGIN_COMMAND_LINE_KEY); int index = arguments().indexOf(hifiNoLoginCommandLineKey); - if (index != -1) { + if (index != -1 || _disableLoginScreen) { resumeAfterLoginDialogActionTaken(); return; } @@ -7079,20 +7081,23 @@ void Application::updateWindowTitle() const { auto nodeList = DependencyManager::get(); auto accountManager = DependencyManager::get(); + auto domainAccountManager = DependencyManager::get(); auto isInErrorState = nodeList->getDomainHandler().isInErrorState(); + bool isMetaverseLoggedIn = accountManager->isLoggedIn(); + bool isDomainLoggedIn = domainAccountManager->isLoggedIn(); + QString authedDomain = domainAccountManager->getAuthedDomain(); QString buildVersion = " - Vircadia - " + (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? QString("Version") : QString("Build")) + " " + applicationVersion(); - // ####### TODO - QString loginStatus = accountManager->isLoggedIn() ? "" : " (NOT LOGGED IN)"; - QString connectionStatus = isInErrorState ? " (ERROR CONNECTING)" : nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED)"; - QString username = accountManager->getAccountInfo().getUsername(); - setCrashAnnotation("sentry[user][username]", username.toStdString()); + QString metaverseUsername = accountManager->getAccountInfo().getUsername(); + QString domainUsername = domainAccountManager->getUsername(); + + setCrashAnnotation("sentry[user][metaverseUsername]", metaverseUsername.toStdString()); QString currentPlaceName; if (isServerlessMode()) { @@ -7108,8 +7113,24 @@ void Application::updateWindowTitle() const { } } - QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) - + currentPlaceName + connectionStatus + loginStatus + buildVersion; + QString metaverseDetails; + if (isMetaverseLoggedIn) { + metaverseDetails = "Metaverse: Logged in as " + metaverseUsername; + } else { + metaverseDetails = "Metaverse: Not Logged In"; + } + + QString domainDetails; + if (currentPlaceName == authedDomain && isDomainLoggedIn) { + // ###### TODO + // domainDetails = "Domain: Logged in as " + domainUsername; + domainDetails = "Domain: Logged in as " + domainUsername; + } else { + domainDetails = "Domain: Not Logged In"; + } + + QString title = QString() + currentPlaceName + connectionStatus + " (" + metaverseDetails + ") (" + domainDetails + ")" + + buildVersion; #ifndef WIN32 // crashes with vs2013/win32 diff --git a/interface/src/Application.h b/interface/src/Application.h index 3d4e6873a8..f42696cda0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -733,6 +733,7 @@ private: GraphicsEngine _graphicsEngine; void updateRenderArgs(float deltaTime); + bool _disableLoginScreen { true }; Overlays _overlays; ApplicationOverlay _applicationOverlay; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0ed5f67ea0..64cdf98239 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -9,6 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// For happ(ier) development of QML, use these two things: +// This forces QML files to be pulled from the source as you edit it: set environment variable HIFI_USE_SOURCE_TREE_RESOURCES=1 +// Use this to live reload: DependencyManager::get()->clearCache(); + #include "Menu.h" #include #include @@ -84,6 +88,13 @@ Menu::Menu() { dialogsManager.data(), &DialogsManager::toggleLoginDialog); } + auto domainLogin = addActionToQMenuAndActionHash(fileMenu, "Domain: Log In"); + connect(domainLogin, &QAction::triggered, [] { + auto dialogsManager = DependencyManager::get(); + dialogsManager->setDomainLoginState(); + dialogsManager->showDomainLoginDialog(); + }); + // File > Quit addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, qApp, SLOT(quit()), QAction::QuitRole); diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 6e807c7b9f..ae4f43d6fa 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -110,10 +110,21 @@ void DialogsManager::setDomainConnectionFailureVisibility(bool visible) { } } +void DialogsManager::setMetaverseLoginState() { + // We're only turning off the domain login trigger but the actual domain auth URL is still saved. + // So we can continue the domain login if desired. + _isDomainLogin = false; +} + +void DialogsManager::setDomainLoginState() { + _isDomainLogin = true; +} void DialogsManager::setDomainLogin(bool isDomainLogin, const QString& domain) { _isDomainLogin = isDomainLogin; - _domainLoginDomain = domain; + if (!domain.isEmpty()) { + _domainLoginDomain = domain; + } } void DialogsManager::toggleLoginDialog() { diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index fa5c589fb4..864174296e 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -41,6 +41,8 @@ public: QPointer getTestingDialog() const { return _testingDialog; } void emitAddressBarShown(bool visible) { emit addressBarShown(visible); } void setAddressBarVisible(bool addressBarVisible); + void setMetaverseLoginState(); + void setDomainLoginState(); bool getIsDomainLogin() { return _isDomainLogin; } QString getDomainLoginDomain() { return _domainLoginDomain; } @@ -52,7 +54,7 @@ public slots: void toggleLoginDialog(); void showLoginDialog(); void hideLoginDialog(); - void showDomainLoginDialog(const QString& domain); + void showDomainLoginDialog(const QString& domain = ""); void octreeStatsDetails(); void lodTools(); void hmdTools(bool showTools); diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index c7597c5658..b45a62ae3a 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -99,14 +99,16 @@ void LoginDialog::toggleAction() { if (accountManager->isLoggedIn()) { // change the menu item to logout - loginAction->setText("Logout " + accountManager->getAccountInfo().getUsername()); + loginAction->setText("Metaverse: Logout " + accountManager->getAccountInfo().getUsername()); connection = connect(loginAction, &QAction::triggered, accountManager.data(), &AccountManager::logout); } else { // change the menu item to login - loginAction->setText("Log In / Sign Up"); + loginAction->setText("Metaverse: Log In / Sign Up"); connection = connect(loginAction, &QAction::triggered, [] { // if not in login state, show. if (!qApp->getLoginDialogPoppedUp()) { + auto dialogsManager = DependencyManager::get(); + dialogsManager->setMetaverseLoginState(); LoginDialog::showWithSelection(); } }); diff --git a/libraries/networking/src/DomainAccountManager.cpp b/libraries/networking/src/DomainAccountManager.cpp index 6bb868df61..19c16178e2 100644 --- a/libraries/networking/src/DomainAccountManager.cpp +++ b/libraries/networking/src/DomainAccountManager.cpp @@ -18,7 +18,9 @@ #include #include +#include +#include "NodeList.h" #include "NetworkingConstants.h" #include "NetworkLogging.h" #include "NetworkAccessManager.h" @@ -101,6 +103,8 @@ void DomainAccountManager::requestAccessTokenFinished() { // miniOrange plugin provides no scope. if (rootObject.contains("access_token")) { // Success. + auto nodeList = DependencyManager::get(); + _domain_name = nodeList->getDomainHandler().getHostname(); QUrl rootURL = requestReply->url(); rootURL.setPath(""); setTokensFromJSON(rootObject, rootURL); @@ -133,10 +137,12 @@ bool DomainAccountManager::accessTokenIsExpired() { bool DomainAccountManager::hasValidAccessToken() { - QString currentDomainAccessToken = domainAccessToken.get(); - - if (currentDomainAccessToken.isEmpty() || accessTokenIsExpired()) { + // ###### TODO: wire this up to actually retrieve a token (based on session or storage) and confirm that it is in fact valid and relevant to the current domain. + // QString currentDomainAccessToken = domainAccessToken.get(); + QString currentDomainAccessToken = _access_token; + // if (currentDomainAccessToken.isEmpty() || accessTokenIsExpired()) { + if (currentDomainAccessToken.isEmpty()) { if (VERBOSE_HTTP_REQUEST_DEBUGGING) { qCDebug(networking) << "An access token is required for requests to" << qPrintable(_authURL.toString()); @@ -153,23 +159,20 @@ bool DomainAccountManager::hasValidAccessToken() { return true; } - } void DomainAccountManager::setTokensFromJSON(const QJsonObject& jsonObject, const QUrl& url) { _access_token = jsonObject["access_token"].toString(); _refresh_token = jsonObject["refresh_token"].toString(); - // ####### TODO: Enable and use these. // ####### TODO: Protect these per AccountManager? // ######: TODO: clientID needed? - /* - qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(url.toString()); - domainAccessToken.set(jsonObject["access_token"].toString()); - domainAccessRefreshToken.set(jsonObject["refresh_token"].toString()); - domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000)); - domainAccessTokenType.set(jsonObject["token_type"].toString()); - */ + + // qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(url.toString()); + // domainAccessToken.set(jsonObject["access_token"].toString()); + // domainAccessRefreshToken.set(jsonObject["refresh_token"].toString()); + // domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000)); + // domainAccessTokenType.set(jsonObject["token_type"].toString()); } bool DomainAccountManager::checkAndSignalForAccessToken() { diff --git a/libraries/networking/src/DomainAccountManager.h b/libraries/networking/src/DomainAccountManager.h index 0388ba1f5a..c8bc5e912c 100644 --- a/libraries/networking/src/DomainAccountManager.h +++ b/libraries/networking/src/DomainAccountManager.h @@ -29,6 +29,9 @@ public: QString getUsername() { return _username; } QString getAccessToken() { return _access_token; } QString getRefreshToken() { return _refresh_token; } + QString getAuthedDomain() { return _domain_name; } + + bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); } Q_INVOKABLE bool checkAndSignalForAccessToken(); @@ -57,6 +60,7 @@ private: QString _username; // ####### TODO: Store elsewhere? QString _access_token; // ####... "" QString _refresh_token; // ####... "" + QString _domain_name; // }; #endif // hifi_DomainAccountManager_h