Beispiel #1
0
class PreferencesForm(forms.Form):
    redirect_to = forms.CharField(required=False, widget=forms.HiddenInput)
    groups = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,
                                       required=False)
    syntax_highlighting = forms.BooleanField(
        required=False,
        label=_("Enable syntax highlighting in the diff viewer"))
    profile_private = forms.BooleanField(
        required=False,
        label=_("Keep your user profile private"))
    open_an_issue = forms.BooleanField(
        required=False,
        label=_("Always open an issue when comment box opens"))
    first_name = forms.CharField(required=False)
    last_name = forms.CharField(required=False)
    email = forms.EmailField()
    password1 = forms.CharField(required=False, widget=widgets.PasswordInput())
    password2 = forms.CharField(required=False, widget=widgets.PasswordInput())
    timezone = TimeZoneField(
        label=_("Time Zone"),
        required=True,
        help_text=_("The time zone used for this account."))

    def __init__(self, user, *args, **kwargs):
        from reviewboard.accounts.backends import get_auth_backends

        super(forms.Form, self).__init__(*args, **kwargs)

        auth_backends = get_auth_backends()
        choices = []

        for g in Group.objects.accessible(user=user).order_by('display_name'):
            choices.append((g.id, g.display_name))

        for site in user.local_site.all().order_by('name'):
            for g in Group.objects.accessible(
                    user=user, local_site=site).order_by('display_name'):
                display_name = '%s / %s' % (g.local_site.name, g.display_name)
                choices.append((g.id, display_name))

        self.fields['groups'].choices = choices
        self.fields['email'].required = auth_backends[0].supports_change_email

    def save(self, user):
        from reviewboard.accounts.backends import get_auth_backends

        auth_backends = get_auth_backends()
        primary_backend = auth_backends[0]

        password = self.cleaned_data['password1']

        if primary_backend.supports_change_password and password:
            primary_backend.update_password(user, password)

        if primary_backend.supports_change_name:
            user.first_name = self.cleaned_data['first_name']
            user.last_name = self.cleaned_data['last_name']
            primary_backend.update_name(user)

        if primary_backend.supports_change_email:
            user.email = self.cleaned_data['email']
            primary_backend.update_email(user)

        user.review_groups = self.cleaned_data['groups']
        user.save()

        profile = user.get_profile()
        profile.first_time_setup_done = True
        profile.syntax_highlighting = self.cleaned_data['syntax_highlighting']
        profile.is_private = self.cleaned_data['profile_private']
        profile.open_an_issue = self.cleaned_data['open_an_issue']
        profile.timezone = self.cleaned_data['timezone']
        profile.save()

    def clean_password2(self):
        p1 = self.cleaned_data['password1']
        p2 = self.cleaned_data['password2']
        if p1 != p2:
            raise forms.ValidationError('passwords do not match')
        return p2
Beispiel #2
0
class GeneralSettingsForm(SiteSettingsForm):
    """General settings for Review Board."""
    CACHE_TYPE_CHOICES = (
        ('memcached', _('Memcached')),
        ('file', _('File cache')),
    )

    CACHE_BACKENDS_MAP = {
        'file': 'django.core.cache.backends.filebased.FileBasedCache',
        'memcached': 'django.core.cache.backends.memcached.CacheClass',
        'locmem': 'django.core.cache.backends.locmem.LocMemCache',
    }

    CACHE_TYPES_MAP = {
        'django.core.cache.backends.filebased.FileBasedCache': 'file',
        'django.core.cache.backends.memcached.CacheClass': 'memcached',
        'django.core.cache.backends.locmem.LocMemCache': 'locmem',
    }

    CACHE_LOCATION_FIELD_MAP = {
        'file': 'cache_path',
        'memcached': 'cache_host',
    }

    server = forms.CharField(
        label=_("Server"),
        help_text=_("The URL of this Review Board server. This should not "
                    "contain the subdirectory Review Board is installed in."),
        widget=forms.TextInput(attrs={'size': '30'}))

    site_media_url = forms.CharField(
        label=_("Media URL"),
        help_text=_("The URL to the media files. Leave blank to use the "
                    "default media path on this server."),
        required=False,
        widget=forms.TextInput(attrs={'size': '30'}))

    site_admin_name = forms.CharField(
        label=_("Administrator Name"),
        required=True,
        widget=forms.TextInput(attrs={'size': '30'}))
    site_admin_email = forms.EmailField(
        label=_("Administrator E-Mail"),
        required=True,
        widget=forms.TextInput(attrs={'size': '30'}))

    locale_timezone = TimeZoneField(
        label=_("Time Zone"),
        required=True,
        help_text=_("The time zone used for all dates on this server."))

    search_enable = forms.BooleanField(
        label=_("Enable search"),
        help_text=_("Provides a search field for quickly searching through "
                    "review requests."),
        required=False)

    search_index_file = forms.CharField(
        label=_("Search index directory"),
        help_text=_("The directory that search index data should be stored "
                    "in."),
        required=False,
        widget=forms.TextInput(attrs={'size': '50'}))

    cache_type = forms.ChoiceField(
        label=_("Cache Backend"),
        choices=CACHE_TYPE_CHOICES,
        help_text=_('The type of server-side caching to use.'),
        required=True)

    cache_path = forms.CharField(
        label=_("Cache Path"),
        help_text=_('The file location for the cache.'),
        required=True,
        widget=forms.TextInput(attrs={'size': '50'}))

    cache_host = forms.CharField(
        label=_("Cache Hosts"),
        help_text=_('The host or hosts used for the cache, in hostname:port '
                    'form. Multiple hosts can be specified by separating '
                    'them with a semicolon (;).'),
        required=True,
        widget=forms.TextInput(attrs={'size': '50'}))

    def load(self):
        domain_method = self.siteconfig.get("site_domain_method")
        site = Site.objects.get_current()

        can_enable_search, reason = get_can_enable_search()
        if not can_enable_search:
            self.disabled_fields['search_enable'] = True
            self.disabled_fields['search_index_file'] = True
            self.disabled_reasons['search_enable'] = reason

        # Load the rest of the settings from the form.
        super(GeneralSettingsForm, self).load()

        # Load the cache settings.
        cache_backend = normalize_cache_backend(
            self.siteconfig.get('cache_backend'))

        cache_type = self.CACHE_TYPES_MAP.get(cache_backend['BACKEND'],
                                              'custom')
        self.fields['cache_type'].initial = cache_type

        if settings.DEBUG:
            self.fields['cache_type'].choices += (('locmem',
                                                   _('Local memory cache')), )

        if cache_type == 'custom':
            self.fields['cache_type'].choices += (('custom', _('Custom')), )
            cache_locations = []
        elif cache_type != 'locmem':
            cache_locations = cache_backend['LOCATION']

            if not isinstance(cache_locations, list):
                cache_locations = [cache_locations]

            location_field = self.CACHE_LOCATION_FIELD_MAP[cache_type]
            self.fields[location_field].initial = ';'.join(cache_locations)

        # This must come after we've loaded the general settings.
        self.fields['server'].initial = "%s://%s" % (domain_method,
                                                     site.domain)

    def save(self):
        server = self.cleaned_data['server']

        if "://" not in server:
            # urlparse doesn't properly handle URLs without a scheme. It
            # believes the domain is actually the path. So we apply a prefix.
            server = "http://" + server

        url_parts = urlparse.urlparse(server)
        domain_method = url_parts[0]
        domain_name = url_parts[1]

        if domain_name.endswith("/"):
            domain_name = domain_name[:-1]

        site = Site.objects.get_current()
        site.domain = domain_name
        site.save()

        self.siteconfig.set("site_domain_method", domain_method)

        cache_type = self.cleaned_data['cache_type']

        if cache_type != 'custom':
            if cache_type == 'locmem':
                # We want to specify a "reviewboard" location to keep items
                # separate from those in other caches.
                location = 'reviewboard'
            else:
                location_field = self.CACHE_LOCATION_FIELD_MAP[cache_type]
                location = self.cleaned_data[location_field]

                if cache_type == 'memcached':
                    # memcached allows a list of servers, rather than just a
                    # string representing one.
                    location = location.split(';')

            self.siteconfig.set(
                'cache_backend', {
                    DEFAULT_CACHE_ALIAS: {
                        'BACKEND': self.CACHE_BACKENDS_MAP[cache_type],
                        'LOCATION': location,
                    }
                })

        super(GeneralSettingsForm, self).save()

        # Reload any important changes into the Django settings.
        load_site_config()

    def full_clean(self):
        cache_type = self['cache_type'].data or self['cache_type'].initial

        for iter_cache_type, field in self.CACHE_LOCATION_FIELD_MAP.iteritems(
        ):
            self.fields[field].required = (cache_type == iter_cache_type)

        return super(GeneralSettingsForm, self).full_clean()

    def clean_cache_host(self):
        cache_host = self.cleaned_data['cache_host'].strip()

        if self.fields['cache_host'].required and not cache_host:
            raise forms.ValidationError(
                _('A valid cache host must be provided.'))

        return cache_host

    def clean_cache_path(self):
        cache_path = self.cleaned_data['cache_path'].strip()

        if self.fields['cache_path'].required and not cache_path:
            raise forms.ValidationError(
                _('A valid cache path must be provided.'))

        return cache_path

    def clean_search_index_file(self):
        """Validates that the specified index file is valid."""
        index_file = self.cleaned_data['search_index_file'].strip()

        if index_file:
            if not os.path.isabs(index_file):
                raise forms.ValidationError(
                    _("The search index path must be absolute."))

            if (os.path.exists(index_file)
                    and not os.access(index_file, os.W_OK)):
                raise forms.ValidationError(
                    _('The search index path is not writable. Make sure the '
                      'web server has write access to it and its parent '
                      'directory.'))

        return index_file

    class Meta:
        title = _("General Settings")
        save_blacklist = ('server', 'cache_type', 'cache_host', 'cache_path')

        fieldsets = (
            {
                'classes': ('wide', ),
                'title':
                _("Site Settings"),
                'fields': ('server', 'site_media_url', 'site_admin_name',
                           'site_admin_email', 'locale_timezone'),
            },
            {
                'classes': ('wide', ),
                'title': _('Cache Settings'),
                'fields': ('cache_type', 'cache_path', 'cache_host'),
            },
            {
                'classes': ('wide', ),
                'title': _("Search"),
                'fields': ('search_enable', 'search_index_file'),
            },
        )
Beispiel #3
0
class GeneralSettingsForm(SiteSettingsForm):
    """General settings for Review Board."""
    server = forms.CharField(
        label=_("Server"),
        help_text=_("The URL of this Review Board server. This should not "
                    "contain the subdirectory Review Board is installed in."),
        widget=forms.TextInput(attrs={'size': '30'}))

    site_media_url = forms.CharField(
        label=_("Media URL"),
        help_text=_("The URL to the media files. Leave blank to use the "
                    "default media path on this server."),
        required=False,
        widget=forms.TextInput(attrs={'size': '30'}))

    site_admin_name = forms.CharField(
        label=_("Administrator Name"),
        required=True,
        widget=forms.TextInput(attrs={'size': '30'}))
    site_admin_email = forms.EmailField(
        label=_("Administrator E-Mail"),
        required=True,
        widget=forms.TextInput(attrs={'size': '30'}))

    locale_timezone = TimeZoneField(
        label=_("Time Zone"),
        required=True,
        help_text=_("The time zone used for all dates on this server."))

    search_enable = forms.BooleanField(
        label=_("Enable search"),
        help_text=_("Provides a search field for quickly searching through "
                    "review requests."),
        required=False)

    search_index_file = forms.CharField(
        label=_("Search index directory"),
        help_text=_("The directory that search index data should be stored "
                    "in."),
        required=False,
        widget=forms.TextInput(attrs={'size': '50'}))

    cache_backend = forms.CharField(
        label=_("Cache Backend"),
        help_text=_("The path to the cache backend."
                    "Example: 'memcached://127.0.0.1:11211/'"),
        required=False,
        widget=forms.TextInput(attrs={'size': '50'}))

    def load(self):
        domain_method = self.siteconfig.get("site_domain_method")
        site = Site.objects.get_current()

        can_enable_search, reason = get_can_enable_search()
        if not can_enable_search:
            self.disabled_fields['search_enable'] = True
            self.disabled_fields['search_index_file'] = True
            self.disabled_reasons['search_enable'] = reason

        super(GeneralSettingsForm, self).load()

        # This must come after we've loaded the general settings.
        self.fields['server'].initial = "%s://%s" % (domain_method,
                                                     site.domain)

    def save(self):
        server = self.cleaned_data['server']

        if "://" not in server:
            # urlparse doesn't properly handle URLs without a scheme. It
            # believes the domain is actually the path. So we apply a prefix.
            server = "http://" + server

        url_parts = urlparse.urlparse(server)
        domain_method = url_parts[0]
        domain_name = url_parts[1]

        if domain_name.endswith("/"):
            domain_name = domain_name[:-1]

        site = Site.objects.get_current()
        site.domain = domain_name
        site.save()

        self.siteconfig.set("site_domain_method", domain_method)

        super(GeneralSettingsForm, self).save()

        # Reload any important changes into the Django settings.
        load_site_config()

    def clean_cache_backend(self):
        """Validates that the specified cache backend is parseable by Django."""
        backend = self.cleaned_data['cache_backend'].strip()
        if backend:
            try:
                parse_backend_uri(backend)
            except InvalidCacheBackendError, e:
                raise forms.ValidationError(e)

        return backend