123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- # -*- Mode: perl; indent-tabs-mode: nil -*-
- #
- # The contents of this file are subject to the Mozilla Public
- # License Version 1.1 (the "License"); you may not use this file
- # except in compliance with the License. You may obtain a copy of
- # the License at http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS
- # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- # implied. See the License for the specific language governing
- # rights and limitations under the License.
- #
- # The Original Code is the Bugzilla Bug Tracking System.
- #
- # Contributor(s): Shane H. W. Travis <travis@sedsystems.ca>
- # Max Kanat-Alexander <mkanat@bugzilla.org>
- # Marc Schumann <wurblzap@gmail.com>
- # Frédéric Buclin <LpSolit@gmail.com>
- package Bugzilla::User::Setting;
- use strict;
- use base qw(Exporter);
- # Module stuff
- @Bugzilla::User::Setting::EXPORT = qw(get_all_settings get_defaults
- add_setting);
- use Bugzilla::Error;
- use Bugzilla::Util qw(trick_taint get_text);
- ###############################
- ### Module Initialization ###
- ###############################
- sub new {
- my $invocant = shift;
- my $setting_name = shift;
- my $user_id = shift;
- my $class = ref($invocant) || $invocant;
- my $subclass = '';
- # Create a ref to an empty hash and bless it
- my $self = {};
- my $dbh = Bugzilla->dbh;
- # Confirm that the $setting_name is properly formed;
- # if not, throw a code error.
- #
- # NOTE: due to the way that setting names are used in templates,
- # they must conform to to the limitations set for HTML NAMEs and IDs.
- #
- if ( !($setting_name =~ /^[a-zA-Z][-.:\w]*$/) ) {
- ThrowCodeError("setting_name_invalid", { name => $setting_name });
- }
- # If there were only two parameters passed in, then we need
- # to retrieve the information for this setting ourselves.
- if (scalar @_ == 0) {
- my ($default, $is_enabled, $value);
- ($default, $is_enabled, $value, $subclass) =
- $dbh->selectrow_array(
- q{SELECT default_value, is_enabled, setting_value, subclass
- FROM setting
- LEFT JOIN profile_setting
- ON setting.name = profile_setting.setting_name
- WHERE name = ?
- AND profile_setting.user_id = ?},
- undef,
- $setting_name, $user_id);
- # if not defined, then grab the default value
- if (! defined $value) {
- ($default, $is_enabled, $subclass) =
- $dbh->selectrow_array(
- q{SELECT default_value, is_enabled, subclass
- FROM setting
- WHERE name = ?},
- undef,
- $setting_name);
- }
- $self->{'is_enabled'} = $is_enabled;
- $self->{'default_value'} = $default;
- # IF the setting is enabled, AND the user has chosen a setting
- # THEN return that value
- # ELSE return the site default, and note that it is the default.
- if ( ($is_enabled) && (defined $value) ) {
- $self->{'value'} = $value;
- } else {
- $self->{'value'} = $default;
- $self->{'isdefault'} = 1;
- }
- }
- else {
- # If the values were passed in, simply assign them and return.
- $self->{'is_enabled'} = shift;
- $self->{'default_value'} = shift;
- $self->{'value'} = shift;
- $self->{'is_default'} = shift;
- $subclass = shift;
- }
- if ($subclass) {
- eval('require ' . $class . '::' . $subclass);
- $@ && ThrowCodeError('setting_subclass_invalid',
- {'subclass' => $subclass});
- $class = $class . '::' . $subclass;
- }
- bless($self, $class);
- $self->{'_setting_name'} = $setting_name;
- $self->{'_user_id'} = $user_id;
- return $self;
- }
- ###############################
- ### Subroutine Definitions ###
- ###############################
- sub add_setting {
- my ($name, $values, $default_value, $subclass, $force_check) = @_;
- my $dbh = Bugzilla->dbh;
- my $exists = _setting_exists($name);
- return if ($exists && !$force_check);
- ($name && $default_value)
- || ThrowCodeError("setting_info_invalid");
- if ($exists) {
- # If this setting exists, we delete it and regenerate it.
- $dbh->do('DELETE FROM setting_value WHERE name = ?', undef, $name);
- $dbh->do('DELETE FROM setting WHERE name = ?', undef, $name);
- # Remove obsolete user preferences for this setting.
- if (defined $values && scalar(@$values)) {
- my $list = join(', ', map {$dbh->quote($_)} @$values);
- $dbh->do("DELETE FROM profile_setting
- WHERE setting_name = ? AND setting_value NOT IN ($list)",
- undef, $name);
- }
- }
- else {
- print get_text('install_setting_new', { name => $name }) . "\n";
- }
- $dbh->do(q{INSERT INTO setting (name, default_value, is_enabled, subclass)
- VALUES (?, ?, 1, ?)},
- undef, ($name, $default_value, $subclass));
- my $sth = $dbh->prepare(q{INSERT INTO setting_value (name, value, sortindex)
- VALUES (?, ?, ?)});
- my $sortindex = 5;
- foreach my $key (@$values){
- $sth->execute($name, $key, $sortindex);
- $sortindex += 5;
- }
- }
- sub get_all_settings {
- my ($user_id) = @_;
- my $settings = get_defaults($user_id); # first get the defaults
- my $dbh = Bugzilla->dbh;
- my $sth = $dbh->prepare(
- q{SELECT name, default_value, is_enabled, setting_value, subclass
- FROM setting
- LEFT JOIN profile_setting
- ON setting.name = profile_setting.setting_name
- WHERE profile_setting.user_id = ?
- ORDER BY name});
- $sth->execute($user_id);
- while (my ($name, $default_value, $is_enabled, $value, $subclass)
- = $sth->fetchrow_array())
- {
- my $is_default;
- if ( ($is_enabled) && (defined $value) ) {
- $is_default = 0;
- } else {
- $value = $default_value;
- $is_default = 1;
- }
- $settings->{$name} = new Bugzilla::User::Setting(
- $name, $user_id, $is_enabled,
- $default_value, $value, $is_default, $subclass);
- }
- return $settings;
- }
- sub get_defaults {
- my ($user_id) = @_;
- my $dbh = Bugzilla->dbh;
- my $default_settings = {};
- $user_id ||= 0;
- my $sth = $dbh->prepare(q{SELECT name, default_value, is_enabled, subclass
- FROM setting
- ORDER BY name});
- $sth->execute();
- while (my ($name, $default_value, $is_enabled, $subclass)
- = $sth->fetchrow_array())
- {
- $default_settings->{$name} = new Bugzilla::User::Setting(
- $name, $user_id, $is_enabled, $default_value, $default_value, 1,
- $subclass);
- }
- return $default_settings;
- }
- sub set_default {
- my ($setting_name, $default_value, $is_enabled) = @_;
- my $dbh = Bugzilla->dbh;
- my $sth = $dbh->prepare(q{UPDATE setting
- SET default_value = ?, is_enabled = ?
- WHERE name = ?});
- $sth->execute($default_value, $is_enabled, $setting_name);
- }
- sub _setting_exists {
- my ($setting_name) = @_;
- my $dbh = Bugzilla->dbh;
- return $dbh->selectrow_arrayref(
- "SELECT 1 FROM setting WHERE name = ?", undef, $setting_name) || 0;
- }
- sub legal_values {
- my ($self) = @_;
- return $self->{'legal_values'} if defined $self->{'legal_values'};
- my $dbh = Bugzilla->dbh;
- $self->{'legal_values'} = $dbh->selectcol_arrayref(
- q{SELECT value
- FROM setting_value
- WHERE name = ?
- ORDER BY sortindex},
- undef, $self->{'_setting_name'});
- return $self->{'legal_values'};
- }
- sub validate_value {
- my $self = shift;
- if (grep(/^$_[0]$/, @{$self->legal_values()})) {
- trick_taint($_[0]);
- }
- else {
- ThrowCodeError('setting_value_invalid',
- {'name' => $self->{'_setting_name'},
- 'value' => $_[0]});
- }
- }
- sub reset_to_default {
- my ($self) = @_;
- my $dbh = Bugzilla->dbh;
- my $sth = $dbh->do(q{ DELETE
- FROM profile_setting
- WHERE setting_name = ?
- AND user_id = ?},
- undef, $self->{'_setting_name'}, $self->{'_user_id'});
- $self->{'value'} = $self->{'default_value'};
- $self->{'is_default'} = 1;
- }
- sub set {
- my ($self, $value) = @_;
- my $dbh = Bugzilla->dbh;
- my $query;
- if ($self->{'is_default'}) {
- $query = q{INSERT INTO profile_setting
- (setting_value, setting_name, user_id)
- VALUES (?,?,?)};
- } else {
- $query = q{UPDATE profile_setting
- SET setting_value = ?
- WHERE setting_name = ?
- AND user_id = ?};
- }
- $dbh->do($query, undef, $value, $self->{'_setting_name'}, $self->{'_user_id'});
- $self->{'value'} = $value;
- $self->{'is_default'} = 0;
- }
- 1;
- __END__
- =head1 NAME
- Bugzilla::User::Setting - Object for a user preference setting
- =head1 SYNOPSIS
- Setting.pm creates a setting object, which is a hash containing the user
- preference information for a single preference for a single user. These
- are usually accessed through the "settings" object of a user, and not
- directly.
- =head1 DESCRIPTION
- use Bugzilla::User::Setting;
- my $settings;
- $settings->{$setting_name} = new Bugzilla::User::Setting(
- $setting_name, $user_id);
- OR
- $settings->{$setting_name} = new Bugzilla::User::Setting(
- $setting_name, $user_id, $is_enabled,
- $default_value, $value, $is_default);
- =head1 CLASS FUNCTIONS
- =over 4
- =item C<add_setting($name, \@values, $default_value, $subclass, $force_check)>
- Description: Checks for the existence of a setting, and adds it
- to the database if it does not yet exist.
- Params: C<$name> - string - the name of the new setting
- C<$values> - arrayref - contains the new choices
- for the new Setting.
- C<$default_value> - string - the site default
- C<$subclass> - string - name of the module returning
- the list of valid values. This means legal values are
- not stored in the DB.
- C<$force_check> - boolean - when true, the existing setting
- and all its values are deleted and replaced by new data.
- Returns: a pointer to a hash of settings
- =item C<get_all_settings($user_id)>
- Description: Provides the user's choices for each setting in the
- system; if the user has made no choice, uses the site
- default instead.
- Params: C<$user_id> - integer - the user id.
- Returns: a pointer to a hash of settings
- =item C<get_defaults($user_id)>
- Description: When a user is not logged in, they must use the site
- defaults for every settings; this subroutine provides them.
- Params: C<$user_id> (optional) - integer - the user id. Note that
- this optional parameter is mainly for internal use only.
- Returns: A pointer to a hash of settings. If $user_id was passed, set
- the user_id value for each setting.
- =item C<set_default($setting_name, $default_value, $is_enabled)>
- Description: Sets the global default for a given setting. Also sets
- whether users are allowed to choose their own value for
- this setting, or if they must use the global default.
- Params: C<$setting_name> - string - the name of the setting
- C<$default_value> - string - the new default value for this setting
- C<$is_enabled> - boolean - if false, all users must use the global default
- Returns: nothing
- =begin private
- =item C<_setting_exists>
- Description: Determines if a given setting exists in the database.
- Params: C<$setting_name> - string - the setting name
- Returns: boolean - true if the setting already exists in the DB.
- =back
- =end private
- =head1 METHODS
- =over 4
- =item C<legal_values($setting_name)>
- Description: Returns all legal values for this setting
- Params: none
- Returns: A reference to an array containing all legal values
- =item C<validate_value>
- Description: Determines whether a value is valid for the setting
- by checking against the list of legal values.
- Untaints the parameter if the value is indeed valid,
- and throws a setting_value_invalid code error if not.
- Params: An lvalue containing a candidate for a setting value
- Returns: nothing
- =item C<reset_to_default>
- Description: If a user chooses to use the global default for a given
- setting, their saved entry is removed from the database via
- this subroutine.
- Params: none
- Returns: nothing
- =item C<set($value)>
- Description: If a user chooses to use their own value rather than the
- global value for a given setting, OR changes their value for
- a given setting, this subroutine is called to insert or
- update the database as appropriate.
- Params: C<$value> - string - the new value for this setting for this user.
- Returns: nothing
- =back
|