def handle(self, *args, **options): if options.get('email'): email = options['email'] else: email = None while not email: email = input("Enter email address: ") if options.get('first-name'): first_name = options['first-name'] else: default = email.split('@')[0].title() first_name = input("Enter first name ({0}): ".format(default)) or default if options.get('last-name'): last_name = options['last-name'] else: default = email.split('@')[1].split('.')[0].title() last_name = input("Enter last name ({0}): ".format(default)) or default if options.get('username'): username = options['username'] else: default = email.split('@')[0] username = input("Enter username ({0}): ".format(default)) or default token = generate_token(email=email, username=username, first_name=first_name, last_name=last_name) self.stdout.write('Token: {0}'.format(token))
def __call__(self, command, options): original = None with open(options["path"]) as data: original = data.read() fixture = json.loads(original) updated = {} for key in fixture.iterkeys(): response = serialize_from_query(key) if isinstance(response, HttpResponseBadRequest): print response break else: updated[key] = response.data new_data = json.dumps(updated, indent=2) if new_data == original: command.stdout.write("No change!") return print "".join(difflib.unified_diff(original.splitlines(True), new_data.splitlines(True))) msg = ("\nThere are differences between the old an new data. " "Update? (yes/no): ") confirm = input(msg) while True: if confirm not in ('yes', 'no'): confirm = input('Please enter either "yes" or "no": ') continue if confirm == 'yes': with open(options["path"], 'w') as data: data.write(new_data) break
def confirm_proceed(self, prompt): """ Prompts the user for yes/no confirmation to proceed. """ # Ensure stdout can handle Unicode data: http://bit.ly/1C3l4eV locale_encoding = locale.getpreferredencoding() old_stdout = sys.stdout sys.stdout = codecs.getwriter(locale_encoding)(sys.stdout) # Send the confirmation prompt out to the user user_input = input(prompt) confirm = None while confirm is None: if user_input.lower() in ['y', 'yes']: confirm = True elif user_input.lower() in ['n', 'no']: confirm = False else: user_input = input("Invalid input. Please type 'yes', 'no', 'y' or 'n':\n") # Set things back to the way they were before continuing. sys.stdout = old_stdout # Pass back what the user typed return confirm
def ask_not_null_addition(self, field_name, model_name): "Adding a NOT NULL field to a model" choice = self._choice_input( "You are trying to add a non-nullable field '%s' to %s without a default;\n" % (field_name, model_name) + "we can't do that (the database needs something to populate existing rows).\n" + "Please select a fix:", [ "Provide a one-off default now (will be set on all existing rows)", "Quit, and let me add a default in models.py", ], ) if choice == 2: sys.exit(3) else: print("Please enter the default value now, as valid Python") print("The datetime module is available, so you can do e.g. datetime.date.today()") while True: if six.PY3: # Six does not correctly abstract over the fact that # py3 input returns a unicode string, while py2 raw_input # returns a bytestring. code = input(">>> ") else: code = input(">>> ").decode(sys.stdin.encoding) if not code: print("Please enter some code, or 'exit' (with no quotes) to exit.") elif code == "exit": sys.exit(1) else: try: return eval(code, {}, {"datetime": datetime_safe}) except (SyntaxError, NameError) as e: print("Invalid input: %s" % e)
def _boolean_input(self, question, default=None): result = input("%s " % question) if not result and default is not None: return default while len(result) < 1 or result[0].lower() not in "yn": result = input("Please answer yes or no: ") return result[0].lower() == "y"
def handle(self, *args, **options): tenant_model = get_tenant_model() # Attempt to build the instance based on specified data try: tenant = tenant_model(None, *args) except IndexError: opts = tenant_model._meta field_names = tuple( field.name for field in opts.local_fields if not field.primary_key ) raise CommandError( "Number of args exceeds the number of fields for model %s.%s.\n" "Got %s when defined fields are %s." % ( opts.app_label, opts.object_name, args, field_names ) ) # Full clean the instance try: tenant.full_clean() except ValidationError as e: name, messages = e.message_dict.popitem() raise CommandError( 'Invalid value for field "%s": %s.' % (name, messages[0]) ) # Redirect the output of the schema creation logger to our stdout. handler = CommandLoggingHandler( self.stdout._out, self.stderr._out, int(options['verbosity']) ) logger = logging.getLogger('tenancy') logger.setLevel(handler.level) logger.addHandler(handler) # Create the tenant instance and create tables tenant.save(force_insert=True) # Remove the handler associated with the schema creation logger. logger.removeHandler(handler) logger.setLevel(logging.NOTSET) from ...settings import TENANT_AUTH_USER_MODEL if options.get('interactive', True) and TENANT_AUTH_USER_MODEL: confirm = input( "\nYou just created a new tenant, which means you don't have " "any superusers defined.\nWould you like to create one " "now? (yes/no): " ) while True: if confirm not in ('yes', 'no'): confirm = input('Please enter either "yes" or "no": ') else: if confirm == 'yes': call_command('createsuperuser', tenant=tenant, **options) break
def migrate_author(self, author_name): """ Handle actions for migrating the authors. """ action_text = ( "The author '%s' needs to be migrated to an user:\n" "1. Use an existing user ?\n" "2. Create a new user ?\n" "Please select a choice: " % self.style.ITEM(author_name) ) while 42: selection = input(smart_str(action_text)) if selection and selection in "12": break if selection == "1": users = Author.objects.all() if users.count() == 1: username = users[0].get_username() preselected_user = username usernames = [username] usernames_display = ["[%s]" % username] else: usernames = [] usernames_display = [] preselected_user = None for user in users: username = user.get_username() if username == author_name: usernames_display.append("[%s]" % username) preselected_user = username else: usernames_display.append(username) usernames.append(username) while 42: user_text = ( "1. Select your user, by typing " "one of theses usernames:\n" "%s or 'back'\n" "Please select a choice: " % ", ".join(usernames_display) ) user_selected = input(user_text) if user_selected in usernames: break if user_selected == "" and preselected_user: user_selected = preselected_user break if user_selected.strip() == "back": return self.migrate_author(author_name) return users.get(**{users[0].USERNAME_FIELD: user_selected}) else: create_text = "2. Please type the email of " "the '%s' user or 'back': " % author_name author_mail = input(create_text) if author_mail.strip() == "back": return self.migrate_author(author_name) try: return Author.objects.create_user(author_name, author_mail) except IntegrityError: return Author.objects.get(**{Author.USERNAME_FIELD: author_name})
def ask_for_confirmation(question, default=None): """Ask for confirmation before proceeding. """ result = input('{} '.format(question)) if not result and default is not None: return default while len(result) < 1 or result[0].lower() not in 'yn': result = input('Please answer yes or no: ') return result[0].lower() == 'y'
def migrate_author(self, author_name): """Handle actions for migrating the authors""" action_text = "The author '%s' needs to be migrated to an user:\n"\ "1. Use an existing user ?\n"\ "2. Create a new user ?\n"\ "Please select a choice: " % self.style.ITEM(author_name) while 42: selection = input(smart_str(action_text)) if selection and selection in '12': break if selection == '1': users = Author.objects.all() if users.count() == 1: username = users[0].username preselected_user = username usernames = [username] usernames_display = ['[%s]' % username] else: usernames = [] usernames_display = [] preselected_user = None for user in users: username = user.username if username == author_name: usernames_display.append('[%s]' % username) preselected_user = username else: usernames_display.append(username) usernames.append(username) while 42: user_text = "1. Select your user, by typing " \ "one of theses usernames:\n"\ "%s or 'back'\n"\ "Please select a choice: " % \ ', '.join(usernames_display) user_selected = input(user_text) if user_selected in usernames: break if user_selected == '' and preselected_user: user_selected = preselected_user break if user_selected.strip() == 'back': return self.migrate_author(author_name) return users.get(username=user_selected) else: create_text = "2. Please type the email of " \ "the '%s' user or 'back': " % author_name author_mail = input(create_text) if author_mail.strip() == 'back': return self.migrate_author(author_name) try: return Author.objects.create_user(author_name, author_mail) except IntegrityError: return Author.objects.get(username=author_name)
def handle_noargs(self, **options): global gdata_service try: from gdata import service gdata_service = service except ImportError: raise CommandError('You need to install the gdata ' 'module to run this command.') self.verbosity = int(options.get('verbosity', 1)) self.blogger_username = options.get('blogger_username') self.blogger_blog_id = options.get('blogger_blog_id') self.blogger_limit = int(options.get('blogger_limit')) self.category_title = options.get('category_title') self.auto_excerpt = options.get('auto-excerpt', True) self.write_out(self.style.TITLE( 'Starting migration from Blogger to Zinnia %s\n' % __version__)) if not self.blogger_username: self.blogger_username = input('Blogger username: '******'Invalid Blogger username') self.blogger_password = getpass('Blogger password: '******'Incorrect Blogger username or password') default_author = options.get('author') if default_author: try: self.default_author = Author.objects.get( **{Author.USERNAME_FIELD: self.default_author}) except Author.DoesNotExist: raise CommandError( 'Invalid Zinnia username for default author "%s"' % default_author) else: self.default_author = Author.objects.all()[0] if not self.blogger_blog_id: self.select_blog_id() if not self.category_title: self.category_title = input( 'Category title for imported entries: ') if not self.category_title: raise CommandError('Invalid category title') self.import_posts()
def _choice_input(self, question, choices): print(question) for i, choice in enumerate(choices): print(" %s) %s" % (i + 1, choice)) result = input("Select an option: ") while True: try: value = int(result) if 0 < value <= len(choices): return value except ValueError: pass result = input("Please select a valid option: ")
def create_first_user(app, created_models, verbosity, db, **kwargs): if User not in created_models: return if not kwargs.get('interactive', True): return msg = ("Would you like to create a user account now? (yes/no): ") confirm = input(msg) while 1: if confirm not in ('yes', 'no'): confirm = input('Please enter either "yes" or "no": ') continue if confirm == 'yes': call_command("createuser", interactive=True, database=db) break
def handle(self, *args, **options): User = get_user_model() if not User.objects.filter(is_superuser=True).count(): msg = ("\nCabot doesn't have any super users defined.\n\n" "Would you like to create one now? (yes/no): ") confirm = input(msg) while 1: if confirm not in ('yes', 'no'): confirm = input('Please enter either "yes" or "no": ') continue if confirm == 'yes': call_command("createsuperuser", interactive=True) break
def create_superuser(app, created_models, verbosity, db, **kwargs): from django.core.management import call_command if auth_app.User in created_models and kwargs.get('interactive', True): msg = ("\nYou just installed Django's auth system, which means you " "don't have any superusers defined.\nWould you like to create one " "now? (yes/no): ") confirm = input(msg) while 1: if confirm not in ('yes', 'no'): confirm = input('Please enter either "yes" or "no": ') continue if confirm == 'yes': call_command("createsuperuser", interactive=True, database=db) break
def handle_noargs(self, **options): db = options.get('database') connection = connections[db] verbosity = int(options.get('verbosity')) interactive = options.get('interactive') # The following are stealth options used by Django's internals. reset_sequences = options.get('reset_sequences', True) allow_cascade = options.get('allow_cascade', False) inhibit_post_migrate = options.get('inhibit_post_migrate', False) self.style = no_style() # Import the 'management' module within each installed app, to register # dispatcher events. for app_name in settings.INSTALLED_APPS: try: import_module('.management', app_name) except ImportError: pass sql_list = sql_flush(self.style, connection, only_django=True, reset_sequences=reset_sequences, allow_cascade=allow_cascade) if interactive: confirm = input("""You have requested a flush of the database. This will IRREVERSIBLY DESTROY all data currently in the %r database, and return each table to a fresh state. Are you sure you want to do this? Type 'yes' to continue, or 'no' to cancel: """ % connection.settings_dict['NAME']) else: confirm = 'yes' if confirm == 'yes': try: with transaction.commit_on_success_unless_managed(): cursor = connection.cursor() for sql in sql_list: cursor.execute(sql) except Exception as e: new_msg = ( "Database %s couldn't be flushed. Possible reasons:\n" " * The database isn't running or isn't configured correctly.\n" " * At least one of the expected database tables doesn't exist.\n" " * The SQL was invalid.\n" "Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.\n" "The full error: %s") % (connection.settings_dict['NAME'], e) six.reraise(CommandError, CommandError(new_msg), sys.exc_info()[2]) if not inhibit_post_migrate: self.emit_post_migrate(verbosity, interactive, db) # Reinstall the initial_data fixture. if options.get('load_initial_data'): # Reinstall the initial_data fixture. call_command('loaddata', 'initial_data', **options) else: self.stdout.write("Flush cancelled.\n")
def handle(self, *args, **options): tenant = {} for field in self.fields: tenant[field.name] = options.get(field.name, None) saved = False while not saved: for field in self.fields: if not getattr(tenant, field.name, None): input_msg = field.verbose_name default = field.get_default() if default: input_msg = "%s (leave blank to use '%s')" % (input_msg, default) tenant[field.name] = input(force_str('%s: ' % input_msg)) or default saved = self.store_tenant(**tenant) if not saved: tenant = {} continue if options.get('s', None): print "Create superuser for %s" % tenant['schema_name'] call_command('createsuperuser', schema_name=tenant['schema_name'])
def handle(self, verbosity, *args, **options): self.set_options(**options) self.createdb_if_not_exists() self.clear_compressor_cache() call_command('migrate') fixture = '{workdir}/{tutorial}/fixtures/myshop.json'.format(workdir=settings.WORK_DIR, tutorial=settings.SHOP_TUTORIAL) if self.interactive: mesg = ("\nThis will overwrite your workdir and install a new database for the django-SHOP demo: {tutorial}\n" "Are you sure you want to do this?\n\n" "Type 'yes' to continue, or 'no' to cancel: ").format(tutorial=settings.SHOP_TUTORIAL) if input(mesg) != 'yes': raise CommandError("SHOP initialization cancelled.") else: if os.path.isfile(fixture): self.stdout.write(self.style.WARNING("Can not override downloaded data in input-less mode.")) return extract_to = os.path.join(settings.WORK_DIR, os.pardir) msg = "Downloading workdir and extracting to {}. Please wait ..." self.stdout.write(msg.format(extract_to)) download_url = self.download_url.format(tutorial=settings.SHOP_TUTORIAL, version=self.version) response = requests.get(download_url, stream=True) zip_ref = zipfile.ZipFile(StringIO(response.content)) try: zip_ref.extractall(extract_to, pwd=self.pwd) finally: zip_ref.close() call_command('loaddata', fixture) call_command('fix_filer_bug_965')
def _reset_token(self, account): service = account.service password = None auth_token = None while True: if (not password and service.get_reset_auth_token_requires_password()): password = getpass.getpass(_('Password for %s: ') % account.username) auth_token = None try: service.reset_auth_token(password, auth_token) self.stdout.write(_('Successfully reset token for %s\n') % account.username) break except TwoFactorAuthCodeRequiredError: auth_token = input('Enter your two-factor auth token: ') except AuthorizationError as e: self.stderr.write('%s\n' % e) password = None except Exception as e: self.stderr.write(_('Unexpected error: %s\n') % e) raise break
def _handle_objects_preventing_db_destruction(self, cursor, parameters, verbosity, autoclobber): # There are objects in the test tablespace which prevent dropping it # The easy fix is to drop the test user -- but are we allowed to do so? print("There are objects in the old test database which prevent its destruction.") print("If they belong to the test user, deleting the user will allow the test " "database to be recreated.") print("Otherwise, you will need to find and remove each of these objects, " "or use a different tablespace.\n") if self._test_user_create(): if not autoclobber: confirm = input("Type 'yes' to delete user %s: " % parameters['user']) if autoclobber or confirm == 'yes': try: if verbosity >= 1: print("Destroying old test user...") self._destroy_test_user(cursor, parameters, verbosity) except Exception as e: sys.stderr.write("Got an error destroying the test user: %s\n" % e) sys.exit(2) try: if verbosity >= 1: print("Destroying old test database for alias '%s'..." % self.connection.alias) self._execute_test_db_destruction(cursor, parameters, verbosity) except Exception as e: sys.stderr.write("Got an error destroying the test database: %s\n" % e) sys.exit(2) else: print("Tests cancelled -- test database cannot be recreated.") sys.exit(1) else: print("Django is configured to use pre-existing test user '%s'," " and will not attempt to delete it.\n" % parameters['user']) print("Tests cancelled -- test database cannot be recreated.") sys.exit(1)
def _create_test_db(self, verbosity, autoclobber, keepdb=False): test_database_name = self._get_test_db_name() if keepdb: return test_database_name if not self.is_in_memory_db(test_database_name): # Erase the old test database if verbosity >= 1: print("Destroying old test database for alias %s..." % ( self._get_database_display_str(verbosity, test_database_name), )) if os.access(test_database_name, os.F_OK): if not autoclobber: confirm = input( "Type 'yes' if you would like to try deleting the test " "database '%s', or 'no' to cancel: " % test_database_name ) if autoclobber or confirm == 'yes': try: os.remove(test_database_name) except Exception as e: sys.stderr.write("Got an error deleting the old test database: %s\n" % e) sys.exit(2) else: print("Tests cancelled.") sys.exit(1) return test_database_name
def handle(self, *args, **options): tenant = {} for field in self.fields: input_value = options.get(field.name, None) if input_value is not None and field.name == 'domain_urls': tenant[field.name] = input_value.split(';') else: tenant[field.name] = input_value saved = False while not saved: for field in self.fields: if tenant.get(field.name, '') == '': input_msg = field.verbose_name default = field.get_default() if default: input_msg = "%s (leave blank to use '%s')" % (input_msg, default) input_value = input(force_str('%s: ' % input_msg)) or default if field.name == 'domain_urls': tenant[field.name] = input_value.split(';') else: tenant[field.name] = input_value saved = self.store_tenant(**tenant) if not saved: tenant = {} continue if options.get('s', None): self.stdout.write("Create superuser for %s" % tenant['schema_name']) call_command('create_tenant_superuser', schema_name=tenant['schema_name'], interactive=True)
def handle_noargs(self, **options): # Confirm the user wants to do this confirm = input("""You have requested to load the python.org development fixtures. This will IRREVERSIBLY DESTROY all data currently in your local database. Are you sure you want to do this? Type 'y' or 'yes' to continue, 'n' or 'no' to cancel: """) if confirm in ('y', 'yes'): self.stdout.write("\nBeginning download, note this can take a couple of minutes...") r = requests.get(settings.DEV_FIXTURE_URL, stream=True) if r.status_code != 200: self.stderr.write("Unable to download file: Received status code {}".format(r.status_code)) sys.exit(1) with open('/tmp/dev-fixtures.json.gz', 'wb') as f: for chunk in r.iter_content(chunk_size=1024): f.write(chunk) f.flush() self.stdout.write("Download complete, loading fixtures") call_command('loaddata', '/tmp/dev-fixtures.json') self.stdout.write("END: Fixtures loaded")
def handle(self, *args, **options): if len(args) == 3: try: instance = CourseInstance.objects.get(id=args[0]) student = UserProfile.objects.get(id=args[1]) except ObjectDoesNotExist: raise CommandError('Given student or instance does not exist!') percentage = int(args[2]) if percentage < 0 or percentage > 100: raise CommandError('Scale percentage must be an integer in 0-100 range!') confirm = input("You are about to scale the grades for student '{}'\non the course instance '{}'\nto {} %.\nType 'yes' to confirm. YOU CAN'T UNDO THIS!\n".format(student,instance,percentage)) if confirm == 'yes': submissions_changed = 0 for submission in student.submissions.all(): if submission.exercise.course_instance == instance: original_grade = submission.grade submission.scale_grade_to(percentage) submission.save() submissions_changed += 1 self.stdout.write('Submission id {}: {} => {}'.format(submission.id, original_grade, submission.grade)) self.stdout.write('{} submission grades were changed'.format(submissions_changed)) else: self.stdout.write('No grades were changed') else: raise CommandError('Invalid number of arguments!')
def handle(self, *args, **options): # execute the commands if DEBUG is set to False if not settings.DEBUG: self.set_options(*args, **options) if options['download']: if options['noinput']: self.download() else: confirm = input(self.prompt.encode('utf-8')) if confirm != 'yes': print "Download cancelled." return False self.download() if options['unzip']: self.unzip() if options['prep']: self.prep() if options['clear']: self.clear() if options['clean']: self.clean() if options['load']: self.load() else: print "DEBUG is not set to False. Please change before running `downloadcalaccess`"
def _create_test_db(self, verbosity, autoclobber): """" Internal implementation - creates the test db tables. """ test_database_name = self._get_test_db_name() self._prepare_for_test_db_ddl() try: self._create_database(test_database_name, verbosity) if verbosity >= 1: print("Database %s created..." % test_database_name) except Exception as e: sys.stderr.write("Got an error creating the test database: %s\n" % e) if not autoclobber: confirm = input("Type 'yes' if you would like to try deleting the test database '%s', or 'no' to cancel: " % test_database_name) if autoclobber or confirm == 'yes': try: if verbosity >= 1: print("Destroying old test database...") self._destroy_test_db(test_database_name, verbosity) if verbosity >= 1: print("Creating test database...") self._create_database(test_database_name, verbosity) if verbosity >= 1: print("Database %s created..." % test_database_name) except Exception as e: sys.stderr.write("Got an error recreating the test database: %s\n" % e) sys.exit(2) else: print("Tests cancelled.") sys.exit(1) return test_database_name
def ask_not_null_addition(self, field_name, model_name): "Adding a NOT NULL field to a model" choice = self._choice_input( "You are trying to add a non-nullable field '%s' to %s without a default;\n" % (field_name, model_name) + "this is not possible. Please select a fix:", [ "Provide a one-off default now (will be set on all existing rows)", "Quit, and let me add a default in models.py", ] ) if choice == 2: sys.exit(3) else: print("Please enter the default value now, as valid Python") print("The datetime module is available, so you can do e.g. datetime.date.today()") while True: code = input(">>> ") if not code: print("Please enter some code, or 'exit' (with no quotes) to exit.") elif code == "exit": sys.exit(1) else: try: return eval(code, {}, {"datetime": datetime_safe}) except (SyntaxError, NameError) as e: print("Invalid input: %s" % e) else: break
def handle(self, *args, **options): from tinc.models import TincHost, TincAddress interactive = options.get('interactive') username = options.get('username') if not interactive: # validate username if not username: raise CommandError("You must use --username with --noinput.") try: username = pwd.getpwnam(username).pw_name except KeyError: raise CommandError("Username doesn't exists.") else: # Prompt for username # Enclose this whole thing in a try/except to trap for a # keyboard interrupt and exit gracefully. prompt_username = None while prompt_username is None: if not prompt_username: input_msg = "Celeryd username" if username: input_msg += " (leave blank to use '%s')" % username value = input(input_msg + ': ') if username and value == '': value = username # validate username try: prompt_username = pwd.getpwnam(value).pw_name except KeyError, e: self.stderr.write("Error: %s" % e) prompt_username = None continue
def handle(self, *usernames, **options): force_yes = options['force_yes'] local_sites = options['local_sites'] accounts = HostingServiceAccount.objects.filter(service_name='github') if usernames: accounts = accounts.filter(username__in=usernames) if local_sites: local_site_names = local_sites.split(',') if local_site_names: accounts = accounts.filter( local_site__name__in=local_site_names) for account in accounts: if force_yes: reset = 'y' else: if account.local_site: reset_msg = _('Reset token for %s (%s) [Y/n] ') % ( account.local_site.name, account.username) else: reset_msg = _('Reset token for %s [Y/n] ') % ( account.username) reset = input(reset_msg) if reset != 'n': self._reset_token(account)
def get_tenant_from_options_or_interactive(self, **options): TenantModel = get_tenant_model() all_tenants = TenantModel.objects.all() if not all_tenants: raise CommandError("""There are no tenants in the system. To learn how create a tenant, see: https://django-multitenants.readthedocs.org/en/latest/use.html#creating-a-tenant""") if options.get('schema_name'): tenant_schema = options['schema_name'] else: while True: tenant_schema = input( "Enter Tenant Schema ('?' to list schemas): ") if tenant_schema == '?': print( '\n'.join(["%s - %s" % (t.schema_name, t.domain_url,) for t in all_tenants])) else: break if tenant_schema not in [t.schema_name for t in all_tenants]: raise CommandError( "Invalid tenant schema, '%s'" % (tenant_schema,)) return TenantModel.objects.get(schema_name=tenant_schema)
def _confirm_execute(self): """Prompt the user to confirm execution of an evolution. This will warn the user of the risks of evolving the database and to recommend a backup. It will then prompt for confirmation, returning the result. Returns: bool: ``True`` if the user confirmed the execution. ``False`` if the execution should be cancelled. """ prompt = self._wrap_paragraphs( _('You have requested a database evolution. This will alter ' 'tables and data currently in the "%s" database, and may ' 'result in IRREVERSABLE DATA LOSS. Evolutions should be ' '*thoroughly* reviewed prior to execution.\n' '\n' 'MAKE A BACKUP OF YOUR DATABASE BEFORE YOU CONTINUE!\n' '\n' 'Are you sure you want to execute the evolutions?\n' '\n' 'Type "yes" to continue, or "no" to cancel:') % self.evolver.database_name) # Note that we must append a space here, rather than above, since the # paragraph wrapping logic will strip trailing whitespace. return input('%s ' % prompt).lower() == 'yes'
def handle(self, *app_labels, **options): days = options["days"] keep = options["keep"] force = options["force"] confirmation = options["confirmation"] manager = options.get('manager') database = options.get('database') # I don't know why verbosity is not already an int in Django? try: verbosity = int(options["verbosity"]) except ValueError: raise CommandError("option -v: invalid choice: '%s' (choose from '0', '1', '2')" % options["verbosity"]) date = None # Validating arguments if options["date"]: if days: raise CommandError("You cannot use --date and --days at the same time. They are exclusive.") try: date = datetime.datetime.strptime(options["date"], "%Y-%m-%d").date() except ValueError: raise CommandError("The date you give (%s) is not a valid date. The date should be in the ISO format (YYYY-MM-DD)." % options["date"]) # Find the date from the days arguments. elif days: date = datetime.datetime.now() - datetime.timedelta(days) # Build the queries revision_query = Revision.objects.using(database).all() if manager: revision_query = revision_query.filter(manager_slug=manager) if date: revision_query = revision_query.filter(date_created__lt=date) if app_labels: app_list = set() mod_list = set() for label in app_labels: try: app_label, model_label = label.split(".") mod_list.add((app_label, model_label)) except ValueError: # This is just an app, no model qualifier. app_list.add(label) # Remove models that their app is already in app_list for app, model in mod_list.copy(): if app in app_list: mod_list.remove((app, model)) # Build apps/models subqueries subqueries = [] if app_list: subqueries.append(Q(app_label__in=app_list)) if mod_list: subqueries.extend([Q(app_label=app, model=model) for app, model in mod_list]) subqueries = reduce(operator.or_, subqueries) if force: models = ContentType.objects.using(database).filter(subqueries) revision_query = revision_query.filter(version__content_type__in=models) else: models = ContentType.objects.using(database).exclude(subqueries) revision_query = revision_query.exclude(version__content_type__in=models) if keep: objs = Version.objects.using(database).all() # If app is specified, to speed up the loop on theses objects, # get only the specified subset. if app_labels: if force: objs = objs.filter(content_type__in=models) else: objs = objs.exclude(content_type__in=models) # Get all the objects that have more than the maximum revisions objs = objs.values("object_id", "content_type_id").annotate(total_ver=Count("object_id")).filter(total_ver__gt=keep) revisions_not_keeped = set() # Get all ids of the oldest revisions minus the max allowed # revisions for all objects. # Was not able to avoid this loop... for obj in objs: revisions_not_keeped.update(list(Version.objects.using(database).filter(content_type__id=obj["content_type_id"], object_id=obj["object_id"]).order_by("-revision__date_created").values_list("revision_id", flat=True)[keep:])) revision_query = revision_query.filter(pk__in=revisions_not_keeped) # Prepare message if verbose if verbosity > 0: if not date and not app_labels and not keep: print("All revisions will be deleted for all models.") else: date_msg = "" if date: date_msg = " older than %s" % date.isoformat() models_msg = " " if app_labels: force_msg = "" if not force: force_msg = " only" models_msg = " having%s theses apps and models:\n- %s\n" % (force_msg, "\n- ".join(sorted(app_list.union(["%s.%s" % (app, model) for app, model in mod_list])),)) if date: models_msg = " and" + models_msg keep_msg = "" if keep: keep_msg = " keeping the %s most recent revisions of each object" % keep revision_count = revision_query.count() if revision_count: version_query = Version.objects.using(database).all() if date or app_labels or keep: version_query = version_query.filter(revision__in=revision_query) print("%s revision(s)%s%swill be deleted%s.\n%s model version(s) will be deleted." % (revision_count, date_msg, models_msg, keep_msg, version_query.count())) else: print("No revision%s%sto delete%s.\nDone" % (date_msg, models_msg, keep_msg)) return # Ask confirmation if confirmation: choice = input("Are you sure you want to delete theses revisions? [y|N] ") if choice.lower() != "y": print("Aborting revision deletion.") return # Delete versions and revisions print("Deleting revisions...") try: revision_query.delete() except DatabaseError: # may fail on sqlite if the query is too long print("Delete failed. Trying again with slower method.") for item in revision_query: item.delete() print("Done")
def handle(self, **options): database = options['database'] connection = connections[database] verbosity = options['verbosity'] interactive = options['interactive'] # The following are stealth options used by Django's internals. reset_sequences = options.get('reset_sequences', True) allow_cascade = options.get('allow_cascade', False) inhibit_post_migrate = options.get('inhibit_post_migrate', False) self.style = no_style() # Import the 'management' module within each installed app, to register # dispatcher events. for app_config in apps.get_app_configs(): try: import_module('.management', app_config.name) except ImportError: pass sql_list = sql_flush(self.style, connection, only_django=True, reset_sequences=reset_sequences, allow_cascade=allow_cascade) if interactive: confirm = input("""You have requested a flush of the database. This will IRREVERSIBLY DESTROY all data currently in the %r database, and return each table to an empty state. Are you sure you want to do this? Type 'yes' to continue, or 'no' to cancel: """ % connection.settings_dict['NAME']) else: confirm = 'yes' if confirm == 'yes': try: with transaction.atomic( using=database, savepoint=connection.features.can_rollback_ddl): with connection.cursor() as cursor: for sql in sql_list: cursor.execute(sql) except Exception as e: new_msg = ( "Database %s couldn't be flushed. Possible reasons:\n" " * The database isn't running or isn't configured correctly.\n" " * At least one of the expected database tables doesn't exist.\n" " * The SQL was invalid.\n" "Hint: Look at the output of 'django-admin sqlflush'. " "That's the SQL this command wasn't able to run.\n" "The full error: %s") % (connection.settings_dict['NAME'], e) six.reraise(CommandError, CommandError(new_msg), sys.exc_info()[2]) # Empty sql_list may signify an empty database and post_migrate would then crash if sql_list and not inhibit_post_migrate: # Emit the post migrate signal. This allows individual applications to # respond as if the database had been migrated from scratch. emit_post_migrate_signal(verbosity, interactive, database) else: self.stdout.write("Flush cancelled.\n")
def handle(self, *args, **options): verbosity = int(options.get('verbosity', 1)) database = options.get('database') email = options.get('email') domain = options.get('domain') interactive = options.get('interactive') send = options.get('send') https = options.get('https') sites = Site.objects.all() site_items = dict((str(obj.id), obj) for obj in sites) site = None if not site_items: raise CommandError("No site available.") while not email: if not interactive: raise CommandError("Missing parameter 'email'") email = (input( force_str('Enter the email address of the recipient: ')) or '').strip() if domain: for site in sites: if site.domain == domain: break else: raise CommandError("A site with domain '%s' does not exist" % domain) else: if len(site_items) == 1: site = sites[0] while site is None: if not interactive: raise CommandError("Missing parameter 'domain'") for obj in sites: self.stdout.write("[%s] %s" % (obj.id, obj.domain)) site_id = input(force_str('Select a site: ')) try: site = site_items[site_id] except KeyError: continue code = InvitationCode.objects.create_invite_code(email, site=site) do_send = None while do_send is None: if not interactive: do_send = 'y' if send else 'n' break do_send = (input(force_str('Send the code now? [y/N]')) or '').strip().lower() do_send = do_send or 'n' if do_send not in 'yn': do_send = None if do_send == 'y': secure = None while secure is None: if not interactive: secure = 'y' if https else 'n' break secure = (input( force_str('Use https for site urls in the email? [y/N]')) or '').strip().lower() secure = secure or 'n' if secure not in 'yn': secure = None protocol = 'http' if secure == 'y': protocol += 's' site_url = '%s://%s%s' % (protocol, site.domain, reverse("home")) login_url = '%s://%s%s' % (protocol, site.domain, reverse("login")) try: send_invite_code_mail(code, site_url, login_url) except Exception as e: self.stderr.write("Mail send error - %s" % e) return else: self.stdout.write("Mail sent to %s." % code.registered_to) else: self.stdout.write(code.short_key)
def handle(self, *args, **options): username = options.get('username') email = options.get('email') password = options.get('password') interactive = options.get('interactive') verbosity = int(options.get('verbosity', 1)) # Validate initial inputs if username is not None: try: username = username.strip() validate_username(username) except ValidationError as e: self.stderr.write(e.messages[0]) username = None if email is not None: try: email = email.strip() validate_email(email) except ValidationError as e: self.stderr.write(e.messages[0]) email = None if password is not None: try: password = password.strip() validate_password(password) except ValidationError as e: self.stderr.write(e.messages[0]) password = None if not interactive: if username and email and password: # Call User manager's create_superuser using our wrapper self.create_superuser(username, email, password, verbosity) else: try: if hasattr(self.stdin, 'isatty') and not self.stdin.isatty(): raise NotRunningInTTYException("Not running in a TTY") # Prompt for username/password, and any other required fields. # Enclose this whole thing in a try/except to trap for a # keyboard interrupt and exit gracefully. while not username: try: message = force_str("Enter displayed username: "******"Enter E-mail address: ").strip() validate_email(raw_value) email = raw_value except ValidationError as e: self.stderr.write(e.messages[0]) while not password: try: raw_value = getpass("Enter password: "******"Repeat password: "******"Entered passwords are different.") password = raw_value except ValidationError as e: self.stderr.write(e.messages[0]) # Call User manager's create_superuser using our wrapper self.create_superuser(username, email, password, verbosity) except KeyboardInterrupt: self.stderr.write("\nOperation cancelled.") sys.exit(1) except NotRunningInTTYException: self.stdout.write( "Superuser creation skipped due to not running in a TTY. " "You can run `manage.py createsuperuser` in your project " "to create one manually." )
def handle_noargs(self, **options): db = options.get('database') connection = connections[db] verbosity = int(options.get('verbosity')) interactive = options.get('interactive') # The following are stealth options used by Django's internals. reset_sequences = options.get('reset_sequences', True) allow_cascade = options.get('allow_cascade', False) inhibit_post_syncdb = options.get('inhibit_post_syncdb', False) self.style = no_style() # Import the 'management' module within each installed app, to register # dispatcher events. for app_name in settings.INSTALLED_APPS: try: import_module('.management', app_name) except ImportError: pass sql_list = sql_flush(self.style, connection, only_django=True, reset_sequences=reset_sequences, allow_cascade=allow_cascade) if interactive: confirm = input("""You have requested a flush of the database. This will IRREVERSIBLY DESTROY all data currently in the %r database, and return each table to the state it was in after syncdb. Are you sure you want to do this? Type 'yes' to continue, or 'no' to cancel: """ % connection.settings_dict['NAME']) else: confirm = 'yes' if confirm == 'yes': try: with transaction.commit_on_success_unless_managed(): cursor = connection.cursor() for sql in sql_list: cursor.execute(sql) except Exception as e: new_msg = ( "Database %s couldn't be flushed. Possible reasons:\n" " * The database isn't running or isn't configured correctly.\n" " * At least one of the expected database tables doesn't exist.\n" " * The SQL was invalid.\n" "Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.\n" "The full error: %s") % (connection.settings_dict['NAME'], e) six.reraise(CommandError, CommandError(new_msg), sys.exc_info()[2]) if not inhibit_post_syncdb: self.emit_post_syncdb(verbosity, interactive, db) # Reinstall the initial_data fixture. if options.get('load_initial_data'): # Reinstall the initial_data fixture. call_command('loaddata', 'initial_data', **options) else: self.stdout.write("Flush cancelled.\n")
def handle(self, *app_labels, **options): days = options["days"] keep = options["keep"] force = options["force"] interactive = options["interactive"] # Load admin classes. admin.autodiscover() # Check for deprecated confirmation option. if not options["confirmation"]: interactive = False warnings.warn( ( "--no-confirmation is deprecated, please use --no-input instead. " "--no-confirmation will be removed in django-reversion 1.12.0" ), DeprecationWarning ) revision_manager = RevisionManager.get_manager(options["manager"]) database = options.get("database") verbosity = int(options.get("verbosity", 1)) # Parse date. date = None if options["date"]: if days: raise CommandError("You cannot use --date and --days at the same time. They are exclusive.") try: date = datetime.datetime.strptime(options["date"], "%Y-%m-%d").date() except ValueError: raise CommandError(( "The date you gave (%s) is not a valid date. ", "The date should be in the ISO format (YYYY-MM-DD)." ) % options["date"]) # Find the date from the days arguments. elif days: date = datetime.date.today() - datetime.timedelta(days) # Build the queries revision_query = Revision.objects.using(database).filter( manager_slug=revision_manager._manager_slug, ) if date: revision_query = revision_query.filter(date_created__lt=date) if app_labels: model_classes = parse_app_labels(revision_manager, app_labels) content_types = [ revision_manager._get_content_type(model_class, db=database) for model_class in model_classes ] revision_query = revision_query.filter(version__content_type__in=content_types) if not force: excluded_content_types = ContentType.objects.db_manager(database).exclude(pk__in=[ content_type.pk for content_type in content_types ]) revision_query = revision_query.exclude(version__content_type__in=excluded_content_types) # Handle keeping n versions. if keep: objs = Version.objects.using(database).filter( revision__manager_slug=revision_manager._manager_slug, revision__in=revision_query, ) # Get all the objects that have more than the maximum revisions. objs = objs.values("object_id", "content_type_id", "db").annotate( total_ver=Count("object_id"), ).filter(total_ver__gt=keep) # Get all ids of the oldest revisions minus the max allowed revisions for all objects. revisions_not_kept = set() for obj in objs: revisions_not_kept.update(list(Version.objects.using(database).filter( content_type__id=obj["content_type_id"], object_id=obj["object_id"], db=obj["db"], ).order_by("-pk").values_list("revision_id", flat=True)[keep:])) revision_query = revision_query.filter(pk__in=revisions_not_kept) revision_count = revision_query.count() # Ask confirmation if interactive: choice = input("Are you sure you want to delete %s revisions? [y|N] " % revision_count) if choice.lower() != "y": self.stdout.write("Aborting revision deletion.") return # Delete versions and revisions if verbosity >= 2: self.stdout.write("Deleting %s revisions..." % revision_count) # Delete the revisions. with transaction.atomic(using=database): revision_query.delete() # Final logging. if verbosity >= 2: self.stdout.write("Deleted %s revisions." % revision_count)
def handle(self, *args, **options): if len(args) != 1: raise CommandError("You must specify a filename on the command " "line.") filename = args[0] if not os.path.exists(filename): raise CommandError("%s does not exist." % filename) confirm = input(""" This will wipe out your existing database prior to loading. It is highly recommended that you have a full SQL database dump in case things go wrong. You should only use this if you're migrating from one type of database to another, with the same version of Review Board on each. Are you sure you want to continue?" Type 'yes' to continue, or 'no' to cancel: """) if confirm != 'yes': return apps = [app.__name__.split('.')[-2] for app in get_apps()] os.system('./reviewboard/manage.py reset --noinput %s' % ' '.join(apps)) transaction_setup = False try: with open(filename, 'r') as f: line = f.readline() m = re.match("^# dbdump v(\d+) - (\d+) objects$", line) if not m: raise CommandError("Unknown dump format\n") version = int(m.group(1)) totalobjs = int(m.group(2)) i = 0 prev_pct = -1 if version != 1: raise CommandError("Unknown dump version\n") transaction.commit_unless_managed() transaction.enter_transaction_management() transaction.managed(True) transaction_setup = True self.stdout.write("Importing new style dump format (v%s)" % version) for line in f: if line[0] == "{": for obj in serializers.deserialize( "json", "[%s]" % line): try: obj.save() except Exception as e: self.stderr.write("Error: %s\n" % e) self.stderr.write("Line %s: '%s'" % (i, line)) elif line[0] != "#": self.stderr.write("Junk data on line %s" % i) db.reset_queries() i += 1 pct = (i * 100 / totalobjs) if pct != prev_pct: self.stdout.write(" [%s%%]\r" % pct) self.stdout.flush() prev_pct = pct transaction.commit() transaction.leave_transaction_management() except Exception as e: raise CommandError("Problem installing '%s': %s\n" % (filename, e)) if transaction_setup: transaction.rollback() transaction.leave_transaction_management() self.stdout.write('\nDone.')
def handle(self, parsed_args): django.setup() management.call_command( "startproject", parsed_args.name, verbosity=False ) path = "%(name)s/%(name)s" % {"name": parsed_args.name} sys.path.append(parsed_args.name) conn_tpl = Template(DBCONN_TPL) connections = {} if parsed_args.dburl: for dburl in parsed_args.dburl: conn_name, url = dburl.split(":", 1) info = dj_database_url.config(default=url) # In case the user fails to supply a valid database url, # fallback to manual mode if not info: print("There was a problem with your database-url. \n") info = self.ask_db_info(conn_name) # If we set this earlier, our fallback method will never # be triggered info["conn_name"] = conn_name connections[conn_name] = conn_tpl.render(Context(info)) else: connections["default"] = conn_tpl.render( Context(self.ask_db_info())) if parsed_args.domain: allowed_host = parsed_args.domain else: allowed_host = input( "What will be the hostname used to access Modoboa? ") if not allowed_host: allowed_host = "localhost" extra_settings = [] extensions = parsed_args.extensions if extensions: if "all" in extensions: extensions = self._get_extension_list() extensions = [(extension, extension.replace("-", "_")) for extension in extensions] if not parsed_args.dont_install_extensions: cmd = ( sys.executable + " -m pip install " + " ".join([extension[0] for extension in extensions]) ) exec_cmd(cmd, capture_output=False) extra_settings = self.find_extra_settings(extensions) extensions = [extension[1] for extension in extensions] bower_components_dir = os.path.realpath( os.path.join(os.path.dirname(__file__), "../../bower_components") ) mod = __import__( parsed_args.name, globals(), locals(), [smart_str("settings")] ) tpl = self._render_template( "%s/settings.py.tpl" % self._templates_dir, { "db_connections": connections, "secret_key": mod.settings.SECRET_KEY, "name": parsed_args.name, "allowed_host": allowed_host, "lang": parsed_args.lang, "timezone": parsed_args.timezone, "bower_components_dir": bower_components_dir, "devmode": parsed_args.devel, "extensions": extensions, "extra_settings": extra_settings } ) with codecs.open("%s/settings.py" % path, "w", "utf-8") as fp: fp.write(tpl) shutil.copyfile( "%s/urls.py.tpl" % self._templates_dir, "%s/urls.py" % path ) os.mkdir("%s/media" % parsed_args.name) if isfile("%s/settings.pyc" % path): os.unlink("%s/settings.pyc" % path) self._exec_django_command( "migrate", parsed_args.name, "--noinput" ) self._exec_django_command( "load_initial_data", parsed_args.name, "--admin-username", parsed_args.admin_username ) if parsed_args.collectstatic: self._exec_django_command( "collectstatic", parsed_args.name, "--noinput" ) self._exec_django_command( "set_default_site", parsed_args.name, allowed_host )
def handle(self, *args, **options): username = options.get('username', None) interactive = options.get('interactive') verbosity = int(options.get('verbosity', 1)) database = options.get('database') UserModel = get_user_model() username_field = UserModel._meta.get_field( getattr(UserModel, 'USERNAME_FIELD', 'username')) other_fields = UserModel.REQUIRED_FIELDS # If not provided, create the user with an unusable password password = None other_data = {} # Do quick and dirty validation if --noinput if not interactive: try: if not username: raise CommandError( "You must use --username with --noinput.") username = username_field.clean(username, None) for field_name in other_fields: if options.get(field_name): field = UserModel._meta.get_field(field_name) other_data[field_name] = field.clean( options[field_name], None) else: raise CommandError( "You must use --%s with --noinput." % field_name) except exceptions.ValidationError as e: raise CommandError('; '.join(e.messages)) else: # Prompt for username/password, and any other required fields. # Enclose this whole thing in a try/except to trap for a # keyboard interrupt and exit gracefully. default_username = get_default_username() try: # Get a username while username is None: username_field = UserModel._meta.get_field( getattr(UserModel, 'USERNAME_FIELD', 'username')) if not username: input_msg = capfirst(username_field.verbose_name) if default_username: input_msg += " (leave blank to use '%s')" % default_username raw_value = input(input_msg + ': ') if default_username and raw_value == '': raw_value = default_username try: username = username_field.clean(raw_value, None) except exceptions.ValidationError as e: self.stderr.write("Error: %s" % '; '.join(e.messages)) username = None continue try: UserModel.objects.using(database).get( **{ getattr(UserModel, 'USERNAME_FIELD', 'username'): username }) except UserModel.DoesNotExist: pass else: self.stderr.write( "Error: That username is already taken.") username = None for field_name in other_fields: field = UserModel._meta.get_field(field_name) other_data[field_name] = options.get(field_name) while other_data[field_name] is None: raw_value = input(capfirst(field.verbose_name + ': ')) try: other_data[field_name] = field.clean( raw_value, None) except exceptions.ValidationError as e: self.stderr.write("Error: %s" % '; '.join(e.messages)) other_data[field_name] = None # Get a password while password is None: if not password: password = getpass.getpass() password2 = getpass.getpass('Password (again): ') if password != password2: self.stderr.write( "Error: Your passwords didn't match.") password = None continue if password.strip() == '': self.stderr.write( "Error: Blank passwords aren't allowed.") password = None continue except KeyboardInterrupt: self.stderr.write("\nOperation cancelled.") sys.exit(1) UserModel.objects.db_manager(database).create_superuser( username=username, password=password, **other_data) if verbosity >= 1: self.stdout.write("Superuser created successfully.")
def prompt_choice(self, prompt, choices): """Prompt the user for a choice from a list. Args: prompt (unicode): The text prompting for a choice. choices (list of dict): The list of choices to present. Each entry is a dictionary with the following keys: ``text`` (:py:class:`unicode`): The text for the choice. ``description`` (:py:class:`unicode`, optional): A description of the choice. ``enabled`` (:py:class:`bool`, optional): Whether the option is enabled/visible. Returns: object: The resulting choice. """ self.print() self.print('You can type either the name or the number from the ' 'list below.') self.print() prompt_style = self.prompt_style valid_choices = [] i = 0 for choice in choices: if choice.get('enabled', True): text = choice['text'] self.print('%s %s %s\n' % (prompt_style( '(%d)' % (i + 1)), text, choice.get('description', ''))) valid_choices.append(text) i += 1 self.print() prompt = self.prompt_style('%s: ' % prompt) choice = None while not choice: self.print(prompt, trailing_newline=False) choice = input() if choice not in valid_choices: try: i = int(choice) - 1 if 0 <= i < len(valid_choices): choice = valid_choices[i] break except ValueError: pass self.error("'%s' is not a valid option." % choice) choice = None return choice
def handle(self, **options): self.set_options(**options) message = ['\n'] if self.dry_run: message.append( 'You have activated the --dry-run option so no files will be modified.\n\n' ) message.append( 'You have requested to collect static files at the destination\n' 'location as specified in your settings') if self.is_local_storage() and self.storage.location: destination_path = self.storage.location message.append(':\n\n %s\n\n' % destination_path) should_warn_user = (self.storage.exists(destination_path) and any( self.storage.listdir(destination_path))) else: destination_path = None message.append('.\n\n') # Destination files existence not checked; play it safe and warn. should_warn_user = True if self.interactive and should_warn_user: if self.clear: message.append( 'This will DELETE ALL FILES in this location!\n') else: message.append('This will overwrite existing files!\n') message.append('Are you sure you want to do this?\n\n' "Type 'yes' to continue, or 'no' to cancel: ") if input(''.join(message)) != 'yes': raise CommandError("Collecting static files cancelled.") collected = self.collect() modified_count = len(collected['modified']) unmodified_count = len(collected['unmodified']) post_processed_count = len(collected['post_processed']) if self.verbosity >= 1: template = ("\n%(modified_count)s %(identifier)s %(action)s" "%(destination)s%(unmodified)s%(post_processed)s.\n") summary = template % { 'modified_count': modified_count, 'identifier': 'static file' + ('' if modified_count == 1 else 's'), 'action': 'symlinked' if self.symlink else 'copied', 'destination': (" to '%s'" % destination_path if destination_path else ''), 'unmodified': (', %s unmodified' % unmodified_count if collected['unmodified'] else ''), 'post_processed': (collected['post_processed'] and ', %s post-processed' % post_processed_count or ''), } return summary
def prompt_input(self, prompt, prompt_type=PROMPT_TYPE_TEXT, default=None, optional=False, strip=True, validate_func=None): """Prompt the user for input. Args: prompt (unicode): The text prompting for input. prompt_type (unicode, optional): The type of input to prompt for. This is one of: * :py:attr:`PROMPT_TYPE_TEXT` * :py:attr:`PROMPT_TYPE_PASSWORD` * :py:attr:`PROMPT_TYPE_YES_NO` default (bool or unicode, optional): The default value to show and use, if an explicit value isn't provided by the user. For yes/no prompts, this should be a boolean. For all else, a string. optional (bool, optional): Whether the prompt is optional and can be skipped by omitting a value. strip (bool, optional): Whether to strip the provided input. validate_func (callable, optional): An optional function for determining if input is valid. This takes the input as a parameter and raises a :py:class:`django.core.exceptions.ValidationError` if invalid. .. code-block:: python def _is_valid(value): if value != 'abc': raise ValidationError('bad!') Returns: unicode: The resulting inputted value. """ if prompt_type == self.PROMPT_TYPE_YES_NO: if default is True: prompt = '%s [Y/n]' % prompt elif default is False: prompt = '%s [y/N]' % prompt default = False else: prompt = '%s [y/n]' % prompt elif default: self.print() self.print('The default is "%s"' % default) prompt = '%s [%s]' % (prompt, default) elif optional: prompt = '%s (optional)' % prompt self.print() prompt = self.prompt_style('%s: ' % prompt) value = None while not value: self.print(prompt, trailing_newline=False) self.stdout.flush() if prompt_type == self.PROMPT_TYPE_PASSWORD: value = getpass.getpass(str(''), stream=self.stdout) else: value = input() if strip: value = value.strip() if not value: if default: value = default elif optional: break if validate_func is not None: try: validate_func(value) except ValidationError as e: for error in e.messages: self.error(error) value = None continue if prompt_type == self.PROMPT_TYPE_YES_NO: if isinstance(value, bool): # This came from the 'default' value. norm_value = value else: assert isinstance(value, six.string_types) norm_value = value.lower() if norm_value not in (True, False, 'y', 'n', 'yes', 'no'): self.error('Must specify one of Y/y/yes or N/n/no.') value = None continue else: value = norm_value in (True, 'y', 'yes') break elif not value: self.error('An answer is required.') return value
def ask_user(self, message, default=None): # pylint: disable=import-error from django.utils.six.moves import input if getattr(self, 'interactive_mode', False): return input(message) or default return default
def handle(self, *args, **options): name = options.get('full_name', None) client_name = options.get('client_name', None) schema_name = options.get('schema_name', None) domain_url = options.get('domain_url', None) post_command = options.get('post_command', None) # If full-name is specified then don't prompt for any values. if name: if not client_name: client_name = ''.join(ch if ch.isalnum() else '-' for ch in name).lower() if not schema_name: schema_name = client_name.replace('-', '_') if not domain_url: base_domain = getattr(settings, 'TENANT_BASE_DOMAIN', 'localhost') domain_url = '{0}.{1}'.format(client_name, base_domain) client = self.store_client(name=name, client_name=client_name, domain_url=domain_url, schema_name=schema_name) if not client: name = None while name is None: if not name: input_msg = 'Tenant name' name = input(force_str('%s: ' % input_msg)) default_client_name = ''.join(ch if ch.isalnum() else '-' for ch in name).lower() default_schema_name = default_client_name.replace('-', '_') base_domain = getattr(settings, 'TENANT_BASE_DOMAIN', 'localhost') default_domain_url = '{0}.{1}'.format(default_client_name, base_domain) while client_name is None: if not client_name: input_msg = 'Client name' input_msg = "%s (leave blank to use '%s')" % ( input_msg, default_client_name) client_name = input(force_str( '%s: ' % input_msg)) or default_client_name while schema_name is None: if not schema_name: input_msg = 'Database schema name' input_msg = "%s (leave blank to use '%s')" % ( input_msg, default_schema_name) schema_name = input(force_str( '%s: ' % input_msg)) or default_schema_name while domain_url is None: if not domain_url: input_msg = 'Domain url' input_msg = "%s (leave blank to use '%s')" % ( input_msg, default_domain_url) domain_url = input(force_str( '%s: ' % input_msg)) or default_domain_url client = self.store_client(name=name, client_name=client_name, domain_url=domain_url, schema_name=schema_name) if client is False: break if not client: name = None continue if client and client_name: self.load_fixtures(client_name=client_name) if client and post_command: call_command(post_command, *args, **options)
def _create_test_db(self, verbosity=1, autoclobber=False, keepdb=False): parameters = self._get_test_db_params() cursor = self._maindb_connection.cursor() if self._test_database_create(): try: self._execute_test_db_creation(cursor, parameters, verbosity, keepdb) except Exception as e: # if we want to keep the db, then no need to do any of the below, # just return and skip it all. if keepdb: return sys.stderr.write("Got an error creating the test database: %s\n" % e) if not autoclobber: confirm = input( "It appears the test database, %s, already exists. " "Type 'yes' to delete it, or 'no' to cancel: " % parameters['user']) if autoclobber or confirm == 'yes': if verbosity >= 1: print("Destroying old test database for alias '%s'..." % self.connection.alias) try: self._execute_test_db_destruction(cursor, parameters, verbosity) except DatabaseError as e: if 'ORA-29857' in str(e): self._handle_objects_preventing_db_destruction(cursor, parameters, verbosity, autoclobber) else: # Ran into a database error that isn't about leftover objects in the tablespace sys.stderr.write("Got an error destroying the old test database: %s\n" % e) sys.exit(2) except Exception as e: sys.stderr.write("Got an error destroying the old test database: %s\n" % e) sys.exit(2) try: self._execute_test_db_creation(cursor, parameters, verbosity, keepdb) except Exception as e: sys.stderr.write("Got an error recreating the test database: %s\n" % e) sys.exit(2) else: print("Tests cancelled.") sys.exit(1) if self._test_user_create(): if verbosity >= 1: print("Creating test user...") try: self._create_test_user(cursor, parameters, verbosity, keepdb) except Exception as e: sys.stderr.write("Got an error creating the test user: %s\n" % e) if not autoclobber: confirm = input( "It appears the test user, %s, already exists. Type " "'yes' to delete it, or 'no' to cancel: " % parameters['user']) if autoclobber or confirm == 'yes': try: if verbosity >= 1: print("Destroying old test user...") self._destroy_test_user(cursor, parameters, verbosity) if verbosity >= 1: print("Creating test user...") self._create_test_user(cursor, parameters, verbosity, keepdb) except Exception as e: sys.stderr.write("Got an error recreating the test user: %s\n" % e) sys.exit(2) else: print("Tests cancelled.") sys.exit(1) self._maindb_connection.close() # done with main user -- test user and tablespaces created self._switch_to_test_user(parameters) return self.connection.settings_dict['NAME']
def get_client_and_server_certs(username, password, dataset_id, nc, user_id=None, noninteractive=False): # get any full-facility certificates we have for the facility owned_certs = (Certificate.objects.filter(id=dataset_id).get_descendants( include_self=True).filter( scope_definition_id=ScopeDefinitions.FULL_FACILITY).exclude( _private_key=None)) if not user_id: # it's a full-facility sync csr_scope_params = {"dataset_id": dataset_id} client_scope = ScopeDefinitions.FULL_FACILITY server_scope = ScopeDefinitions.FULL_FACILITY else: # it's a single-user sync csr_scope_params = {"dataset_id": dataset_id, "user_id": user_id} if owned_certs: # client is the one with a full-facility cert client_scope = ScopeDefinitions.FULL_FACILITY server_scope = ScopeDefinitions.SINGLE_USER else: # server must be the one with the full-facility cert client_scope = ScopeDefinitions.SINGLE_USER server_scope = ScopeDefinitions.FULL_FACILITY # check for certs we own for the specific user_id for single-user syncing owned_certs = (Certificate.objects.filter( id=dataset_id).get_descendants(include_self=True).filter( scope_definition_id=ScopeDefinitions.SINGLE_USER).filter( scope_params__contains=user_id).exclude( _private_key=None)) # get server certificates that server has a private key for server_certs = nc.get_remote_certificates(dataset_id, scope_def_id=server_scope) # filter down to the single-user certificates for this specific user, if needed if server_scope == ScopeDefinitions.SINGLE_USER: server_certs = [ cert for cert in server_certs if user_id in cert.scope_params ] if not server_certs: raise CommandError( "Server does not have needed certificate with scope '{}'".format( server_scope)) server_cert = server_certs[0] # if we don't own any certs, do a csr request if not owned_certs: # prompt user for creds if not already specified if not username or not password: if noninteractive: raise CommandError( "Server username and/or password not specified") else: username = input("Please enter username: "******"Please enter password: ") client_cert = nc.certificate_signing_request( server_cert, client_scope, csr_scope_params, userargs=username, password=password, ) else: client_cert = owned_certs[0] return client_cert, server_cert, username
def handle(self, *args, **options): username = options.get(self.UserModel.USERNAME_FIELD, None) database = options.get('database') # If not provided, create the user with an unusable password password = None user_data = {} # Do quick and dirty validation if --noinput if not options['interactive']: try: if not username: raise CommandError("You must use --%s with --noinput." % self.UserModel.USERNAME_FIELD) username = self.username_field.clean(username, None) for field_name in self.UserModel.REQUIRED_FIELDS: if options.get(field_name): field = self.UserModel._meta.get_field(field_name) user_data[field_name] = field.clean( options[field_name], None) else: raise CommandError( "You must use --%s with --noinput." % field_name) except exceptions.ValidationError as e: raise CommandError('; '.join(e.messages)) else: # Prompt for username/password, and any other required fields. # Enclose this whole thing in a try/except to trap for a # keyboard interrupt and exit gracefully. default_username = get_default_username() try: if hasattr(self.stdin, 'isatty') and not self.stdin.isatty(): raise NotRunningInTTYException("Not running in a TTY") # Get a username verbose_field_name = self.username_field.verbose_name while username is None: if not username: input_msg = capfirst(verbose_field_name) if default_username: input_msg = "%s (leave blank to use '%s')" % ( input_msg, default_username) raw_value = input(force_str('%s: ' % input_msg)) if default_username and raw_value == '': raw_value = default_username try: username = self.username_field.clean(raw_value, None) except exceptions.ValidationError as e: self.stderr.write("Error: %s" % '; '.join(e.messages)) username = None continue try: self.UserModel._default_manager.db_manager( database).get_by_natural_key(username) except self.UserModel.DoesNotExist: pass else: self.stderr.write("Error: That %s is already taken." % verbose_field_name) username = None for field_name in self.UserModel.REQUIRED_FIELDS: field = self.UserModel._meta.get_field(field_name) user_data[field_name] = options.get(field_name) while user_data[field_name] is None: raw_value = input( force_str('%s: ' % capfirst(field.verbose_name))) try: user_data[field_name] = field.clean( raw_value, None) except exceptions.ValidationError as e: self.stderr.write("Error: %s" % '; '.join(e.messages)) user_data[field_name] = None # Get a password while password is None: if not password: password = getpass.getpass() password2 = getpass.getpass( force_str('Password (again): ')) if password != password2: self.stderr.write( "Error: Your passwords didn't match.") password = None continue if password.strip() == '': self.stderr.write( "Error: Blank passwords aren't allowed.") password = None continue except KeyboardInterrupt: self.stderr.write("\nOperation cancelled.") sys.exit(1) except NotRunningInTTYException: self.stdout.write( "Superuser creation skipped due to not running in a TTY. " "You can run `manage.py createsuperuser` in your project " "to create one manually.") if username: user_data[self.UserModel.USERNAME_FIELD] = username user_data['password'] = password self.UserModel._default_manager.db_manager( database).create_superuser(**user_data) if options['verbosity'] >= 1: self.stdout.write("Superuser created successfully.")
def handle_label(self, filename, **options): missing_options = [] for k in ['generation_id', 'area_type_code', 'name_type_code', 'country_code']: if options[k]: continue else: missing_options.append(k) if missing_options: message_start = "Missing arguments " if len(missing_options) > 1 else "Missing argument " message = message_start + " ".join('--{0}'.format(k) for k in missing_options) raise CommandError(message) generation_id = options['generation_id'] area_type_code = options['area_type_code'] name_type_code = options['name_type_code'] country_code = options['country_code'] override_name = options['override_name'] name_field = options['name_field'] if not (override_name or name_field): name_field = 'Name' override_code = options['override_code'] code_field = options['code_field'] code_type_code = options['code_type'] encoding = options['encoding'] or 'utf-8' if name_field and override_name: raise CommandError("You must not specify both --name_field and --override_name") if code_field and override_code: raise CommandError("You must not specify both --code_field and --override_code") using_code = (code_field or override_code) if (using_code and not code_type_code) or (not using_code and code_type_code): raise CommandError( "If you want to save a code, specify --code_type and either --code_field or --override_code") try: area_type = Type.objects.get(code=area_type_code) except: type_desc = input('Please give a description for area type code %s: ' % area_type_code) area_type = Type(code=area_type_code, description=type_desc) if options['commit']: area_type.save() try: name_type = NameType.objects.get(code=name_type_code) except: name_desc = input('Please give a description for name type code %s: ' % name_type_code) name_type = NameType(code=name_type_code, description=name_desc) if options['commit']: name_type.save() try: country = Country.objects.get(code=country_code) except: country_name = input('Please give the name for country code %s: ' % country_code) country = Country(code=country_code, name=country_name) if options['commit']: country.save() if code_type_code: try: code_type = CodeType.objects.get(code=code_type_code) except: code_desc = input('Please give a description for code type %s: ' % code_type_code) code_type = CodeType(code=code_type_code, description=code_desc) if options['commit']: code_type.save() self.stdout.write("Importing from %s" % filename) if not options['commit']: self.stdout.write('(will not save to db as --commit not specified)') current_generation = Generation.objects.current() new_generation = Generation.objects.get(id=generation_id) def verbose(*args): if int(options['verbosity']) > 1: self.stdout.write(" ".join(str(a) for a in args)) ds = DataSource(filename) layer = ds[0] if (override_name or override_code) and len(layer) > 1: message = ( "Warning: you have specified an override %s and this file contains more than one feature; " "multiple areas with the same %s will be created") if override_name: self.stdout.write(message % ('name', 'name')) if override_code: self.stdout.write(message % ('code', 'code')) for feat in layer: if override_name: name = override_name else: name = None for nf in name_field.split(','): try: name = feat[nf].value break except: pass if name is None: choices = ', '.join(layer.fields) raise CommandError( "Could not find name using name field '%s' - should it be something else? " "It will be one of these: %s. Specify which with --name_field" % (name_field, choices)) try: if not isinstance(name, six.text_type): name = name.decode(encoding) except: raise CommandError( "Could not decode name using encoding '%s' - is it in another encoding? " "Specify one with --encoding" % encoding) name = re.sub('\s+', ' ', name) if not name: if options['ignore_blank']: continue raise Exception("Could not find a name to use for area") code = None if override_code: code = override_code elif code_field: try: code = feat[code_field].value except: choices = ', '.join(layer.fields) raise CommandError( "Could not find code using code field '%s' - should it be something else? " "It will be one of these: %s. Specify which with --code_field" % (code_field, choices)) self.stdout.write(" looking at '%s'%s" % (name, (' (%s)' % code) if code else '')) g = None if hasattr(feat, 'geom'): g = feat.geom.transform(settings.MAPIT_AREA_SRID, clone=True) try: if options['new']: # Always want a new area raise Area.DoesNotExist if code: matching_message = "code %s of code type %s" % (code, code_type) areas = Area.objects.filter(codes__code=code, codes__type=code_type).order_by('-generation_high') else: matching_message = "name %s of area type %s" % (name, area_type) areas = Area.objects.filter(name=name, type=area_type).order_by('-generation_high') if len(areas) == 0: verbose(" the area was not found - creating a new one") raise Area.DoesNotExist m = areas[0] verbose(" found the area") if options['preserve']: # Find whether we need to create a new Area: previous_geos_geometry = m.polygons.aggregate(Collect('polygon'))['polygon__collect'] if m.generation_high < current_generation.id: # Then it was missing in current_generation: verbose(" area existed previously, but was missing from", current_generation) raise Area.DoesNotExist elif g is None: if previous_geos_geometry is not None: verbose(" area is now empty") raise Area.DoesNotExist else: verbose(" the area has remained empty") elif previous_geos_geometry is None: # It was empty in the previous generation: verbose(" area was empty in", current_generation) raise Area.DoesNotExist else: # Otherwise, create a new Area unless the # polygons were the same in current_generation: previous_geos_geometry = previous_geos_geometry.simplify(tolerance=0) new_geos_geometry = g.geos.simplify(tolerance=0) create_new_area = not previous_geos_geometry.equals(new_geos_geometry) p = previous_geos_geometry.sym_difference(new_geos_geometry).area / previous_geos_geometry.area verbose(" change in area is:", "%.03f%%" % (100 * p,)) if create_new_area: verbose(" the area", m, "has changed, creating a new area due to --preserve") raise Area.DoesNotExist else: verbose(" the area remained the same") else: # If --preserve is not specified, the code or the name must be unique: if len(areas) > 1: raise Area.MultipleObjectsReturned( "There was more than one area with %s, and --preserve was not specified" % ( matching_message,)) except Area.DoesNotExist: m = Area( name=name, type=area_type, country=country, # parent_area=parent_area, generation_low=new_generation, generation_high=new_generation, ) if options['use_code_as_id'] and code: m.id = int(code) # check that we are not about to skip a generation if m.generation_high and current_generation and m.generation_high.id < current_generation.id: raise Exception("Area %s found, but not in current generation %s" % (m, current_generation)) m.generation_high = new_generation if options['fix_invalid_polygons'] and g is not None: # Make a GEOS geometry only to check for validity: geos_g = g.geos if not geos_g.valid: geos_g = fix_invalid_geos_geometry(geos_g) if geos_g is None: self.stdout.write("The geometry for area %s was invalid and couldn't be fixed" % name) g = None else: g = geos_g.ogr poly = [g] if g is not None else [] if options['commit']: m.save() m.names.update_or_create(type=name_type, defaults={'name': name}) if code: m.codes.update_or_create(type=code_type, defaults={'code': code}) save_polygons({m.id: (m, poly)})
def _create_test_db(self, verbosity=1, autoclobber=False): TEST_NAME = self._test_database_name() TEST_USER = self._test_database_user() TEST_PASSWD = self._test_database_passwd() TEST_TBLSPACE = self._test_database_tblspace() TEST_TBLSPACE_TMP = self._test_database_tblspace_tmp() parameters = { 'dbname': TEST_NAME, 'user': TEST_USER, 'password': TEST_PASSWD, 'tblspace': TEST_TBLSPACE, 'tblspace_temp': TEST_TBLSPACE_TMP, } cursor = self.connection.cursor() if self._test_database_create(): try: self._execute_test_db_creation(cursor, parameters, verbosity) except Exception as e: sys.stderr.write( "Got an error creating the test database: %s\n" % e) if not autoclobber: confirm = input( "It appears the test database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_NAME) if autoclobber or confirm == 'yes': try: if verbosity >= 1: print("Destroying old test database '%s'..." % self.connection.alias) self._execute_test_db_destruction( cursor, parameters, verbosity) self._execute_test_db_creation(cursor, parameters, verbosity) except Exception as e: sys.stderr.write( "Got an error recreating the test database: %s\n" % e) sys.exit(2) else: print("Tests cancelled.") sys.exit(1) if self._test_user_create(): if verbosity >= 1: print("Creating test user...") try: self._create_test_user(cursor, parameters, verbosity) except Exception as e: sys.stderr.write("Got an error creating the test user: %s\n" % e) if not autoclobber: confirm = input( "It appears the test user, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % TEST_USER) if autoclobber or confirm == 'yes': try: if verbosity >= 1: print("Destroying old test user...") self._destroy_test_user(cursor, parameters, verbosity) if verbosity >= 1: print("Creating test user...") self._create_test_user(cursor, parameters, verbosity) except Exception as e: sys.stderr.write( "Got an error recreating the test user: %s\n" % e) sys.exit(2) else: print("Tests cancelled.") sys.exit(1) real_settings = settings.DATABASES[self.connection.alias] real_settings['SAVED_USER'] = self.connection.settings_dict[ 'SAVED_USER'] = self.connection.settings_dict['USER'] real_settings['SAVED_PASSWORD'] = self.connection.settings_dict[ 'SAVED_PASSWORD'] = self.connection.settings_dict['PASSWORD'] real_test_settings = real_settings['TEST'] test_settings = self.connection.settings_dict['TEST'] real_test_settings['USER'] = real_settings['USER'] = test_settings[ 'USER'] = self.connection.settings_dict['USER'] = TEST_USER real_settings['PASSWORD'] = self.connection.settings_dict[ 'PASSWORD'] = TEST_PASSWD return self.connection.settings_dict['NAME']
def update_contenttypes(app, created_models, verbosity=2, db=DEFAULT_DB_ALIAS, **kwargs): """ Django's default update_contenttypes relies on many inconsistent queries which causes problems with syncdb. This monkeypatch replaces it with a version that does look ups on unique constraints which are slightly better protected from eventual consistency issues by the context cache. """ if verbosity >= 2: print( "Running Djangae version of update_contenttypes on {}".format(app)) try: get_model('contenttypes', 'ContentType') except UnavailableApp: return if hasattr(router, "allow_syncdb"): if not router.allow_syncdb(db, ContentType): return else: if not router.allow_migrate(db, ContentType): return ContentType.objects.clear_cache() app_models = get_models(app) if not app_models: return # They all have the same app_label, get the first one. app_label = app_models[0]._meta.app_label app_models = dict((model._meta.model_name, model) for model in app_models) created_or_existing_pks = [] created_or_existing_by_unique = {} for (model_name, model) in six.iteritems(app_models): # Go through get_or_create any models that we want to keep ct, created = ContentType.objects.get_or_create( app_label=app_label, model=model_name, defaults={"name": smart_text(model._meta.verbose_name_raw)}) if verbosity >= 2 and created: print("Adding content type '%s | %s'" % (ct.app_label, ct.model)) created_or_existing_pks.append(ct.pk) created_or_existing_by_unique[(app_label, model_name)] = ct.pk # Now lets see if we should remove any to_remove = [ x for x in ContentType.objects.filter(app_label=app_label) if x.pk not in created_or_existing_pks ] # Now it's possible that our get_or_create failed because of consistency issues and we create a duplicate. # Then the original appears in the to_remove and we remove the original. This is bad. So here we go through the # to_remove list, and if we created the content type just now, we delete that one, and restore the original in the # cache for ct in to_remove: unique = (ct.app_label, ct.model) if unique in created_or_existing_by_unique: # We accidentally created a duplicate above due to HRD issues, delete the one we created ContentType.objects.get( pk=created_or_existing_by_unique[unique]).delete() created_or_existing_by_unique[unique] = ct.pk ct.save() # Recache this one in the context cache to_remove = [ x for x in to_remove if (x.app_label, x.model) not in created_or_existing_by_unique ] # Now, anything left should actually be a stale thing. It's still possible we missed some but they'll get picked up # next time. Confirm that the content type is stale before deletion. if to_remove: if kwargs.get('interactive', False): content_type_display = '\n'.join( [' %s | %s' % (x.app_label, x.model) for x in to_remove]) ok_to_delete = input( """The following content types are stale and need to be deleted: %s Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'. Type 'yes' to continue, or 'no' to cancel: """ % content_type_display) else: ok_to_delete = False if ok_to_delete == 'yes': for ct in to_remove: if verbosity >= 2: print("Deleting stale content type '%s | %s'" % (ct.app_label, ct.model)) ct.delete() else: if verbosity >= 2: print("Stale content types remain.")
def upgrade_database(): """Perform an upgrade of the database. This will prompt the user for confirmation, with instructions on what will happen. If the database is using SQLite3, it will be backed up automatically, making a copy that contains the current timestamp. Otherwise, the user will be prompted to back it up instead. Returns: bool: ``True`` if the user has confirmed the upgrade. ``False`` if they have not. """ from django.conf import settings from django.utils.six.moves import input database = settings.DATABASES['default'] db_name = database['NAME'] backup_db_name = None # See if we can make a backup of the database. if ('--no-backup' not in sys.argv and database['ENGINE'] == 'django.db.backends.sqlite3' and os.path.exists(db_name)): # Make a copy of the database. backup_db_name = '%s.%s' % ( db_name, datetime.now().strftime('%Y%m%d.%H%M%S')) try: shutil.copy(db_name, backup_db_name) except Exception as e: sys.stderr.write('Unable to make a backup of your database at ' '%s: %s\n\n' % (db_name, e)) backup_db_name = None if '--noinput' in sys.argv: if backup_db_name: print ( 'Your existing database has been backed up to\n' '%s\n' % backup_db_name ) perform_upgrade = True else: message = ( 'You are about to upgrade your database, which cannot be undone.' '\n\n' ) if backup_db_name: message += ( 'Your existing database has been backed up to\n' '%s' % backup_db_name ) else: message += 'PLEASE MAKE A BACKUP BEFORE YOU CONTINUE!' message += '\n\nType "yes" to continue or "no" to cancel: ' perform_upgrade = input(message).lower() in ('yes', 'y') print('\n') if perform_upgrade: print( '===========================================================\n' 'Performing the database upgrade. Any "unapplied evolutions"\n' 'will be handled automatically.\n' '===========================================================\n' ) commands = [ ['syncdb', '--noinput'], ['evolve', '--noinput'] ] for command in commands: execute_from_command_line([sys.argv[0]] + command) else: print('The upgrade has been cancelled.\n') sys.exit(1)
def ask_user(self, message, default=None): if getattr(self, 'interactive_mode', False): return input(message) return default
def handle(self, *args, **options): HOSTS = settings.ES_CONNECTIONS[ settings.DESIGNSAFE_ENVIRONMENT]['hosts'] es_client = elasticsearch.Elasticsearch(HOSTS, http_auth=settings.ES_AUTH) index = options.get('index') cleanup = options.get('cleanup') swap_only = options.get('swap-only') index_config = settings.ES_INDICES[index] default_index_alias = index_config['alias'] reindex_index_alias = default_index_alias + '-reindex' if not swap_only: confirm = eval( input( 'This will delete any documents in the index "{}" and recreate the index. Continue? (Y/n) ' .format(reindex_index_alias))) if confirm != 'Y': raise SystemExit # Set up a fresh reindexing alias. setup_index(index_config, force=True, reindex=True) try: default_index_name = list( Index(default_index_alias, using=es_client).get_alias().keys())[0] reindex_index_name = list( Index(reindex_index_alias, using=es_client).get_alias().keys())[0] except Exception as e: self.stdout.write( 'Unable to lookup required indices by alias. Have you set up both a default and a reindexing index?' ) raise SystemExit if not swap_only: # Reindex file metadata from the default index to the reindexing index elasticsearch.helpers.reindex(es_client, default_index_name, reindex_index_name) alias_body = { 'actions': [ { 'remove': { 'index': default_index_name, 'alias': default_index_alias } }, { 'remove': { 'index': reindex_index_name, 'alias': reindex_index_alias } }, { 'add': { 'index': default_index_name, 'alias': reindex_index_alias } }, { 'add': { 'index': reindex_index_name, 'alias': default_index_alias } }, ] } # Swap the aliases of the default and reindexing aliases. es_client.indices.update_aliases(alias_body) # Re-initialize the new reindexing index to save space. if cleanup: reindex_index_name = list( Index(reindex_index_alias, using=es_client).get_alias().keys())[0] Index(reindex_index_name, using=es_client).delete(ignore=404)
def update_contenttypes(app, created_models, verbosity=2, db=DEFAULT_DB_ALIAS, **kwargs): """ Creates content types for models in the given app, removing any model entries that no longer have a matching model class. """ try: get_model('contenttypes', 'ContentType') except UnavailableApp: return if not router.allow_migrate(db, ContentType): return ContentType.objects.clear_cache() app_models = get_models(app) if not app_models: return # They all have the same app_label, get the first one. app_label = app_models[0]._meta.app_label app_models = dict((model._meta.model_name, model) for model in app_models) # Get all the content types content_types = dict( (ct.model, ct) for ct in ContentType.objects.using(db).filter(app_label=app_label)) to_remove = [ ct for (model_name, ct) in six.iteritems(content_types) if model_name not in app_models ] cts = [ ContentType( name=smart_text(model._meta.verbose_name_raw), app_label=app_label, model=model_name, ) for (model_name, model) in six.iteritems(app_models) if model_name not in content_types ] ContentType.objects.using(db).bulk_create(cts) if verbosity >= 2: for ct in cts: print("Adding content type '%s | %s'" % (ct.app_label, ct.model)) # Confirm that the content type is stale before deletion. if to_remove: if kwargs.get('interactive', False): content_type_display = '\n'.join( ' %s | %s' % (ct.app_label, ct.model) for ct in to_remove) ok_to_delete = input( """The following content types are stale and need to be deleted: %s Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'. Type 'yes' to continue, or 'no' to cancel: """ % content_type_display) else: ok_to_delete = False if ok_to_delete == 'yes': for ct in to_remove: if verbosity >= 2: print("Deleting stale content type '%s | %s'" % (ct.app_label, ct.model)) ct.delete() else: if verbosity >= 2: print("Stale content types remain.")
def handle(self, *args, **options): logfile = options.get('logfile') if logfile: handler = logging.FileHandler(logfile) else: handler = logging.StreamHandler() handler.setLevel(logging.INFO) handler.setFormatter(formatter) logger.addHandler(handler) if acquire_lock(): try: if not options.get('filename'): raise CommandError( 'You must provide path to csv-file. Use -f option.') path_to_file = os.path.normpath(options.get('filename')) if not os.path.exists(path_to_file): raise CommandError('File not found') if os.path.isdir(path_to_file): raise CommandError('%s is a directory' % path_to_file) with open(path_to_file, 'rb') as csvfile: try: dialect = csv.Sniffer().sniff(csvfile.read(2048), delimiters=';') csvfile.seek(0) data = csv.DictReader( csvfile, fieldnames=['old_path', 'new_path'], dialect=dialect) except csv.Error: mess = 'Incorrect file format' logger.error(mess) raise CommandError(mess) with transaction.commit_on_success(): try: for i, row in enumerate(data): old_path = row['old_path'] new_path = row['new_path'] if not old_path.startswith("/"): mess = 'LINE: %s. Invalid url: %s' % ( i + 1, old_path) logger.error(mess) raise Exception(mess) if not new_path.startswith("/"): mess = 'LINE: %s. Invalid url: %s' % ( i + 1, new_path) logger.error(mess) raise Exception(mess) redirect, created = Redirect.objects.get_or_create( site_id=settings.SITE_ID, old_path=old_path) if created: redirect.new_path = new_path redirect.save() else: if redirect.new_path != new_path: change = "" if not options.get('change'): self.stdout.write( '\nRedirect %s exist. Change to %s ---> %s ?:\n' % (redirect.__unicode__(), old_path, new_path)) change = input( '"y" for Yes or "n" for No (leave blank for "n"): ' ) if change == "y" or options.get( 'change'): redirect.new_path = new_path redirect.save() except DatabaseError: mess = 'Error in transaction. Please repeat import' logger.error(mess) raise logger.info('Import completed successfully') finally: release_lock() else: logger.error( 'Redirects is already being imported. Please repeat later')
def get_input(text): return input(text).strip()
def update_contenttypes(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, apps=global_apps, **kwargs): """ Creates content types for models in the given app, removing any model entries that no longer have a matching model class. """ if not app_config.models_module: return app_label = app_config.label try: app_config = apps.get_app_config(app_label) ContentType = apps.get_model('contenttypes', 'ContentType') except LookupError: return if not router.allow_migrate_model(using, ContentType): return ContentType.objects.clear_cache() # Always clear the global content types cache. if apps is not global_apps: global_apps.get_model('contenttypes', 'ContentType').objects.clear_cache() app_models = { model._meta.model_name: model for model in app_config.get_models() } if not app_models: return # Get all the content types content_types = { ct.model: ct for ct in ContentType.objects.using(using).filter(app_label=app_label) } to_remove = [ ct for (model_name, ct) in six.iteritems(content_types) if model_name not in app_models ] cts = [ ContentType( app_label=app_label, model=model_name, ) for (model_name, model) in six.iteritems(app_models) if model_name not in content_types ] ContentType.objects.using(using).bulk_create(cts) if verbosity >= 2: for ct in cts: print("Adding content type '%s | %s'" % (ct.app_label, ct.model)) # Confirm that the content type is stale before deletion. if to_remove: if interactive: content_type_display = '\n'.join( ' %s | %s' % (ct.app_label, ct.model) for ct in to_remove) ok_to_delete = input( """The following content types are stale and need to be deleted: %s Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'. Type 'yes' to continue, or 'no' to cancel: """ % content_type_display) else: ok_to_delete = False if ok_to_delete == 'yes': for ct in to_remove: if verbosity >= 2: print("Deleting stale content type '%s | %s'" % (ct.app_label, ct.model)) ct.delete() else: if verbosity >= 2: print("Stale content types remain.")