diff --git a/Changelog.md b/Changelog.md index cc34cbc09..5126ac3c5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -125,6 +125,8 @@ This is disabled by default since it requires the installation of additional pac * Truncate too long OpenGraph descriptions [#5387](https://github.com/diaspora/diaspora/pull/5387) * Make the source code URL configurable [#5410](https://github.com/diaspora/diaspora/pull/5410) * Prefill publisher on the tag pages [#5442](https://github.com/diaspora/diaspora/pull/5442) +* Allows users to export their data in JSON format from their user settings page [#5354](https://github.com/diaspora/diaspora/pull/5354) + # 0.4.1.2 diff --git a/Gemfile b/Gemfile index 838da0b9c..861957660 100644 --- a/Gemfile +++ b/Gemfile @@ -162,6 +162,8 @@ gem 'zip-zip' # https://github.com/discourse/discourse/pull/238 gem 'minitest' +# Serializers +gem 'active_model_serializers' # Windows and OSX have an execjs compatible runtime built-in, Linux users should # install Node.js or use 'therubyracer'. diff --git a/Gemfile.lock b/Gemfile.lock index b732e0655..ed1961d52 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -22,6 +22,8 @@ GEM erubis (~> 2.7.0) activemodel (4.1.8) activesupport (= 4.1.8) + active_model_serializers (0.9.0) + activemodel (>= 3.2) builder (~> 3.1) activerecord (4.1.8) activemodel (= 4.1.8) @@ -606,6 +608,7 @@ DEPENDENCIES actionpack-action_caching actionpack-page_caching activerecord-import (= 0.6.0) + active_model_serializers acts-as-taggable-on (= 3.4.2) acts_as_api (= 0.4.2) addressable (= 2.3.6) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 327b6068c..0e3453a2d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -28,6 +28,10 @@ class ApplicationController < ActionController::Base private + def default_serializer_options + {root: false} + end + def ensure_http_referer_is_set request.env['HTTP_REFERER'] ||= '/' end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d31773443..91ac6b3d3 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -136,8 +136,11 @@ class UsersController < ApplicationController end def export - exporter = Diaspora::Exporter.new(Diaspora::Exporters::XML) - send_data exporter.execute(current_user), :filename => "#{current_user.username}_diaspora_data.xml", :type => :xml + if export = Diaspora::Exporter.new(current_user).execute + send_data export, filename: "#{current_user.username}_diaspora_data.json", type: :json + else + head :not_acceptable + end end def export_photos diff --git a/app/models/user.rb b/app/models/user.rb index 75cde7fa1..0a7c2d863 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -37,6 +37,8 @@ class User < ActiveRecord::Base serialize :hidden_shareables, Hash has_one :person, :foreign_key => :owner_id + has_one :profile, through: :person + delegate :guid, :public_key, :posts, :photos, :owns?, :image_url, :diaspora_handle, :name, :public_url, :profile, :url, :first_name, :last_name, :gender, :participations, to: :person diff --git a/app/serializers/export/aspect_serializer.rb b/app/serializers/export/aspect_serializer.rb new file mode 100644 index 000000000..5507e516a --- /dev/null +++ b/app/serializers/export/aspect_serializer.rb @@ -0,0 +1,7 @@ +module Export + class AspectSerializer < ActiveModel::Serializer + attributes :name, + :contacts_visible, + :chat_enabled + end +end diff --git a/app/serializers/export/contact_serializer.rb b/app/serializers/export/contact_serializer.rb new file mode 100644 index 000000000..be025304f --- /dev/null +++ b/app/serializers/export/contact_serializer.rb @@ -0,0 +1,12 @@ +module Export + class ContactSerializer < ActiveModel::Serializer + attributes :sharing, + :receiving, + :person_guid, + :person_name, + :person_first_name, + :person_diaspora_handle + + has_many :aspects, each_serializer: Export::AspectSerializer + end +end diff --git a/app/serializers/export/profile_serializer.rb b/app/serializers/export/profile_serializer.rb new file mode 100644 index 000000000..b8eb2001f --- /dev/null +++ b/app/serializers/export/profile_serializer.rb @@ -0,0 +1,14 @@ +module Export + class ProfileSerializer < ActiveModel::Serializer + attributes :first_name, + :last_name, + :gender, + :bio, + :birthday, + :location, + :image_url, + :diaspora_handle, + :searchable, + :nsfw + end +end diff --git a/app/serializers/export/user_serializer.rb b/app/serializers/export/user_serializer.rb new file mode 100644 index 000000000..da277dc7f --- /dev/null +++ b/app/serializers/export/user_serializer.rb @@ -0,0 +1,16 @@ +module Export + class UserSerializer < ActiveModel::Serializer + attributes :name, + :email, + :language, + :username, + :disable_mail, + :show_community_spotlight_in_stream, + :auto_follow_back, + :auto_follow_back_aspect + has_one :profile, serializer: Export::ProfileSerializer + has_many :aspects, each_serializer: Export::AspectSerializer + has_many :contacts, each_serializer: Export::ContactSerializer + + end +end \ No newline at end of file diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml index 64b7cd5f1..597979811 100644 --- a/app/views/users/edit.html.haml +++ b/app/views/users/edit.html.haml @@ -180,7 +180,8 @@ #account_data.span6 %h3 = t('.export_data') - = link_to t('.download_xml'), export_user_path, :class => "button" + .small-horizontal-spacer + = link_to t('.download_profile'), export_user_path(format: :json), :class => "button" .small-horizontal-spacer = link_to t('.download_photos'), "#", :class => "button", :id => "photo-export-button", :title => t('.photo_export_unavailable') diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index e41deb7ea..ccd08851b 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -1266,7 +1266,7 @@ en: current_password: "Current password" current_password_expl: "the one you sign in with..." character_minimum_expl: "must be at least six characters" - download_xml: "download my xml" + download_profile: "download my profile" download_photos: "download my photos" your_handle: "Your diaspora* ID" your_email: "Your email" diff --git a/config/routes.rb b/config/routes.rb index 341180458..ce1211a97 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -101,7 +101,7 @@ Diaspora::Application.routes.draw do resource :user, :only => [:edit, :update, :destroy], :shallow => true do get :getting_started_completed - get :export + get :export, format: :json get :export_photos end diff --git a/lib/account_deleter.rb b/lib/account_deleter.rb index 6e52aeaf3..7aaf40937 100644 --- a/lib/account_deleter.rb +++ b/lib/account_deleter.rb @@ -50,7 +50,7 @@ class AccountDeleter end def special_ar_user_associations - [:invitations_from_me, :person, :contacts, :auto_follow_back_aspect] + [:invitations_from_me, :person, :profile, :contacts, :auto_follow_back_aspect] end def ignored_ar_user_associations diff --git a/lib/diaspora/exporter.rb b/lib/diaspora/exporter.rb index 6360d635c..e6f65ac7a 100644 --- a/lib/diaspora/exporter.rb +++ b/lib/diaspora/exporter.rb @@ -5,87 +5,23 @@ module Diaspora class Exporter - def initialize(strategy) - self.class.send(:include, strategy) + + SERIALIZED_VERSION = '1.0' + + def initialize(user) + @user = user end - end - module Exporters - module XML - def execute(user) - builder = Nokogiri::XML::Builder.new do |xml| - user_person_id = user.person_id - xml.export { - xml.user { - xml.username user.username - xml.serialized_private_key user.serialized_private_key - - xml.parent << user.person.to_xml - } - - - - xml.aspects { - user.aspects.each do |aspect| - xml.aspect { - xml.name aspect.name - -# xml.person_ids { - #aspect.person_ids.each do |id| - #xml.person_id id - #end - #} - - xml.post_ids { - aspect.posts.where(author_id: user_person_id).each do |post| - xml.post_id post.id - end - } - } - end - } - - xml.contacts { - user.contacts.each do |contact| - xml.contact { - xml.user_id contact.user_id - xml.person_id contact.person_id - xml.person_guid contact.person_guid - - xml.aspects { - contact.aspects.each do |aspect| - xml.aspect { - xml.name aspect.name - } - end - } - } - end - } - - xml.posts { - user.visible_shareables(Post).where(author_id: user_person_id).each do |post| - #post.comments.each do |comment| - # post_doc << comment.to_xml - #end - - xml.parent << post.to_xml - end - } - - xml.people { - user.contacts.each do |contact| - person = contact.person - xml.parent << person.to_xml - - end - } - } - end - - builder.to_xml.to_s - end + def execute + @export ||= JSON.generate serialized_user.merge(version: SERIALIZED_VERSION) end + + private + + def serialized_user + @serialized_user ||= Export::UserSerializer.new(@user).as_json + end + end end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 57fdba9d5..a2bc3d511 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -12,9 +12,9 @@ describe UsersController, :type => :controller do end describe '#export' do - it 'returns an xml file' do - get :export - expect(response.header["Content-Type"]).to include "application/xml" + it 'can return a json file' do + get :export, format: :json + expect(response.header["Content-Type"]).to include "application/json" end end diff --git a/spec/lib/account_deleter_spec.rb b/spec/lib/account_deleter_spec.rb index 7c890757e..46fe41b9b 100644 --- a/spec/lib/account_deleter_spec.rb +++ b/spec/lib/account_deleter_spec.rb @@ -43,6 +43,21 @@ describe AccountDeleter do end end + context "profile deletion" do + before do + @profile_deletion = AccountDeleter.new(remote_raphael.diaspora_handle) + @profile = remote_raphael.profile + end + + it "nulls out fields in the profile" do + @profile_deletion.perform! + expect(@profile.reload.first_name).to be_blank + expect(@profile.last_name).to be_blank + expect(@profile.searchable).to be_falsey + end + + end + context "person deletion" do before do @person_deletion = AccountDeleter.new(remote_raphael.diaspora_handle) diff --git a/spec/lib/diaspora/exporter_spec.rb b/spec/lib/diaspora/exporter_spec.rb index 63d3c2316..412be8a8f 100644 --- a/spec/lib/diaspora/exporter_spec.rb +++ b/spec/lib/diaspora/exporter_spec.rb @@ -9,8 +9,6 @@ describe Diaspora::Exporter do before do @user1 = alice - @user2 = FactoryGirl.create(:user) - @user3 = bob @user1.person.profile.first_name = "