diff --git a/api/examples/create-user b/api/examples/create-user new file mode 100755 index 0000000000..bacfb76a28 --- /dev/null +++ b/api/examples/create-user @@ -0,0 +1,54 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 Zulip, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import sys +from os import path +import optparse + +usage = """create-user --new-email= --new-password= --new-full-name= --new-short-name= [options] + +Create a user. You must be a realm admin to use this API, and the user +will be created in your realm. + +Example: create-user --site=http://localhost:9991 --user=rwbarton@zulip.com --new-email=jarthur@zulip.com --new-password=random17 --new-full-name 'J. Arthur Random' --new-short-name='jarthur' +""" + +sys.path.append(path.join(path.dirname(__file__), '..')) +import zulip + +parser = optparse.OptionParser(usage=usage) +parser.add_option_group(zulip.generate_option_group(parser)) +parser.add_option('--new-email') +parser.add_option('--new-password') +parser.add_option('--new-full-name') +parser.add_option('--new-short-name') +(options, args) = parser.parse_args() + +client = zulip.init_from_options(options) + +print client.create_user({ + 'email': options.new_email, + 'password': options.new_password, + 'full_name': options.new_full_name, + 'short_name': options.new_short_name + }) diff --git a/api/zulip/__init__.py b/api/zulip/__init__.py index e2e4529bb7..c79e84f062 100644 --- a/api/zulip/__init__.py +++ b/api/zulip/__init__.py @@ -360,3 +360,4 @@ Client._register('list_subscriptions', method='GET', url='users/me/subscriptions Client._register('add_subscriptions', url='users/me/subscriptions', make_request=_mk_subs) Client._register('remove_subscriptions', method='PATCH', url='users/me/subscriptions', make_request=_mk_rm_subs) Client._register('render_message', method='GET', url='messages/render') +Client._register('create_user', method='POST', url='users') diff --git a/zerver/forms.py b/zerver/forms.py index 7e7a02bd0d..70d36c3a1a 100644 --- a/zerver/forms.py +++ b/zerver/forms.py @@ -82,6 +82,6 @@ class LoggingSetPasswordForm(SetPasswordForm): log=True, commit=commit) return self.user -class CreateBotForm(forms.Form): +class CreateUserForm(forms.Form): full_name = forms.CharField(max_length=100) email = forms.EmailField() diff --git a/zerver/views/__init__.py b/zerver/views/__init__.py index 5d0c94bfa1..5a0657f26a 100644 --- a/zerver/views/__init__.py +++ b/zerver/views/__init__.py @@ -44,7 +44,7 @@ from zerver.lib.actions import bulk_remove_subscriptions, \ from zerver.lib.create_user import random_api_key from zerver.lib.push_notifications import num_push_devices_for_user from zerver.forms import RegistrationForm, HomepageForm, ToSForm, \ - CreateBotForm, is_inactive + CreateUserForm, is_inactive from django.views.decorators.csrf import csrf_exempt, csrf_protect from django_openid_auth.views import default_render_failure, login_complete from django_auth_ldap.backend import LDAPBackend, _LDAPUser @@ -1907,6 +1907,30 @@ def json_change_notify_settings(request, user_profile, return json_success(result) +@require_realm_admin +@has_request_variables +def create_user_backend(request, user_profile, email=REQ, password=REQ, + full_name=REQ, short_name=REQ): + form = CreateUserForm({'full_name': full_name, 'email': email}) + if not form.is_valid(): + return json_error('Bad name or username') + + # Check that the new user's email address belongs to the admin's realm + realm = user_profile.realm + domain = resolve_email_to_domain(email) + if realm.domain != domain: + return json_error("Email '%s' does not belong to domain '%s'" % (email, realm.domain)) + + try: + get_user_profile_by_email(email) + return json_error("Email '%s' already in use" % (email,)) + except UserProfile.DoesNotExist: + pass + + new_user_profile = do_create_user(email, password, realm, full_name, short_name) + process_new_human_user(new_user_profile) + return json_success() + @authenticated_json_post_view @has_request_variables def json_stream_exists(request, user_profile, stream=REQ): @@ -2261,7 +2285,7 @@ def regenerate_bot_api_key(request, user_profile, email): def json_create_bot(request, user_profile, full_name=REQ, short_name=REQ): short_name += "-bot" email = short_name + "@" + user_profile.realm.domain - form = CreateBotForm({'full_name': full_name, 'email': email}) + form = CreateUserForm({'full_name': full_name, 'email': email}) if not form.is_valid(): # We validate client-side as well return json_error('Bad name or username') diff --git a/zproject/urls.py b/zproject/urls.py index 9b0cc42d9a..be718b23b2 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -191,7 +191,8 @@ v1_api_and_json_patterns = patterns('zerver.views', 'GET': 'stream_exists_backend', 'DELETE': 'deactivate_stream_backend'}), url(r'^users$', 'rest_dispatch', - {'GET': 'get_members_backend'}), + {'GET': 'get_members_backend', + 'POST': 'create_user_backend'}), url(r'^users/me$', 'rest_dispatch', {'GET': 'get_profile_backend'}), url(r'^users/me/enter-sends$', 'rest_dispatch',