rfe: User Profile Privacy Settings (#507) - users now have granular control of whether or not their profile fields are viewable - admin settings still apply

This commit is contained in:
Frank Dillon 2008-11-19 05:18:58 +00:00
parent 2945189adb
commit 6eff997f81
8 changed files with 266 additions and 46 deletions

View file

@ -10,6 +10,7 @@
- New Friends Account module added providing a better interface into WebGUI's friends system
- rfe: Event hover detail exclusions (#8761)
- rfe: Database Link test (#513)
- rfe: User Profile Privacy Settings (#507) - users now have granular control of whether or not their profile fields are viewable - admin settings still apply
- The Display Account and My Purchases interfaces have been added to the new Account system
- Added a new macro which returns the self deactivation link if the setting is enabled.
- Added a new macro which returns the back to site link

View file

@ -24,6 +24,7 @@ use WebGUI::Asset::Wobject::Survey;
use WebGUI::Asset::Wobject::Survey::SurveyJSON;
use WebGUI::Asset::Wobject::Survey::ResponseJSON;
use WebGUI::ProfileField;
use JSON;
my $toVersion = '7.6.4';
my $quiet; # this line required
@ -37,9 +38,48 @@ addPosMode($session);
fixFriendsGroups( $session );
upgradeAccount( $session );
removeProcessRecurringPaymentsFromConfig( $session );
addExtendedProfilePrivileges( $session );
addStorageUrlMacro( $session );
finish($session); # this line required
#----------------------------------------------------------------------------
sub addExtendedProfilePrivileges {
my $session = shift;
print qq{\tExtending User Profile Privileges..} if !$quiet;
my $userProfDesc = $session->db->buildHashRef('describe userProfileData');
if(grep { $_ =~ /^wg_privacySettings/ } keys %{$userProfDesc}) {
$session->db->write("alter table userProfileData drop column wg_privacySettings");
}
$session->db->write("alter table userProfileData add wg_privacySettings longtext");
my $fields = WebGUI::ProfileField->getFields($session);
my $users = $session->db->buildArrayRef("select userId from users");
foreach my $userId (@{$users}) {
my $hash = {};
foreach my $field (@{$fields}) {
if($field->getId eq "publicEmail") {
my $u = WebGUI::User->new($session,$userId);
$hash->{$field->getId} = $u->profileField("publicEmail") ? "all" : "none";
next;
}
$hash->{$field->getId} = $field->isViewable ? "all" : "none";
}
my $json = JSON->new->encode($hash);
$session->db->write("update userProfileData set wg_privacySettings=? where userId=?",[$json,$userId]);
}
#Delete the public email field
my $publicEmail = WebGUI::ProfileField->new($session,"publicEmail");
if(defined $publicEmail) {
$publicEmail->delete;
}
print qq{Finished\n} if !$quiet;
}
#----------------------------------------------------------------------------
sub addPosMode {
@ -447,7 +487,6 @@ sub upgradeAccount {
$setting->add("shopStyleTemplateId",""); #Use the userStyle by default
$setting->add("shopLayoutTemplateId","aUDsJ-vB9RgP-AYvPOy8FQ");
#Add inbox changes
$session->db->write(q{
create table inbox_messageState (

View file

@ -353,37 +353,50 @@ sub www_edit {
#Initialize the category template loop which gets filled inside the loop
$var->{'profile_category_loop'} = [];
#Cache the privacy settings
my $privacySettingsHash = WebGUI::ProfileField->getPrivacyOptions($session);
#Get the editable categories
my $categories = WebGUI::ProfileCategory->getCategories($session, { editable => 1 } );
foreach my $category (@{ $categories } ) {
my @fields = ();
use Data::Dumper;
foreach my $field (@{ $category->getFields( { editable => 1 } ) }) {
my $fieldId = $field->getId;
my $fieldLabel = $field->getLabel;
my $fieldForm = $field->formField({ extras=>$self->getExtrasStyle($field,\@errorFields,$user->profileField($fieldId)) });
my $fieldSubtext = $field->isRequired ? "*" : undef;
my $fieldExtras = $field->getExtras;
my $fieldPrivacy = WebGUI::Form::radoList($session,{
my $fieldId = $field->getId;
my $fieldLabel = $field->getLabel;
my $fieldForm = $field->formField({ extras=>$self->getExtrasStyle($field,\@errorFields,$user->profileField($fieldId)) });
my $fieldRequired = $field->isRequired;
my $fieldExtras = $field->getExtras;
my $fieldViewable = $field->isViewable;
my $rawPrivacySetting = $user->getProfileFieldPrivacySetting($fieldId);
my $fieldPrivacySetting = $privacySettingsHash->{$rawPrivacySetting};
my $fieldPrivacy = WebGUI::Form::selectBox($session,{
name => "privacy_$fieldId",
options => $field->getPrivacyOptions($session),
value => $user->getProfileFieldPrivacySetting($fieldId)
options => $privacySettingsHash,
value => $rawPrivacySetting,
extras => (!$fieldViewable) ? " disabled" : ""
});
#Create a seperate template var for each field
$var->{'profile_field_'.$fieldId.'_form' } = $fieldForm;
$var->{'profile_field_'.$fieldId.'_label' } = $fieldLabel;
$var->{'profile_field_'.$fieldId.'_subtext'} = $fieldSubtext;
$var->{'profile_field_'.$fieldId.'_extras' } = $fieldExtras;
$var->{'profile_field_'.$fieldId.'_privacy'} = $fieldPrivacy;
my $fieldBase = 'profile_field_'.$fieldId;
$var->{$fieldBase.'_form' } = $fieldForm;
$var->{$fieldBase.'_label' } = $fieldLabel;
$var->{$fieldBase.'_required' } = $fieldRequired;
$var->{$fieldBase.'_extras' } = $fieldExtras;
$var->{$fieldBase.'_privacy_form' } = $fieldPrivacy;
$var->{$fieldBase.'_field_viewable' } = $fieldViewable;
$var->{$fieldBase.'_privacy_setting' } = $fieldPrivacySetting;
$var->{$fieldBase.'_privacy_is_'.$rawPrivacySetting } = $rawPrivacySetting;
push(@fields, {
'profile_field_id' => $fieldId,
'profile_field_form' => $fieldForm,
'profile_field_label' => $fieldLabel,
'profile_field_subtext' => $field->isRequired ? "*" : undef,
'profile_field_extras' => $field->getExtras,
'profile_field_privacy' => $fieldPrivacy,
'profile_field_id' => $fieldId,
'profile_field_form' => $fieldForm,
'profile_field_label' => $fieldLabel,
'profile_field_required' => $fieldRequired,
'profile_field_extras' => $fieldExtras,
'profile_field_viewable' => $fieldViewable,
'profile_field_privacy_form' => $fieldPrivacy,
'profile_field_privacy_setting' => $fieldPrivacySetting,
'profile_field_privacy_is_'.$rawPrivacySetting => $rawPrivacySetting,
});
}
@ -420,7 +433,15 @@ sub www_editSave {
push (@{$retHash->{errors}},@{$retHash->{warnings}});
unless(scalar(@{$retHash->{errors}})) {
$session->user->updateProfileFields( $retHash->{profile} );
my $profile = $retHash->{profile};
my $privacy = {};
foreach my $fieldName (keys %{$profile}) {
$session->user->profileField($fieldName,$profile->{$fieldName});
my $privacySetting = $session->form->get("privacy_".$fieldName);
next unless $privacySetting;
$privacy->{$fieldName} = $privacySetting;
}
$session->user->setProfileFieldPrivacySetting($privacy);
}
#Store the category the error occurred in the object for reference
@ -457,6 +478,8 @@ sub www_view {
#Overwrite these
$var->{'user_full_name' } = $user->getWholeName;
$var->{'user_member_since' } = $user->dateCreated;
$var->{'profile_user_id' } = $user->userId;
$var->{'can_edit_profile' } = $uid eq $session->user->userId;
#Check user privileges
unless ($user->profileIsViewable($session->user)) {
@ -469,28 +492,38 @@ sub www_view {
);
}
#Cache the privacy settings
my $privacySettingsHash = WebGUI::ProfileField->getPrivacyOptions($session);
$var->{'profile_category_loop' } = [];
foreach my $category (@{WebGUI::ProfileCategory->getCategories($session,{ visible => 1})}) {
my @fields = ();
foreach my $field (@{$category->getFields({ visible => 1 })}) {
my $fieldId = $field->getId;
my $fieldLabel = $field->getLabel;
my $fieldValue = $field->formField(undef,2,$user);
my $fieldRaw = $user->profileField($fieldId);;
next unless ($user->canViewField($field->getId,$session->user));
my $rawPrivacySetting = $user->getProfileFieldPrivacySetting($field->getId);
my $privacySetting = $privacySettingsHash->{$rawPrivacySetting};
my $fieldId = $field->getId;
my $fieldLabel = $field->getLabel;
my $fieldValue = $field->formField(undef,2,$user);
my $fieldRaw = $user->profileField($fieldId);;
#Create a seperate template var for each field
$var->{'profile_field_'.$fieldId.'_label' } = $fieldLabel;
$var->{'profile_field_'.$fieldId.'_value' } = $fieldValue;
$var->{'profile_field_'.$fieldId.'_raw' } = $fieldRaw;
my $fieldBase = 'profile_field_'.$fieldId;
$var->{$fieldBase.'_label' } = $fieldLabel;
$var->{$fieldBase.'_value' } = $fieldValue;
$var->{$fieldBase.'_raw' } = $fieldRaw;
$var->{$fieldBase.'_privacySetting' } = $privacySetting;
$var->{$fieldBase.'_privacy_is_'.$rawPrivacySetting } = "true";
push(@fields, {
'profile_field_id' => $fieldId,
'profile_field_is_'.$fieldId => "true",
'profile_field_label' => $fieldLabel,
'profile_field_value' => $fieldValue,
'profile_field_raw' => $fieldRaw
'profile_field_id' => $fieldId,
'profile_field_is_'.$fieldId => "true",
'profile_field_label' => $fieldLabel,
'profile_field_value' => $fieldValue,
'profile_field_raw' => $fieldRaw,
'profile_field_privacySetting' => $privacySetting,
'profile_field_privacy_is_'.$rawPrivacySetting => "true",
});
}
#Don't bother displaying the category if there's nothing in it.
next unless (scalar(@fields));
#Append the category variables
$self->appendCategoryVars($var,$category,\@fields);
}
@ -503,8 +536,6 @@ sub www_view {
my $privacySetting = $user->profileField("publicProfile") || "none";
$var->{'profile_privacy_'.$privacySetting } = "true";
$var->{'profile_user_id' } = $user->userId;
$var->{'can_edit_profile' } = $uid eq $session->user->userId;
$var->{'acceptsPrivateMessages'} = $user->acceptsPrivateMessages($session->user->userId);
$var->{'acceptsFriendsRequests'} = $user->acceptsFriendsRequests($session->user);

View file

@ -66,7 +66,7 @@ Return true iff fieldName is reserved and therefore not usable as a profile fiel
sub isReservedFieldName {
my $class = shift;
my $fieldName = shift;
return isIn($fieldName, ('func', 'op'));
return isIn($fieldName, ('func', 'op', 'wg_privacySettings'));
}
#-------------------------------------------------------------------
@ -337,7 +337,10 @@ Returns a WebGUI::ProfileCategory object for the category that this profile fiel
sub getCategory {
my $self = shift;
return WebGUI::ProfileCategory->new($self->session,$self->get("profileCategoryId"));
unless ($self->{_category}) {
$self->{_category} = WebGUI::ProfileCategory->new($self->session,$self->get("profileCategoryId"));
}
return $self->{_category};
}
@ -440,6 +443,27 @@ sub getFormControlClass {
#-------------------------------------------------------------------
=head2 getPrivacyOptions ( session )
Class method which returns a hash reference containing the privacy options available.
=cut
sub getPrivacyOptions {
my $class = shift;
my $session = shift;
my $i18n = WebGUI::International->new($session);
tie my %hash, "Tie::IxHash";
%hash = (
all => $i18n->get('user profile field private message allow label'),
friends => $i18n->get('user profile field private message friends only label'),
none => $i18n->get('user profile field private message allow none label'),
);
return \%hash;
}
#-------------------------------------------------------------------
=head2 getRequiredFields ( session )
Returns an array reference of WebGUI::ProfileField objects that are marked "required". This is a class method.
@ -512,7 +536,7 @@ Returns a boolean indicating whether this field may be editable by a user.
sub isEditable {
my $self = shift;
return $self->get("editable") || $self->isRequired;
return $self->getCategory->isEditable && ($self->get("editable") || $self->isRequired);
}
@ -575,8 +599,8 @@ Returns a boolean indicating whether this field may be viewed by a user.
=cut
sub isViewable {
my $self = shift;
return $self->get("visible");
my $self = shift;
return $self->getCategory->isViewable && $self->get("visible");
}
#-------------------------------------------------------------------

View file

@ -21,6 +21,7 @@ use WebGUI::DatabaseLink;
use WebGUI::Exception;
use WebGUI::Utility;
use WebGUI::Operation::Shared;
use JSON;
=head1 NAME
@ -258,6 +259,42 @@ sub canUseAdminMode {
#-------------------------------------------------------------------
=head2 canViewField ( field, user)
Returns whether or not the user passed in can view the field value for the user.
This will only check the user level privileges.
=head3 field
Field to check privileges on
=head3 user
User to check field privileges for
=cut
sub canViewField {
my $self = shift;
my $session = $self->session;
my $field = shift;
my $user = shift;
return 0 unless ($field && $user);
#Always true for yourself
return 1 if ($self->userId eq $user->userId);
my $privacySetting = $self->getProfileFieldPrivacySetting($field);
return 0 unless (WebGUI::Utility::isIn($privacySetting,qw(all none friends)));
return 1 if ($privacySetting eq "all");
return 0 if ($privacySetting eq "none");
#It's friends so return whether or not user is a friend
return WebGUI::Friends->new($session,$self)->isFriend($user->userId);
}
#-------------------------------------------------------------------
=head2 dateCreated ( )
Returns the epoch for when this user was created.
@ -449,6 +486,42 @@ sub getGroupIdsRecursive {
return [ keys %groupIds ];
}
#-------------------------------------------------------------------
=head2 getProfileFieldPrivacySetting ( [field ])
Returns the privacy setting for the field passed in. If no field is passed in the entire hash is returned
=head3 field
Field to get privacy setting for.
=cut
sub getProfileFieldPrivacySetting {
my $self = shift;
my $session = $self->session;
my $field = shift;
unless ($self->{_privacySettings}) {
#Look it up manually because we want to cache this separately.
my $privacySettings = $session->db->quickScalar(
q{select wg_privacySettings from userProfileData where userId=?},
[$self->userId]
);
$privacySettings = "{}" unless $privacySettings;
$self->{_privacySettings} = JSON->new->decode($privacySettings);
}
return $self->{_privacySettings} unless ($field);
#No privacy settings returned the privacy setting field
return "none" if($field eq "wg_privacySettings");
return $self->{_privacySettings}->{$field};
}
#-------------------------------------------------------------------
=head2 getProfileUrl ( [page] )
@ -806,6 +879,7 @@ sub profileField {
my $fieldName = shift;
my $value = shift;
my $db = $self->session->db;
return "" if ($fieldName eq "wg_privacySettings"); # this is a special internal field, don't try to process it.
if (!exists $self->{_profile}{$fieldName} && !$self->session->db->quickScalar("SELECT COUNT(*) FROM userProfileField WHERE fieldName = ?", [$fieldName])) {
$self->session->errorHandler->warn("No such profile field: $fieldName");
return undef;
@ -902,6 +976,43 @@ sub session {
}
#-------------------------------------------------------------------
=head2 setProfileFieldPrivacySetting ( settings )
Sets the profile field privacy settings
=head3 settings
hash ref containing the field and it's corresponding privacy setting
=cut
sub setProfileFieldPrivacySetting {
my $self = shift;
my $session = $self->session;
my $settings = shift;
return undef unless scalar(keys %{$settings});
#Get the current settings
my $currentSettings = $self->getProfileFieldPrivacySetting;
foreach my $fieldId (keys %{$settings}) {
my $privacySetting = $settings->{$fieldId};
next unless (WebGUI::Utility::isIn($privacySetting,qw(all none friends)));
$currentSettings->{$fieldId} = $settings->{$fieldId};
}
#Store the data in the database
my $json = JSON->new->encode($currentSettings);
$session->db->write("update userProfileData set wg_privacySettings=? where userId=?",[$json,$self->userId]);
#Recache the current settings
$self->{_privacySettings} = $currentSettings;
}
#-------------------------------------------------------------------
=head2 status ( [ value ] )

View file

@ -160,7 +160,15 @@ our $I18N = {
lastUpdated => 1225724810,
},
'set by admin' => {
message => q{site administrator has set this field to not be visible },
lastUpdated => 1225724810,
},
'required field' => {
message => q{required },
lastUpdated => 1225724810,
},
};
1;

View file

@ -3603,17 +3603,17 @@ LongTruncOk=1</p>
},
'user profile field private message allow label' => {
message => q|Allow All|,
message => q|Public|,
lastUpdated => 1181019679,
},
'user profile field private message friends only label' => {
message => q|Allow From My Friends Only|,
message => q|Friends Only|,
lastUpdated => 1181019679,
},
'user profile field private message allow none label' => {
message => q|Allow None|,
message => q|Private|,
lastUpdated => 1181019679,
},
@ -4306,6 +4306,12 @@ Users may override this setting in their profile.
context => q{i18n label for time duration in WebGUI::DateTime},
},
'profile privacy settings' => {
message => q{Privacy Settings},
lastUpdated => 1226706547,
context => q{i18n label for time duration in WebGUI::DateTime},
},
};
1;