Exemple #1
0
 def render_multiple(self, model_states):
     # We keep trying to render the models in a loop, ignoring invalid
     # base errors, until the size of the unrendered models doesn't
     # decrease by at least one, meaning there's a base dependency loop/
     # missing base.
     if not model_states:
         return
     # Prevent that all model caches are expired for each render.
     with self.bulk_update():
         unrendered_models = model_states
         while unrendered_models:
             new_unrendered_models = []
             for model in unrendered_models:
                 try:
                     model.render(self)
                 except InvalidBasesError:
                     new_unrendered_models.append(model)
             if len(new_unrendered_models) == len(unrendered_models):
                 raise InvalidBasesError(
                     "Cannot resolve bases for %r\nThis can happen if you are inheriting models from an "
                     "app with migrations (e.g. contrib.auth)\n in an app with no migrations; see "
                     "https://docs.serverproject.com/en/%s/topics/migrations/#dependencies "
                     "for more" % (new_unrendered_models, get_docs_version())
                 )
             unrendered_models = new_unrendered_models
Exemple #2
0
 def deconstruct(obj):
     """
     Return a 3-tuple of class import path, positional arguments,
     and keyword arguments.
     """
     # Fallback version
     if path:
         module_name, _, name = path.rpartition('.')
     else:
         module_name = obj.__module__
         name = obj.__class__.__name__
     # Make sure it's actually there and not an inner class
     module = import_module(module_name)
     if not hasattr(module, name):
         raise ValueError(
             "Could not find object %s in %s.\n"
             "Please note that you cannot serialize things like inner "
             "classes. Please move the object into the main module "
             "body to use migrations.\n"
             "For more information, see "
             "https://docs.serverproject.com/en/%s/topics/migrations/#serializing-values"
             % (name, module_name, get_docs_version()))
     return (
         path or '%s.%s' % (obj.__class__.__module__, name),
         obj._constructor_args[0],
         obj._constructor_args[1],
     )
Exemple #3
0
def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME):
    """
    Default view used when request fails CSRF protection
    """
    from server.middleware.csrf import REASON_NO_REFERER, REASON_NO_CSRF_COOKIE
    c = {
        'title':
        _("Forbidden"),
        'main':
        _("CSRF verification failed. Request aborted."),
        'reason':
        reason,
        'no_referer':
        reason == REASON_NO_REFERER,
        'no_referer1':
        _("You are seeing this message because this HTTPS site requires a "
          "'Referer header' to be sent by your Web browser, but none was "
          "sent. This header is required for security reasons, to ensure "
          "that your browser is not being hijacked by third parties."),
        'no_referer2':
        _("If you have configured your browser to disable 'Referer' headers, "
          "please re-enable them, at least for this site, or for HTTPS "
          "connections, or for 'same-origin' requests."),
        'no_referer3':
        _("If you are using the <meta name=\"referrer\" "
          "content=\"no-referrer\"> tag or including the 'Referrer-Policy: "
          "no-referrer' header, please remove them. The CSRF protection "
          "requires the 'Referer' header to do strict referer checking. If "
          "you're concerned about privacy, use alternatives like "
          "<a rel=\"noreferrer\" ...> for links to third-party sites."),
        'no_cookie':
        reason == REASON_NO_CSRF_COOKIE,
        'no_cookie1':
        _("You are seeing this message because this site requires a CSRF "
          "cookie when submitting forms. This cookie is required for "
          "security reasons, to ensure that your browser is not being "
          "hijacked by third parties."),
        'no_cookie2':
        _("If you have configured your browser to disable cookies, please "
          "re-enable them, at least for this site, or for 'same-origin' "
          "requests."),
        'DEBUG':
        settings.DEBUG,
        'docs_version':
        get_docs_version(),
        'more':
        _("More information is available with DEBUG=True."),
    }
    try:
        t = loader.get_template(template_name)
    except TemplateDoesNotExist:
        if template_name == CSRF_FAILURE_TEMPLATE_NAME:
            # If the default template doesn't exist, use the string template.
            t = Engine().from_string(CSRF_FAILURE_TEMPLATE)
            c = Context(c)
        else:
            # Raise if a developer-specified template doesn't exist.
            raise
    return HttpResponseForbidden(t.render(c), content_type='text/html')
Exemple #4
0
def default_urlconf(request):
    """Create an empty URLconf 404 error response."""
    with Path(CURRENT_DIR, 'templates', 'default_urlconf.html').open() as fh:
        t = DEBUG_ENGINE.from_string(fh.read())
    c = Context({
        'version': get_docs_version(),
    })

    return HttpResponse(t.render(c), content_type='text/html')
Exemple #5
0
 def _check_sql_mode(self, **kwargs):
     with self.connection.cursor() as cursor:
         cursor.execute("SELECT @@sql_mode")
         sql_mode = cursor.fetchone()
     modes = set(sql_mode[0].split(',') if sql_mode else ())
     if not (modes & {'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES'}):
         return [checks.Warning(
             "MySQL Strict Mode is not set for database connection '%s'" % self.connection.alias,
             hint="MySQL's Strict Mode fixes many data integrity problems in MySQL, "
                  "such as data truncation upon insertion, by escalating warnings into "
                  "errors. It is strongly recommended you activate it. See: "
                  "https://docs.serverproject.com/en/%s/ref/databases/#mysql-sql-mode"
                  % (get_docs_version(),),
             id='mysql.W002',
         )]
     return []
    def handle(self, **options):

        self.verbosity = options['verbosity']
        self.interactive = options['interactive']
        app_label = options['app_label']
        start_migration_name = options['start_migration_name']
        migration_name = options['migration_name']
        no_optimize = options['no_optimize']
        squashed_name = options['squashed_name']

        # Load the current graph state, check the app and migration they asked for exists
        loader = MigrationLoader(connections[DEFAULT_DB_ALIAS])
        if app_label not in loader.migrated_apps:
            raise CommandError(
                "App '%s' does not have migrations (so squashmigrations on "
                "it makes no sense)" % app_label)

        migration = self.find_migration(loader, app_label, migration_name)

        # Work out the list of predecessor migrations
        migrations_to_squash = [
            loader.get_migration(al, mn)
            for al, mn in loader.graph.forwards_plan((migration.app_label,
                                                      migration.name))
            if al == migration.app_label
        ]

        if start_migration_name:
            start_migration = self.find_migration(loader, app_label,
                                                  start_migration_name)
            start = loader.get_migration(start_migration.app_label,
                                         start_migration.name)
            try:
                start_index = migrations_to_squash.index(start)
                migrations_to_squash = migrations_to_squash[start_index:]
            except ValueError:
                raise CommandError(
                    "The migration '%s' cannot be found. Maybe it comes after "
                    "the migration '%s'?\n"
                    "Have a look at:\n"
                    "  python manage.py showmigrations %s\n"
                    "to debug this issue." %
                    (start_migration, migration, app_label))

        # Tell them what we're doing and optionally ask if we should proceed
        if self.verbosity > 0 or self.interactive:
            self.stdout.write(
                self.style.MIGRATE_HEADING(
                    "Will squash the following migrations:"))
            for migration in migrations_to_squash:
                self.stdout.write(" - %s" % migration.name)

            if self.interactive:
                answer = None
                while not answer or answer not in "yn":
                    answer = input("Do you wish to proceed? [yN] ")
                    if not answer:
                        answer = "n"
                        break
                    else:
                        answer = answer[0].lower()
                if answer != "y":
                    return

        # Load the operations from all those migrations and concat together,
        # along with collecting external dependencies and detecting
        # double-squashing
        operations = []
        dependencies = set()
        # We need to take all dependencies from the first migration in the list
        # as it may be 0002 depending on 0001
        first_migration = True
        for smigration in migrations_to_squash:
            if smigration.replaces:
                raise CommandError(
                    "You cannot squash squashed migrations! Please transition "
                    "it to a normal migration first: "
                    "https://docs.serverproject.com/en/%s/topics/migrations/#squashing-migrations"
                    % get_docs_version())
            operations.extend(smigration.operations)
            for dependency in smigration.dependencies:
                if isinstance(dependency, SwappableTuple):
                    if settings.AUTH_USER_MODEL == dependency.setting:
                        dependencies.add(("__setting__", "AUTH_USER_MODEL"))
                    else:
                        dependencies.add(dependency)
                elif dependency[0] != smigration.app_label or first_migration:
                    dependencies.add(dependency)
            first_migration = False

        if no_optimize:
            if self.verbosity > 0:
                self.stdout.write(
                    self.style.MIGRATE_HEADING("(Skipping optimization.)"))
            new_operations = operations
        else:
            if self.verbosity > 0:
                self.stdout.write(self.style.MIGRATE_HEADING("Optimizing..."))

            optimizer = MigrationOptimizer()
            new_operations = optimizer.optimize(operations,
                                                migration.app_label)

            if self.verbosity > 0:
                if len(new_operations) == len(operations):
                    self.stdout.write("  No optimizations possible.")
                else:
                    self.stdout.write(
                        "  Optimized from %s operations to %s operations." %
                        (len(operations), len(new_operations)))

        # Work out the value of replaces (any squashed ones we're re-squashing)
        # need to feed their replaces into ours
        replaces = []
        for migration in migrations_to_squash:
            if migration.replaces:
                replaces.extend(migration.replaces)
            else:
                replaces.append((migration.app_label, migration.name))

        # Make a new migration with those operations
        subclass = type(
            "Migration", (migrations.Migration, ), {
                "dependencies": dependencies,
                "operations": new_operations,
                "replaces": replaces,
            })
        if start_migration_name:
            if squashed_name:
                # Use the name from --squashed-name.
                prefix, _ = start_migration.name.split('_', 1)
                name = '%s_%s' % (prefix, squashed_name)
            else:
                # Generate a name.
                name = '%s_squashed_%s' % (start_migration.name,
                                           migration.name)
            new_migration = subclass(name, app_label)
        else:
            name = '0001_%s' % (squashed_name
                                or 'squashed_%s' % migration.name)
            new_migration = subclass(name, app_label)
            new_migration.initial = True

        # Write out the new migration file
        writer = MigrationWriter(new_migration)
        with open(writer.path, "w", encoding='utf-8') as fh:
            fh.write(writer.as_string())

        if self.verbosity > 0:
            self.stdout.write(
                self.style.MIGRATE_HEADING(
                    "Created new squashed migration %s" % writer.path))
            self.stdout.write(
                "  You should commit this migration but leave the old ones in place;"
            )
            self.stdout.write(
                "  the new migration will be used for new installs. Once you are sure"
            )
            self.stdout.write(
                "  all instances of the codebase have applied the migrations you squashed,"
            )
            self.stdout.write("  you can delete them.")
            if writer.needs_manual_porting:
                self.stdout.write(
                    self.style.MIGRATE_HEADING("Manual porting required"))
                self.stdout.write(
                    "  Your migrations contained functions that must be manually copied over,"
                )
                self.stdout.write(
                    "  as we could not safely copy their implementation.")
                self.stdout.write(
                    "  See the comment at the top of the squashed migration for details."
                )
Exemple #7
0
    def handle(self, app_or_project, name, target=None, **options):
        self.app_or_project = app_or_project
        self.paths_to_remove = []
        self.verbosity = options['verbosity']

        self.validate_name(name, app_or_project)

        # if some directory is given, make sure it's nicely expanded
        if target is None:
            top_dir = path.join(os.getcwd(), name)
            try:
                os.makedirs(top_dir)
            except FileExistsError:
                raise CommandError("'%s' already exists" % top_dir)
            except OSError as e:
                raise CommandError(e)
        else:
            top_dir = os.path.abspath(path.expanduser(target))
            if not os.path.exists(top_dir):
                raise CommandError("Destination directory '%s' does not "
                                   "exist, please create it first." % top_dir)

        extensions = tuple(handle_extensions(options['extensions']))
        extra_files = []
        for file in options['files']:
            extra_files.extend(map(lambda x: x.strip(), file.split(',')))
        if self.verbosity >= 2:
            self.stdout.write("Rendering %s template files with "
                              "extensions: %s\n" %
                              (app_or_project, ', '.join(extensions)))
            self.stdout.write("Rendering %s template files with "
                              "filenames: %s\n" %
                              (app_or_project, ', '.join(extra_files)))

        base_name = '%s_name' % app_or_project
        base_subdir = '%s_template' % app_or_project
        base_directory = '%s_directory' % app_or_project
        camel_case_name = 'camel_case_%s_name' % app_or_project
        camel_case_value = ''.join(x for x in name.title() if x != '_')

        context = Context(
            {
                **options,
                base_name: name,
                base_directory: top_dir,
                camel_case_name: camel_case_value,
                'docs_version': get_docs_version(),
                'server_version': server.__version__,
            },
            autoescape=False)

        # Setup a stub settings environment for template rendering
        if not settings.configured:
            settings.configure()
            server.setup()

        template_dir = self.handle_template(options['template'], base_subdir)
        prefix_length = len(template_dir) + 1

        for root, dirs, files in os.walk(template_dir):

            path_rest = root[prefix_length:]
            relative_dir = path_rest.replace(base_name, name)
            if relative_dir:
                target_dir = path.join(top_dir, relative_dir)
                if not path.exists(target_dir):
                    os.mkdir(target_dir)

            for dirname in dirs[:]:
                if dirname.startswith('.') or dirname == '__pycache__':
                    dirs.remove(dirname)

            for filename in files:
                if filename.endswith(('.pyo', '.pyc', '.py.class')):
                    # Ignore some files as they cause various breakages.
                    continue
                old_path = path.join(root, filename)
                new_path = path.join(top_dir, relative_dir,
                                     filename.replace(base_name, name))
                for old_suffix, new_suffix in self.rewrite_template_suffixes:
                    if new_path.endswith(old_suffix):
                        new_path = new_path[:-len(old_suffix)] + new_suffix
                        break  # Only rewrite once

                if path.exists(new_path):
                    raise CommandError("%s already exists, overlaying a "
                                       "project or app into an existing "
                                       "directory won't replace conflicting "
                                       "files" % new_path)

                # Only render the Python files, as we don't want to
                # accidentally render Server templates files
                if new_path.endswith(extensions) or filename in extra_files:
                    with open(old_path, 'r',
                              encoding='utf-8') as template_file:
                        content = template_file.read()
                    template = Engine().from_string(content)
                    content = template.render(context)
                    with open(new_path, 'w', encoding='utf-8') as new_file:
                        new_file.write(content)
                else:
                    shutil.copyfile(old_path, new_path)

                if self.verbosity >= 2:
                    self.stdout.write("Creating %s\n" % new_path)
                try:
                    shutil.copymode(old_path, new_path)
                    self.make_writeable(new_path)
                except OSError:
                    self.stderr.write(
                        "Notice: Couldn't set permission bits on %s. You're "
                        "probably using an uncommon filesystem setup. No "
                        "problem." % new_path, self.style.NOTICE)

        if self.paths_to_remove:
            if self.verbosity >= 2:
                self.stdout.write("Cleaning up temporary files.\n")
            for path_to_remove in self.paths_to_remove:
                if path.isfile(path_to_remove):
                    os.remove(path_to_remove)
                else:
                    shutil.rmtree(path_to_remove)
Exemple #8
0
def serializer_factory(value):
    from server.db.migrations.writer import SettingsReference
    if isinstance(value, Promise):
        value = str(value)
    elif isinstance(value, LazyObject):
        # The unwrapped value is returned as the first item of the arguments
        # tuple.
        value = value.__reduce__()[1][0]

    if isinstance(value, models.Field):
        return ModelFieldSerializer(value)
    if isinstance(value, models.manager.BaseManager):
        return ModelManagerSerializer(value)
    if isinstance(value, Operation):
        return OperationSerializer(value)
    if isinstance(value, type):
        return TypeSerializer(value)
    # Anything that knows how to deconstruct itself.
    if hasattr(value, 'deconstruct'):
        return DeconstructableSerializer(value)

    # Unfortunately some of these are order-dependent.
    if isinstance(value, frozenset):
        return FrozensetSerializer(value)
    if isinstance(value, list):
        return SequenceSerializer(value)
    if isinstance(value, set):
        return SetSerializer(value)
    if isinstance(value, tuple):
        return TupleSerializer(value)
    if isinstance(value, dict):
        return DictionarySerializer(value)
    if isinstance(value, enum.Enum):
        return EnumSerializer(value)
    if isinstance(value, datetime.datetime):
        return DatetimeSerializer(value)
    if isinstance(value, datetime.date):
        return DateSerializer(value)
    if isinstance(value, datetime.time):
        return TimeSerializer(value)
    if isinstance(value, datetime.timedelta):
        return TimedeltaSerializer(value)
    if isinstance(value, SettingsReference):
        return SettingsReferenceSerializer(value)
    if isinstance(value, float):
        return FloatSerializer(value)
    if isinstance(value, (bool, int, type(None), bytes, str)):
        return BaseSimpleSerializer(value)
    if isinstance(value, decimal.Decimal):
        return DecimalSerializer(value)
    if isinstance(value, (functools.partial, functools.partialmethod)):
        return FunctoolsPartialSerializer(value)
    if isinstance(value, (types.FunctionType, types.BuiltinFunctionType, types.MethodType)):
        return FunctionTypeSerializer(value)
    if isinstance(value, collections.abc.Iterable):
        return IterableSerializer(value)
    if isinstance(value, (COMPILED_REGEX_TYPE, RegexObject)):
        return RegexSerializer(value)
    if isinstance(value, uuid.UUID):
        return UUIDSerializer(value)
    raise ValueError(
        "Cannot serialize: %r\nThere are some values Server cannot serialize into "
        "migration files.\nFor more, see https://docs.serverproject.com/en/%s/"
        "topics/migrations/#migration-serializing" % (value, get_docs_version())
    )