Allow extended profile fields (previously private profile) to be set public (#5684).
This adds a new boolean field "public_details" to person model. By default it is false and represents old behaviour. When it is set to true, extended profile (bio,location,gender,birthday) get available to people who didn't log into diaspora and to people you don't share with (i.e. it is made public). In UI, a bootstrap-switch added on the profile-edit page in order to change the setting. This also changes wording from public/private profile to basic/extended. The latter could be public and limited.
This commit is contained in:
parent
e0782437b8
commit
7a5a0a909a
24 changed files with 131 additions and 69 deletions
1
Gemfile
1
Gemfile
|
|
@ -57,6 +57,7 @@ gem "bootstrap-sass", "3.3.5"
|
|||
gem "compass-rails", "2.0.4"
|
||||
gem "sass-rails", "5.0.1"
|
||||
gem "autoprefixer-rails", "5.2.1"
|
||||
gem "bootstrap-switch-rails", "3.3.3"
|
||||
|
||||
# Database
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ GEM
|
|||
bootstrap-sass (3.3.5)
|
||||
autoprefixer-rails (>= 5.0.0.1)
|
||||
sass (>= 3.2.19)
|
||||
bootstrap-switch-rails (3.3.3)
|
||||
buftok (0.2.0)
|
||||
builder (3.2.2)
|
||||
byebug (4.0.5)
|
||||
|
|
@ -751,6 +752,7 @@ DEPENDENCIES
|
|||
autoprefixer-rails (= 5.2.1)
|
||||
backbone-on-rails (= 1.1.2.1)
|
||||
bootstrap-sass (= 3.3.5)
|
||||
bootstrap-switch-rails (= 3.3.3)
|
||||
capybara (= 2.4.4)
|
||||
carrierwave (= 0.10.0)
|
||||
compass-rails (= 2.0.4)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
app.pages.Settings = Backbone.View.extend({
|
||||
initialize: function() {
|
||||
$(".settings_visibility").tooltip({placement: "top"});
|
||||
$("[name='profile[public_details]']").bootstrapSwitch();
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ app.Router = Backbone.Router.extend({
|
|||
"conversations": "conversations",
|
||||
"user/edit": "settings",
|
||||
"users/sign_up": "registration",
|
||||
"profile/edit": "settings",
|
||||
|
||||
//new hotness
|
||||
"posts/:id": "singlePost",
|
||||
|
|
|
|||
|
|
@ -1,17 +1,7 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.ProfileSidebar = app.views.Base.extend({
|
||||
templateName: 'profile_sidebar',
|
||||
|
||||
presenter: function() {
|
||||
return _.extend({}, this.defaultPresenter(), {
|
||||
show_profile_info: this._shouldShowProfileInfo(),
|
||||
});
|
||||
},
|
||||
|
||||
_shouldShowProfileInfo: function() {
|
||||
return (this.model.isSharing() || this.model.get('is_own_profile'));
|
||||
}
|
||||
templateName: "profile_sidebar"
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -46,3 +46,4 @@
|
|||
//= require mentions
|
||||
//= require bootstrap
|
||||
//= require osmlocator
|
||||
//= require bootstrap-switch
|
||||
|
|
|
|||
|
|
@ -92,3 +92,5 @@
|
|||
|
||||
/* statistics */
|
||||
@import 'new_styles/statistics';
|
||||
|
||||
@import "bootstrap3-switch";
|
||||
|
|
|
|||
|
|
@ -148,3 +148,9 @@
|
|||
&:last-of-type{ float: right; }
|
||||
}
|
||||
}
|
||||
|
||||
#update_profile_form {
|
||||
.visibility-hint-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class PeopleController < ApplicationController
|
|||
def show
|
||||
mark_corresponding_notifications_read if user_signed_in?
|
||||
|
||||
@person_json = PersonPresenter.new(@person, current_user).full_hash_with_profile
|
||||
@person_json = PersonPresenter.new(@person, current_user).as_json
|
||||
|
||||
respond_to do |format|
|
||||
format.all do
|
||||
|
|
@ -144,7 +144,7 @@ class PeopleController < ApplicationController
|
|||
if @person
|
||||
@contact = current_user.contact_for(@person)
|
||||
@contacts_of_contact = Contact.contact_contacts_for(current_user, @person)
|
||||
gon.preloads[:person] = PersonPresenter.new(@person, current_user).full_hash_with_profile
|
||||
gon.preloads[:person] = PersonPresenter.new(@person, current_user).as_json
|
||||
gon.preloads[:photos] = {
|
||||
count: photos_from(@person, :all).count(:all)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class PhotosController < ApplicationController
|
|||
@posts = current_user.photos_from(@person, max_time: max_time).order('created_at desc')
|
||||
respond_to do |format|
|
||||
format.all do
|
||||
gon.preloads[:person] = PersonPresenter.new(@person, current_user).full_hash_with_profile
|
||||
gon.preloads[:person] = PersonPresenter.new(@person, current_user).as_json
|
||||
gon.preloads[:photos] = {
|
||||
count: current_user.photos_from(@person, limit: :all).count(:all)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class ProfilesController < ApplicationController
|
|||
#checkbox tags wtf
|
||||
@profile_attrs[:searchable] ||= false
|
||||
@profile_attrs[:nsfw] ||= false
|
||||
@profile_attrs[:public_details] ||= false
|
||||
|
||||
if params[:photo_id]
|
||||
@profile_attrs[:photo] = Photo.where(:author_id => current_user.person_id, :id => params[:photo_id]).first
|
||||
|
|
@ -79,6 +80,8 @@ class ProfilesController < ApplicationController
|
|||
end
|
||||
|
||||
def profile_params
|
||||
params.require(:profile).permit(:first_name, :last_name, :gender, :bio, :location, :searchable, :tag_string, :nsfw, :date => [:year, :month, :day]) || {}
|
||||
params.require(:profile).permit(:first_name, :last_name, :gender, :bio,
|
||||
:location, :searchable, :tag_string, :nsfw,
|
||||
:public_details, date: %i(year month day)) || {}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class Person < ActiveRecord::Base
|
|||
has_one :profile, :dependent => :destroy
|
||||
delegate :last_name, :image_url, :tag_string, :bio, :location,
|
||||
:gender, :birthday, :formatted_birthday, :tags, :searchable,
|
||||
to: :profile
|
||||
:public_details?, to: :profile
|
||||
accepts_nested_attributes_for :profile
|
||||
|
||||
before_validation :downcase_diaspora_handle
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ class ContactPresenter < BasePresenter
|
|||
end
|
||||
|
||||
def full_hash_with_person
|
||||
full_hash.merge(person: PersonPresenter.new(person, current_user).full_hash_with_profile)
|
||||
full_hash.merge(person: PersonPresenter.new(person, current_user).as_json)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,41 +10,16 @@ class PersonPresenter < BasePresenter
|
|||
|
||||
def full_hash
|
||||
base_hash.merge(
|
||||
relationship: relationship,
|
||||
block: is_blocked? ? BlockPresenter.new(current_user_person_block).base_hash : false,
|
||||
contact: (!own_profile? && has_contact?) ? {id: current_user_person_contact.id} : false,
|
||||
is_own_profile: own_profile?
|
||||
relationship: relationship,
|
||||
block: is_blocked? ? BlockPresenter.new(current_user_person_block).base_hash : false,
|
||||
contact: (!own_profile? && has_contact?) ? {id: current_user_person_contact.id} : false,
|
||||
is_own_profile: own_profile?,
|
||||
show_profile_info: public_details? || own_profile? || person_is_following_current_user
|
||||
)
|
||||
end
|
||||
|
||||
def full_hash_with_avatar
|
||||
full_hash.merge(avatar: AvatarPresenter.new(profile).base_hash)
|
||||
end
|
||||
|
||||
def full_hash_with_profile
|
||||
attrs = full_hash
|
||||
|
||||
if own_profile? || person_is_following_current_user
|
||||
attrs.merge!(profile: ProfilePresenter.new(profile).private_hash)
|
||||
else
|
||||
attrs.merge!(profile: ProfilePresenter.new(profile).public_hash)
|
||||
end
|
||||
|
||||
attrs
|
||||
end
|
||||
|
||||
def as_json(_options={})
|
||||
attrs = full_hash_with_avatar
|
||||
|
||||
if own_profile? || person_is_following_current_user
|
||||
attrs.merge!(
|
||||
location: @presentable.location,
|
||||
birthday: @presentable.formatted_birthday,
|
||||
bio: @presentable.bio
|
||||
)
|
||||
end
|
||||
|
||||
attrs
|
||||
full_hash_with_profile
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
@ -69,6 +44,18 @@ class PersonPresenter < BasePresenter
|
|||
@presentable.shares_with(current_user)
|
||||
end
|
||||
|
||||
def full_hash_with_profile
|
||||
attrs = full_hash
|
||||
|
||||
if attrs[:show_profile_info]
|
||||
attrs.merge!(profile: ProfilePresenter.new(profile).private_hash)
|
||||
else
|
||||
attrs.merge!(profile: ProfilePresenter.new(profile).public_hash)
|
||||
end
|
||||
|
||||
attrs
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_user_person_block
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@
|
|||
-# the COPYRIGHT file.
|
||||
|
||||
%hr
|
||||
%h3= t('profiles.edit.your_private_profile')
|
||||
%h3.inline
|
||||
= t("profiles.edit.extended")
|
||||
= t("profiles.edit.extended_visibility_text")
|
||||
= check_box_tag "profile[public_details]", true, profile.public_details, {"data-size" => "mini", "data-on-text" => t("profiles.edit.public"), "data-off-text" => t("profiles.edit.limited")}
|
||||
%span{ :title => t("profiles.edit.extended_hint") }
|
||||
%i.entypo.circled-help.visibility-hint-icon
|
||||
.small-horizontal-spacer
|
||||
|
||||
%h4= t('profiles.edit.your_bio')
|
||||
|
||||
|
|
@ -30,6 +36,12 @@
|
|||
|
||||
.small-horizontal-spacer
|
||||
|
||||
%hr
|
||||
%h3.inline
|
||||
= t('profiles.edit.settings')
|
||||
|
||||
.small-horizontal-spacer
|
||||
|
||||
%h4= t('search')
|
||||
|
||||
.well.checkbox
|
||||
|
|
|
|||
|
|
@ -38,7 +38,11 @@
|
|||
.stream
|
||||
%p{:class => "conversation_#{name}"}= msg
|
||||
|
||||
%h3= t('profiles.edit.your_public_profile')
|
||||
%h3.inline
|
||||
= t("profiles.edit.basic")
|
||||
%span{ :title => t("profiles.edit.basic_hint") }
|
||||
%i.entypo.circled-help.visibility-hint-icon
|
||||
.small-horizontal-spacer
|
||||
|
||||
= error_messages_for profile
|
||||
|
||||
|
|
|
|||
|
|
@ -1008,8 +1008,14 @@ en:
|
|||
|
||||
profiles:
|
||||
edit:
|
||||
your_public_profile: "Your public profile"
|
||||
your_private_profile: "Your private profile"
|
||||
basic: "My basic profile"
|
||||
extended: "My extended profile"
|
||||
settings: "Profile settings"
|
||||
extended_visibility_text: "Visibility of your extended profile:"
|
||||
public: "Public"
|
||||
limited: "Limited"
|
||||
basic_hint: "Every item in your profile is optional. Your basic profile will always be publicly visible."
|
||||
extended_hint: "Click the switch to set your extended profile data visibility. Public means it is visible to the internet, limited means only people who you share with will see this information."
|
||||
your_name: "Your name"
|
||||
first_name: "First name"
|
||||
last_name: "Last name"
|
||||
|
|
|
|||
5
db/migrate/20150630221004_add_public_to_profiles.rb
Normal file
5
db/migrate/20150630221004_add_public_to_profiles.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class AddPublicToProfiles < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :profiles, :public_details, :boolean, default: false
|
||||
end
|
||||
end
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150607143809) do
|
||||
ActiveRecord::Schema.define(version: 20150630221004) do
|
||||
|
||||
create_table "account_deletions", force: :cascade do |t|
|
||||
t.string "diaspora_handle", limit: 255
|
||||
|
|
@ -409,6 +409,7 @@ ActiveRecord::Schema.define(version: 20150607143809) do
|
|||
t.string "location", limit: 255
|
||||
t.string "full_name", limit: 70
|
||||
t.boolean "nsfw", default: false
|
||||
t.boolean "public_details", default: false
|
||||
end
|
||||
|
||||
add_index "profiles", ["full_name", "searchable"], name: "index_profiles_on_full_name_and_searchable", using: :btree
|
||||
|
|
|
|||
|
|
@ -31,13 +31,16 @@ Feature: editing your profile
|
|||
And the "profile_date_day" field should be filled with "30"
|
||||
And the "profile_location" field should be filled with "Kamino"
|
||||
And I should see "#starwars" within "ul#as-selections-tags"
|
||||
And the "#profile_public_details" bootstrap-switch should be off
|
||||
|
||||
When I fill in "profile[tag_string]" with "#kamino"
|
||||
And I press the first ".as-result-item" within ".as-results"
|
||||
And I toggle the "#profile_public_details" bootstrap-switch
|
||||
|
||||
And I press "update_profile"
|
||||
Then I should see "#kamino" within "ul#as-selections-tags"
|
||||
And I should see "#starwars" within "ul#as-selections-tags"
|
||||
And the "#profile_public_details" bootstrap-switch should be on
|
||||
|
||||
When I attach the file "spec/fixtures/bad_urls.txt" to "file" within "#file-upload"
|
||||
And I confirm the alert
|
||||
|
|
|
|||
|
|
@ -168,6 +168,15 @@ Then /^the "([^"]*)" checkbox(?: within "([^"]*)")? should not be checked$/ do |
|
|||
end
|
||||
end
|
||||
|
||||
Then /^the "([^"]*)" bootstrap-switch should be (on|off)$/ do |label, state|
|
||||
result = execute_script("return $('#{label}').bootstrapSwitch('state')")
|
||||
result.should state == "on" ? be_truthy : be_falsey
|
||||
end
|
||||
|
||||
Then /^I toggle the "([^"]*)" bootstrap-switch$/ do |label|
|
||||
execute_script("return $('#{label}').bootstrapSwitch('toggleState')")
|
||||
end
|
||||
|
||||
Then /^(?:|I )should be on (.+)$/ do |page_name|
|
||||
confirm_on_page(page_name)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ describe("app.views.ProfileSidebar", function() {
|
|||
diaspora_id: "alice@umbrella.corp",
|
||||
name: "Project Alice",
|
||||
relationship: 'mutual',
|
||||
show_profile_info: true,
|
||||
profile: {
|
||||
bio: "confidential",
|
||||
location: "underground",
|
||||
|
|
|
|||
|
|
@ -356,18 +356,19 @@ describe Profile, :type => :model do
|
|||
profile = FactoryGirl.build :profile
|
||||
expect(profile.send(:clearable_fields).sort).to eq(
|
||||
["diaspora_handle",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"image_url",
|
||||
"image_url_small",
|
||||
"image_url_medium",
|
||||
"birthday",
|
||||
"gender",
|
||||
"bio",
|
||||
"searchable",
|
||||
"nsfw",
|
||||
"location",
|
||||
"full_name"].sort
|
||||
"first_name",
|
||||
"last_name",
|
||||
"image_url",
|
||||
"image_url_small",
|
||||
"image_url_medium",
|
||||
"birthday",
|
||||
"gender",
|
||||
"bio",
|
||||
"searchable",
|
||||
"nsfw",
|
||||
"location",
|
||||
"public_details",
|
||||
"full_name"].sort
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,26 +6,52 @@ describe PersonPresenter do
|
|||
|
||||
describe "#as_json" do
|
||||
context "with no current_user" do
|
||||
it "returns the user's public information if a user is not logged in" do
|
||||
it "returns the user's basic profile" do
|
||||
expect(PersonPresenter.new(person, nil).as_json).to include(person.as_api_response(:backbone).except(:avatar))
|
||||
end
|
||||
|
||||
it "returns the user's additional profile if the user has set additional profile public" do
|
||||
person.profile.public_details = true
|
||||
expect(PersonPresenter.new(person, nil).as_json[:profile]).to include(*%i(location bio gender birthday))
|
||||
end
|
||||
|
||||
it "doesn't return user's additional profile if the user hasn't set additional profile public" do
|
||||
person.profile.public_details = false
|
||||
expect(PersonPresenter.new(person, nil).as_json[:profile]).not_to include(*%i(location bio gender birthday))
|
||||
end
|
||||
end
|
||||
|
||||
context "with a current_user" do
|
||||
let(:current_user) { FactoryGirl.create(:user)}
|
||||
let(:presenter){ PersonPresenter.new(person, current_user) }
|
||||
# here private information == addtional user profile, because additional profile by default is private
|
||||
|
||||
it "doesn't share private information when the users aren't connected" do
|
||||
expect(presenter.full_hash_with_profile[:profile]).not_to have_key(:location)
|
||||
expect(person.profile.public_details).to be_falsey
|
||||
expect(presenter.as_json[:show_profile_info]).to be_falsey
|
||||
expect(presenter.as_json[:profile]).not_to have_key(:location)
|
||||
end
|
||||
|
||||
it "shares private information when the users aren't connected, but profile is public" do
|
||||
person.profile.public_details = true
|
||||
expect(presenter.as_json[:show_profile_info]).to be_truthy
|
||||
expect(presenter.as_json[:relationship]).to be(:not_sharing)
|
||||
expect(presenter.as_json[:profile]).to have_key(:location)
|
||||
end
|
||||
|
||||
it "has private information when the person is sharing with the current user" do
|
||||
expect(person).to receive(:shares_with).with(current_user).and_return(true)
|
||||
expect(presenter.full_hash_with_profile[:profile]).to have_key(:location)
|
||||
expect(person.profile.public_details).to be_falsey
|
||||
pr_json = presenter.as_json
|
||||
expect(pr_json[:show_profile_info]).to be_truthy
|
||||
expect(pr_json[:profile]).to have_key(:location)
|
||||
end
|
||||
|
||||
it "returns the user's private information if a user is logged in as herself" do
|
||||
expect(PersonPresenter.new(current_user.person, current_user).as_json).to have_key(:location)
|
||||
current_person_presenter = PersonPresenter.new(current_user.person, current_user)
|
||||
expect(current_user.person.profile.public_details).to be_falsey
|
||||
expect(current_person_presenter.as_json[:show_profile_info]).to be_truthy
|
||||
expect(current_person_presenter.as_json[:profile]).to have_key(:location)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue