Repository: jupyterhub/jupyterhub

Issue:
Users added with "Add Users" button are not listed in the admin page
**Describe the bug**
Since commit 81a410db91912b0e925fdc3971f46805a648bdaf, the _Add Users_ button does not add new rows in the user table. However, the users count is incremented.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to admin page
2. Click on 'Add Users'
3. Add a username that does not exist in the list.
4. Users number is incremented, but user does not show up in the table.

**Expected behavior**
Users added with the _Add Users_ button should be present in the user table.

**Screenshots**
![image](https://user-images.githubusercontent.com/884095/55194647-b1abc980-5180-11e9-8b36-a5f7d46dd103.png)


**Desktop (please complete the following information):**
 - OS: macOS 
 - Browser: Firefox, Safari, Chrome
 - Version: 10.13.6


**Additional context**
I did a git bisect between 0.9.5 and 1.0.0b1 and found that commit 81a410db91912b0e925fdc3971f46805a648bdaf is when the button stopped working properly.

EDIT 1:
After digging a bit more, it appears that the generator `all_spawners` for users added with the _Add Users_ button is empty.

EDIT 2:
New `jupyterhub.user.User` object begin their _object life_ with 0 spawner. Therefore, `all_spawners` will always be empty for new users added with the _Add Users_ button.

A quick-and-dirty fix is to force the creation of the default spawner by adding the line
```python
self.spawner
``` 
after the creation of `self.spawners` in `jupyterhub.user.User.__init__`.


Discussion:
Quickly jumping in from mobile to say I think this was a very nice writeup!! :heart:

Resolving patch:
diff --git a/jupyterhub/user.py b/jupyterhub/user.py
--- a/jupyterhub/user.py
+++ b/jupyterhub/user.py
@@ -163,6 +163,10 @@ def __init__(self, orm_user, settings=None, db=None):
 
         self.spawners = _SpawnerDict(self._new_spawner)
 
+        # ensure default spawner exists in the database
+        if '' not in self.orm_user.orm_spawners:
+            self._new_orm_spawner('')
+
     @property
     def authenticator(self):
         return self.settings.get('authenticator', None)
@@ -221,6 +225,14 @@ def all_spawners(self, include_default=True):
                 # otherwise, yield low-level ORM object (server is not active)
                 yield orm_spawner
 
+    def _new_orm_spawner(self, server_name):
+        """Creat the low-level orm Spawner object"""
+        orm_spawner = orm.Spawner(user=self.orm_user, name=server_name)
+        self.db.add(orm_spawner)
+        self.db.commit()
+        assert server_name in self.orm_spawners
+        return orm_spawner
+
     def _new_spawner(self, server_name, spawner_class=None, **kwargs):
         """Create a new spawner"""
         if spawner_class is None:
@@ -229,10 +241,7 @@ def _new_spawner(self, server_name, spawner_class=None, **kwargs):
 
         orm_spawner = self.orm_spawners.get(server_name)
         if orm_spawner is None:
-            orm_spawner = orm.Spawner(user=self.orm_user, name=server_name)
-            self.db.add(orm_spawner)
-            self.db.commit()
-            assert server_name in self.orm_spawners
+            orm_spawner = self._new_orm_spawner(server_name)
         if server_name == '' and self.state:
             # migrate user.state to spawner.state
             orm_spawner.state = self.state


Test patch: