prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Admin panel - Add ability to import multiple users at once
  It would be nice to add a list of users as a bulk list of newline delimited users.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `jupyterhub/apihandlers/users.py`
  Content:
  ```
  1 """User handlers"""
  2 
  3 # Copyright (c) Jupyter Development Team.
  4 # Distributed under the terms of the Modified BSD License.
  5 
  6 import json
  7 
  8 from tornado import gen, web
  9 
  10 from .. import orm
  11 from ..utils import admin_only
  12 from .base import APIHandler
  13 
  14 
  15 class UserListAPIHandler(APIHandler):
  16     @admin_only
  17     def get(self):
  18         users = self.db.query(orm.User)
  19         data = [ self.user_model(u) for u in users ]
  20         self.write(json.dumps(data))
  21 
  22 
  23 def admin_or_self(method):
  24     """Decorator for restricting access to either the target user or admin"""
  25     def m(self, name):
  26         current = self.get_current_user()
  27         if current is None:
  28             raise web.HTTPError(403)
  29         if not (current.name == name or current.admin):
  30             raise web.HTTPError(403)
  31         
  32         # raise 404 if not found
  33         if not self.find_user(name):
  34             raise web.HTTPError(404)
  35         return method(self, name)
  36     return m
  37 
  38 class UserAPIHandler(APIHandler):
  39     
  40     @admin_or_self
  41     def get(self, name):
  42         user = self.find_user(name)
  43         self.write(json.dumps(self.user_model(user)))
  44     
  45     @admin_only
  46     @gen.coroutine
  47     def post(self, name):
  48         data = self.get_json_body()
  49         user = self.find_user(name)
  50         if user is not None:
  51             raise web.HTTPError(400, "User %s already exists" % name)
  52         
  53         user = self.user_from_username(name)
  54         if data:
  55             self._check_user_model(data)
  56             if 'admin' in data:
  57                 user.admin = data['admin']
  58                 self.db.commit()
  59         
  60         try:
  61             yield gen.maybe_future(self.authenticator.add_user(user))
  62         except Exception:
  63             self.log.error("Failed to create user: %s" % name, exc_info=True)
  64             self.db.delete(user)
  65             self.db.commit()
  66             raise web.HTTPError(400, "Failed to create user: %s" % name)
  67         
  68         self.write(json.dumps(self.user_model(user)))
  69         self.set_status(201)
  70     
  71     @admin_only
  72     @gen.coroutine
  73     def delete(self, name):
  74         user = self.find_user(name)
  75         if user is None:
  76             raise web.HTTPError(404)
  77         if user.name == self.get_current_user().name:
  78             raise web.HTTPError(400, "Cannot delete yourself!")
  79         if user.stop_pending:
  80             raise web.HTTPError(400, "%s's server is in the process of stopping, please wait." % name)
  81         if user.running:
  82             yield self.stop_single_user(user)
  83             if user.stop_pending:
  84                 raise web.HTTPError(400, "%s's server is in the process of stopping, please wait." % name)
  85         
  86         yield gen.maybe_future(self.authenticator.delete_user(user))
  87         
  88         # remove from the db
  89         self.db.delete(user)
  90         self.db.commit()
  91         
  92         self.set_status(204)
  93     
  94     @admin_only
  95     def patch(self, name):
  96         user = self.find_user(name)
  97         if user is None:
  98             raise web.HTTPError(404)
  99         data = self.get_json_body()
  100         self._check_user_model(data)
  101         for key, value in data.items():
  102             setattr(user, key, value)
  103         self.db.commit()
  104         self.write(json.dumps(self.user_model(user)))
  105 
  106 
  107 class UserServerAPIHandler(APIHandler):
  108     @gen.coroutine
  109     @admin_or_self
  110     def post(self, name):
  111         user = self.find_user(name)
  112         if user.spawner:
  113             state = yield user.spawner.poll()
  114             if state is None:
  115                 raise web.HTTPError(400, "%s's server is already running" % name)
  116 
  117         yield self.spawn_single_user(user)
  118         status = 202 if user.spawn_pending else 201
  119         self.set_status(status)
  120 
  121     @gen.coroutine
  122     @admin_or_self
  123     def delete(self, name):
  124         user = self.find_user(name)
  125         if user.stop_pending:
  126             self.set_status(202)
  127             return
  128         if not user.running:
  129             raise web.HTTPError(400, "%s's server is not running" % name)
  130         status = yield user.spawner.poll()
  131         if status is not None:
  132             raise web.HTTPError(400, "%s's server is not running" % name)
  133         yield self.stop_single_user(user)
  134         status = 202 if user.stop_pending else 204
  135         self.set_status(status)
  136 
  137 class UserAdminAccessAPIHandler(APIHandler):
  138     """Grant admins access to single-user servers
  139     
  140     This handler sets the necessary cookie for an admin to login to a single-user server.
  141     """
  142     @admin_only
  143     def post(self, name):
  144         current = self.get_current_user()
  145         self.log.warn("Admin user %s has requested access to %s's server",
  146             current.name, name,
  147         )
  148         if not self.settings.get('admin_access', False):
  149             raise web.HTTPError(403, "admin access to user servers disabled")
  150         user = self.find_user(name)
  151         if user is None:
  152             raise web.HTTPError(404)
  153         if not user.running:
  154             raise web.HTTPError(400, "%s's server is not running" % name)
  155         self.set_server_cookie(user)
  156 
  157 
  158 default_handlers = [
  159     (r"/api/users", UserListAPIHandler),
  160     (r"/api/users/([^/]+)", UserAPIHandler),
  161     (r"/api/users/([^/]+)/server", UserServerAPIHandler),
  162     (r"/api/users/([^/]+)/admin-access", UserAdminAccessAPIHandler),
  163 ]
  164
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py
  --- a/jupyterhub/apihandlers/users.py
  +++ b/jupyterhub/apihandlers/users.py
  @@ -18,6 +18,49 @@
           users = self.db.query(orm.User)
           data = [ self.user_model(u) for u in users ]
           self.write(json.dumps(data))
  +    
  +    @admin_only
  +    @gen.coroutine
  +    def post(self):
  +        data = self.get_json_body()
  +        if not data or not isinstance(data, dict) or not data.get('usernames'):
  +            raise web.HTTPError(400, "Must specify at least one user to create")
  +        
  +        usernames = data.pop('usernames')
  +        self._check_user_model(data)
  +        # admin is set for all users
  +        # to create admin and non-admin users requires at least two API requests
  +        admin = data.get('admin', False)
  +        
  +        to_create = []
  +        for name in usernames:
  +            user = self.find_user(name)
  +            if user is not None:
  +                self.log.warn("User %s already exists" % name)
  +            else:
  +                to_create.append(name)
  +        
  +        if not to_create:
  +            raise web.HTTPError(400, "All %i users already exist" % len(usernames))
  +        
  +        created = []
  +        for name in to_create:
  +            user = self.user_from_username(name)
  +            if admin:
  +                user.admin = True
  +                self.db.commit()
  +            try:
  +                yield gen.maybe_future(self.authenticator.add_user(user))
  +            except Exception:
  +                self.log.error("Failed to create user: %s" % name, exc_info=True)
  +                self.db.delete(user)
  +                self.db.commit()
  +                raise web.HTTPError(400, "Failed to create user: %s" % name)
  +            else:
  +                created.append(user)
  +        
  +        self.write(json.dumps([ self.user_model(u) for u in created ]))
  +        self.set_status(201)
   
   
   def admin_or_self(method):
  
verification_info: {"golden_diff": "diff --git a/jupyterhub/apihandlers/users.py b/jupyterhub/apihandlers/users.py\n--- a/jupyterhub/apihandlers/users.py\n+++ b/jupyterhub/apihandlers/users.py\n@@ -18,6 +18,49 @@\n         users = self.db.query(orm.User)\n         data = [ self.user_model(u) for u in users ]\n         self.write(json.dumps(data))\n+    \n+    @admin_only\n+    @gen.coroutine\n+    def post(self):\n+        data = self.get_json_body()\n+        if not data or not isinstance(data, dict) or not data.get('usernames'):\n+            raise web.HTTPError(400, \"Must specify at least one user to create\")\n+        \n+        usernames = data.pop('usernames')\n+        self._check_user_model(data)\n+        # admin is set for all users\n+        # to create admin and non-admin users requires at least two API requests\n+        admin = data.get('admin', False)\n+        \n+        to_create = []\n+        for name in usernames:\n+            user = self.find_user(name)\n+            if user is not None:\n+                self.log.warn(\"User %s already exists\" % name)\n+            else:\n+                to_create.append(name)\n+        \n+        if not to_create:\n+            raise web.HTTPError(400, \"All %i users already exist\" % len(usernames))\n+        \n+        created = []\n+        for name in to_create:\n+            user = self.user_from_username(name)\n+            if admin:\n+                user.admin = True\n+                self.db.commit()\n+            try:\n+                yield gen.maybe_future(self.authenticator.add_user(user))\n+            except Exception:\n+                self.log.error(\"Failed to create user: %s\" % name, exc_info=True)\n+                self.db.delete(user)\n+                self.db.commit()\n+                raise web.HTTPError(400, \"Failed to create user: %s\" % name)\n+            else:\n+                created.append(user)\n+        \n+        self.write(json.dumps([ self.user_model(u) for u in created ]))\n+        self.set_status(201)\n \n \n def admin_or_self(method):\n", "issue": "Admin panel - Add ability to import multiple users at once\nIt would be nice to add a list of users as a bulk list of newline delimited users.\n\n", "before_files": [{"content": "\"\"\"User handlers\"\"\"\n\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nimport json\n\nfrom tornado import gen, web\n\nfrom .. import orm\nfrom ..utils import admin_only\nfrom .base import APIHandler\n\n\nclass UserListAPIHandler(APIHandler):\n    @admin_only\n    def get(self):\n        users = self.db.query(orm.User)\n        data = [ self.user_model(u) for u in users ]\n        self.write(json.dumps(data))\n\n\ndef admin_or_self(method):\n    \"\"\"Decorator for restricting access to either the target user or admin\"\"\"\n    def m(self, name):\n        current = self.get_current_user()\n        if current is None:\n            raise web.HTTPError(403)\n        if not (current.name == name or current.admin):\n            raise web.HTTPError(403)\n        \n        # raise 404 if not found\n        if not self.find_user(name):\n            raise web.HTTPError(404)\n        return method(self, name)\n    return m\n\nclass UserAPIHandler(APIHandler):\n    \n    @admin_or_self\n    def get(self, name):\n        user = self.find_user(name)\n        self.write(json.dumps(self.user_model(user)))\n    \n    @admin_only\n    @gen.coroutine\n    def post(self, name):\n        data = self.get_json_body()\n        user = self.find_user(name)\n        if user is not None:\n            raise web.HTTPError(400, \"User %s already exists\" % name)\n        \n        user = self.user_from_username(name)\n        if data:\n            self._check_user_model(data)\n            if 'admin' in data:\n                user.admin = data['admin']\n                self.db.commit()\n        \n        try:\n            yield gen.maybe_future(self.authenticator.add_user(user))\n        except Exception:\n            self.log.error(\"Failed to create user: %s\" % name, exc_info=True)\n            self.db.delete(user)\n            self.db.commit()\n            raise web.HTTPError(400, \"Failed to create user: %s\" % name)\n        \n        self.write(json.dumps(self.user_model(user)))\n        self.set_status(201)\n    \n    @admin_only\n    @gen.coroutine\n    def delete(self, name):\n        user = self.find_user(name)\n        if user is None:\n            raise web.HTTPError(404)\n        if user.name == self.get_current_user().name:\n            raise web.HTTPError(400, \"Cannot delete yourself!\")\n        if user.stop_pending:\n            raise web.HTTPError(400, \"%s's server is in the process of stopping, please wait.\" % name)\n        if user.running:\n            yield self.stop_single_user(user)\n            if user.stop_pending:\n                raise web.HTTPError(400, \"%s's server is in the process of stopping, please wait.\" % name)\n        \n        yield gen.maybe_future(self.authenticator.delete_user(user))\n        \n        # remove from the db\n        self.db.delete(user)\n        self.db.commit()\n        \n        self.set_status(204)\n    \n    @admin_only\n    def patch(self, name):\n        user = self.find_user(name)\n        if user is None:\n            raise web.HTTPError(404)\n        data = self.get_json_body()\n        self._check_user_model(data)\n        for key, value in data.items():\n            setattr(user, key, value)\n        self.db.commit()\n        self.write(json.dumps(self.user_model(user)))\n\n\nclass UserServerAPIHandler(APIHandler):\n    @gen.coroutine\n    @admin_or_self\n    def post(self, name):\n        user = self.find_user(name)\n        if user.spawner:\n            state = yield user.spawner.poll()\n            if state is None:\n                raise web.HTTPError(400, \"%s's server is already running\" % name)\n\n        yield self.spawn_single_user(user)\n        status = 202 if user.spawn_pending else 201\n        self.set_status(status)\n\n    @gen.coroutine\n    @admin_or_self\n    def delete(self, name):\n        user = self.find_user(name)\n        if user.stop_pending:\n            self.set_status(202)\n            return\n        if not user.running:\n            raise web.HTTPError(400, \"%s's server is not running\" % name)\n        status = yield user.spawner.poll()\n        if status is not None:\n            raise web.HTTPError(400, \"%s's server is not running\" % name)\n        yield self.stop_single_user(user)\n        status = 202 if user.stop_pending else 204\n        self.set_status(status)\n\nclass UserAdminAccessAPIHandler(APIHandler):\n    \"\"\"Grant admins access to single-user servers\n    \n    This handler sets the necessary cookie for an admin to login to a single-user server.\n    \"\"\"\n    @admin_only\n    def post(self, name):\n        current = self.get_current_user()\n        self.log.warn(\"Admin user %s has requested access to %s's server\",\n            current.name, name,\n        )\n        if not self.settings.get('admin_access', False):\n            raise web.HTTPError(403, \"admin access to user servers disabled\")\n        user = self.find_user(name)\n        if user is None:\n            raise web.HTTPError(404)\n        if not user.running:\n            raise web.HTTPError(400, \"%s's server is not running\" % name)\n        self.set_server_cookie(user)\n\n\ndefault_handlers = [\n    (r\"/api/users\", UserListAPIHandler),\n    (r\"/api/users/([^/]+)\", UserAPIHandler),\n    (r\"/api/users/([^/]+)/server\", UserServerAPIHandler),\n    (r\"/api/users/([^/]+)/admin-access\", UserAdminAccessAPIHandler),\n]\n", "path": "jupyterhub/apihandlers/users.py"}], "after_files": [{"content": "\"\"\"User handlers\"\"\"\n\n# Copyright (c) Jupyter Development Team.\n# Distributed under the terms of the Modified BSD License.\n\nimport json\n\nfrom tornado import gen, web\n\nfrom .. import orm\nfrom ..utils import admin_only\nfrom .base import APIHandler\n\n\nclass UserListAPIHandler(APIHandler):\n    @admin_only\n    def get(self):\n        users = self.db.query(orm.User)\n        data = [ self.user_model(u) for u in users ]\n        self.write(json.dumps(data))\n    \n    @admin_only\n    @gen.coroutine\n    def post(self):\n        data = self.get_json_body()\n        if not data or not isinstance(data, dict) or not data.get('usernames'):\n            raise web.HTTPError(400, \"Must specify at least one user to create\")\n        \n        usernames = data.pop('usernames')\n        self._check_user_model(data)\n        # admin is set for all users\n        # to create admin and non-admin users requires at least two API requests\n        admin = data.get('admin', False)\n        \n        to_create = []\n        for name in usernames:\n            user = self.find_user(name)\n            if user is not None:\n                self.log.warn(\"User %s already exists\" % name)\n            else:\n                to_create.append(name)\n        \n        if not to_create:\n            raise web.HTTPError(400, \"All %i users already exist\" % len(usernames))\n        \n        created = []\n        for name in to_create:\n            user = self.user_from_username(name)\n            if admin:\n                user.admin = True\n                self.db.commit()\n            try:\n                yield gen.maybe_future(self.authenticator.add_user(user))\n            except Exception:\n                self.log.error(\"Failed to create user: %s\" % name, exc_info=True)\n                self.db.delete(user)\n                self.db.commit()\n                raise web.HTTPError(400, \"Failed to create user: %s\" % name)\n            else:\n                created.append(user)\n        \n        self.write(json.dumps([ self.user_model(u) for u in created ]))\n        self.set_status(201)\n\n\ndef admin_or_self(method):\n    \"\"\"Decorator for restricting access to either the target user or admin\"\"\"\n    def m(self, name):\n        current = self.get_current_user()\n        if current is None:\n            raise web.HTTPError(403)\n        if not (current.name == name or current.admin):\n            raise web.HTTPError(403)\n        \n        # raise 404 if not found\n        if not self.find_user(name):\n            raise web.HTTPError(404)\n        return method(self, name)\n    return m\n\nclass UserAPIHandler(APIHandler):\n    \n    @admin_or_self\n    def get(self, name):\n        user = self.find_user(name)\n        self.write(json.dumps(self.user_model(user)))\n    \n    @admin_only\n    @gen.coroutine\n    def post(self, name):\n        data = self.get_json_body()\n        user = self.find_user(name)\n        if user is not None:\n            raise web.HTTPError(400, \"User %s already exists\" % name)\n        \n        user = self.user_from_username(name)\n        if data:\n            self._check_user_model(data)\n            if 'admin' in data:\n                user.admin = data['admin']\n                self.db.commit()\n        \n        try:\n            yield gen.maybe_future(self.authenticator.add_user(user))\n        except Exception:\n            self.log.error(\"Failed to create user: %s\" % name, exc_info=True)\n            self.db.delete(user)\n            self.db.commit()\n            raise web.HTTPError(400, \"Failed to create user: %s\" % name)\n        \n        self.write(json.dumps(self.user_model(user)))\n        self.set_status(201)\n    \n    @admin_only\n    @gen.coroutine\n    def delete(self, name):\n        user = self.find_user(name)\n        if user is None:\n            raise web.HTTPError(404)\n        if user.name == self.get_current_user().name:\n            raise web.HTTPError(400, \"Cannot delete yourself!\")\n        if user.stop_pending:\n            raise web.HTTPError(400, \"%s's server is in the process of stopping, please wait.\" % name)\n        if user.running:\n            yield self.stop_single_user(user)\n            if user.stop_pending:\n                raise web.HTTPError(400, \"%s's server is in the process of stopping, please wait.\" % name)\n        \n        yield gen.maybe_future(self.authenticator.delete_user(user))\n        \n        # remove from the db\n        self.db.delete(user)\n        self.db.commit()\n        \n        self.set_status(204)\n    \n    @admin_only\n    def patch(self, name):\n        user = self.find_user(name)\n        if user is None:\n            raise web.HTTPError(404)\n        data = self.get_json_body()\n        self._check_user_model(data)\n        for key, value in data.items():\n            setattr(user, key, value)\n        self.db.commit()\n        self.write(json.dumps(self.user_model(user)))\n\n\nclass UserServerAPIHandler(APIHandler):\n    @gen.coroutine\n    @admin_or_self\n    def post(self, name):\n        user = self.find_user(name)\n        if user.spawner:\n            state = yield user.spawner.poll()\n            if state is None:\n                raise web.HTTPError(400, \"%s's server is already running\" % name)\n\n        yield self.spawn_single_user(user)\n        status = 202 if user.spawn_pending else 201\n        self.set_status(status)\n\n    @gen.coroutine\n    @admin_or_self\n    def delete(self, name):\n        user = self.find_user(name)\n        if user.stop_pending:\n            self.set_status(202)\n            return\n        if not user.running:\n            raise web.HTTPError(400, \"%s's server is not running\" % name)\n        status = yield user.spawner.poll()\n        if status is not None:\n            raise web.HTTPError(400, \"%s's server is not running\" % name)\n        yield self.stop_single_user(user)\n        status = 202 if user.stop_pending else 204\n        self.set_status(status)\n\nclass UserAdminAccessAPIHandler(APIHandler):\n    \"\"\"Grant admins access to single-user servers\n    \n    This handler sets the necessary cookie for an admin to login to a single-user server.\n    \"\"\"\n    @admin_only\n    def post(self, name):\n        current = self.get_current_user()\n        self.log.warn(\"Admin user %s has requested access to %s's server\",\n            current.name, name,\n        )\n        if not self.settings.get('admin_access', False):\n            raise web.HTTPError(403, \"admin access to user servers disabled\")\n        user = self.find_user(name)\n        if user is None:\n            raise web.HTTPError(404)\n        if not user.running:\n            raise web.HTTPError(400, \"%s's server is not running\" % name)\n        self.set_server_cookie(user)\n\n\ndefault_handlers = [\n    (r\"/api/users\", UserListAPIHandler),\n    (r\"/api/users/([^/]+)\", UserAPIHandler),\n    (r\"/api/users/([^/]+)/server\", UserServerAPIHandler),\n    (r\"/api/users/([^/]+)/admin-access\", UserAdminAccessAPIHandler),\n]\n", "path": "jupyterhub/apihandlers/users.py"}]}