Repository: getredash/redash

Issue:
No invitation link after adding a new user when email server is not configured
<!--

We use GitHub only for bug reports 🐛

Anything else should be posted to https://discuss.redash.io 👫

🚨For support, help & questions use https://discuss.redash.io/c/support
💡For feature requests & ideas use https://discuss.redash.io/c/feature-requests

**Found a security vulnerability?** Please email security@redash.io to report any security vulnerabilities. We will acknowledge receipt of your vulnerability and strive to send you regular updates about our progress. If you're curious about the status of your disclosure please feel free to email us again. If you want to encrypt your disclosure email, you can use this PGP key.

-->

### Issue Summary

After #3267 and #3229 admins no longer receive a link to invite users when the server doesn't have an email server configured.

### Steps to Reproduce

1. Open `/users/new` in a server without email configured (e.g.: [preview](https://redash-preview.netlify.com/users/new))
2. Create a new user and check that no link is provided.
3. Open the pending invitation User Profile and notice there's only the "Resend" option (again it leads to nowhere)

Any other info e.g. Why do you consider this to be a bug? What did you expect to happen instead?
The admin should receive a link to send to the user manually.

### Technical details:

* Redash Version: Latest (Redash Preview)
* Browser/OS: --
* How did you install Redash: --



Discussion:

Resolving patch:
diff --git a/redash/handlers/users.py b/redash/handlers/users.py
--- a/redash/handlers/users.py
+++ b/redash/handlers/users.py
@@ -15,6 +15,7 @@
 
 from redash.authentication.account import invite_link_for_user, send_invite_email, send_password_reset_email, send_verify_email
 from redash.settings import parse_boolean
+from redash import settings
 
 
 # Ordering map for relationships
@@ -36,9 +37,17 @@
 )
 
 
-def invite_user(org, inviter, user):
+def invite_user(org, inviter, user, send_email=True):
+    email_configured = settings.MAIL_DEFAULT_SENDER is not None
+    d = user.to_dict()
+
     invite_url = invite_link_for_user(user)
-    send_invite_email(inviter, user, invite_url, org)
+    if email_configured and send_email:
+        send_invite_email(inviter, user, invite_url, org)
+    else:
+        d['invite_link'] = invite_url
+
+    return d
 
 
 class UserListResource(BaseResource):
@@ -137,19 +146,14 @@ def post(self):
         })
 
         should_send_invitation = 'no_invite' not in request.args
-        if should_send_invitation:
-            invite_user(self.current_org, self.current_user, user)
-
-        return user.to_dict()
+        return invite_user(self.current_org, self.current_user, user, send_email=should_send_invitation)
 
 
 class UserInviteResource(BaseResource):
     @require_admin
     def post(self, user_id):
         user = models.User.get_by_id_and_org(user_id, self.current_org)
-        invite_url = invite_user(self.current_org, self.current_user, user)
-
-        return user.to_dict()
+        return invite_user(self.current_org, self.current_user, user)
 
 
 class UserResetPasswordResource(BaseResource):


Test patch:
diff --git a/client/app/components/users/UserShow.test.js b/client/app/components/users/UserShow.test.js
--- a/client/app/components/users/UserShow.test.js
+++ b/client/app/components/users/UserShow.test.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import renderer from 'react-test-renderer';
-import { UserShow } from './UserShow';
+import UserShow from './UserShow';
 
 test('renders correctly', () => {
   const user = {
diff --git a/tests/handlers/test_users.py b/tests/handlers/test_users.py
--- a/tests/handlers/test_users.py
+++ b/tests/handlers/test_users.py
@@ -1,4 +1,4 @@
-from redash import models
+from redash import models, settings
 from tests import BaseTestCase
 from mock import patch
 
@@ -40,6 +40,34 @@ def test_creates_user(self):
         self.assertEqual(rv.json['name'], test_user['name'])
         self.assertEqual(rv.json['email'], test_user['email'])
 
+    def test_shows_invite_link_when_email_is_not_configured(self):
+        previous = settings.MAIL_DEFAULT_SENDER
+        settings.MAIL_DEFAULT_SENDER = None
+
+        admin = self.factory.create_admin()
+
+        test_user = {'name': 'User', 'email': 'user@example.com'}
+        rv = self.make_request('post', '/api/users', data=test_user, user=admin)
+
+        self.assertEqual(rv.status_code, 200)
+        self.assertTrue('invite_link' in rv.json)
+
+        settings.MAIL_DEFAULT_SENDER = previous
+
+    def test_does_not_show_invite_link_when_email_is_configured(self):
+        previous = settings.MAIL_DEFAULT_SENDER
+        settings.MAIL_DEFAULT_SENDER = "john@doe.com"
+
+        admin = self.factory.create_admin()
+
+        test_user = {'name': 'User', 'email': 'user@example.com'}
+        rv = self.make_request('post', '/api/users', data=test_user, user=admin)
+
+        self.assertEqual(rv.status_code, 200)
+        self.assertFalse('invite_link' in rv.json)
+
+        settings.MAIL_DEFAULT_SENDER = previous
+
     def test_creates_user_case_insensitive_email(self):
         admin = self.factory.create_admin()