diff options
author | francis <francis> | 2009-08-05 16:31:10 +0000 |
---|---|---|
committer | francis <francis> | 2009-08-05 16:31:10 +0000 |
commit | 0610eeb4597138723cce97dcd0c4702a0de0dbcd (patch) | |
tree | 73c3c36b700911f41ac5b2be08aee36efd99085b | |
parent | 9d3f7b1d205e36768e0910d4748ee913cb8df60f (diff) |
Some (as yet unused) profile photo code done on a whim on the train while it
was my birthday.
-rw-r--r-- | app/controllers/user_controller.rb | 8 | ||||
-rw-r--r-- | app/models/profile_photo.rb | 88 | ||||
-rw-r--r-- | app/models/user.rb | 13 | ||||
-rw-r--r-- | db/migrate/079_add_profile_photo.rb | 20 | ||||
-rw-r--r-- | db/schema.rb | 8 | ||||
-rw-r--r-- | spec/fixtures/parrot.jpg | bin | 0 -> 15232 bytes | |||
-rw-r--r-- | spec/fixtures/parrot.png | bin | 0 -> 96431 bytes | |||
-rw-r--r-- | spec/models/profile_photo_spec.rb | 40 | ||||
-rw-r--r-- | spec/models/user_spec.rb | 32 | ||||
-rw-r--r-- | spec/spec_helper.rb | 6 |
10 files changed, 212 insertions, 3 deletions
diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 6d3cb3480..cf1eb1d2c 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -4,7 +4,7 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: user_controller.rb,v 1.66 2009-04-23 12:17:06 tony Exp $ +# $Id: user_controller.rb,v 1.67 2009-08-05 16:31:10 francis Exp $ class UserController < ApplicationController # Show page about a user @@ -314,4 +314,10 @@ class UserController < ApplicationController render :action => 'confirm' # must be same as for send_confirmation_mail above to avoid leak of presence of email in db end + def set_profile_photo + @photo_user = User.find(params[:id]) + new_profile_photo = ProfilePhoto.new(:data => data) + @photo_user.set_profile_photo(new_profile_photo) + end end + diff --git a/app/models/profile_photo.rb b/app/models/profile_photo.rb new file mode 100644 index 000000000..23c85c133 --- /dev/null +++ b/app/models/profile_photo.rb @@ -0,0 +1,88 @@ +# models/profile_photo.rb: +# Image of user that goes on their profile. +# +# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved. +# Email: francis@mysociety.org; WWW: http://www.mysociety.org/ +# +# $Id: profile_photo.rb,v 1.1 2009-08-05 16:31:11 francis Exp $ +# +require 'mahoro' +require 'RMagick' + +class ProfilePhoto < ActiveRecord::Base + WIDTH = 96 + HEIGHT = 96 + + has_one :user + validates_presence_of :user + + # deliberately don't strip_attributes, so keeps raw photo properly + + # convert binary data blob into ImageMagick image when assigned + attr_accessor :image + def data=(data) + write_attribute(:data, data) + if data.nil? + self.image = nil + return + end + + image_list = Magick::ImageList.new + begin + image_list.from_blob(data) + rescue Magick::ImageMagickError + self.image = nil + write_attribute(:data, nil) + return + end + + self.image = image_list[0] # XXX perhaps take largest image or somesuch if there were multiple in the file? + self.convert_image + end + + # make image valid format and size + def convert_image + if self.data.nil? + return + end + if self.image.nil? + return + end + + # convert to PNG if it isn't, and to right size + altered = false + if self.image.format != 'PNG' + self.image.format = 'PNG' + altered = true + end + if image.columns != WIDTH || image.rows != HEIGHT + image.resize_to_fill!(WIDTH, HEIGHT) + altered = true + end + if altered + write_attribute(:data, self.image.to_blob) + end + end + + def validate + if self.data.nil? + errors.add(:data, "^No image specified") + return + end + + if self.image.nil? + errors.add(:data, "^Couldn't read the image that you uploaded, please try again.") + return + end + + if self.image.format != 'PNG' + errors.add(:data, "^Failed to convert image to a PNG") + end + + if self.image.columns != WIDTH || self.image.rows != HEIGHT + errors.add(:data, "^Failed to convert image to the correct size: at #{self.image.columns}x#{self.image.rows}, need #{WIDTH}x#{HEIGHT}") + end + end +end + + diff --git a/app/models/user.rb b/app/models/user.rb index 4853d633c..7bb5118ac 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,7 +23,7 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: user.rb,v 1.97 2009-07-03 11:43:37 francis Exp $ +# $Id: user.rb,v 1.98 2009-08-05 16:31:11 francis Exp $ require 'digest/sha1' @@ -42,6 +42,7 @@ class User < ActiveRecord::Base has_many :post_redirects has_many :track_things, :foreign_key => 'tracking_user_id', :order => 'created_at desc' has_many :comments, :order => 'created_at desc' + has_one :profile_photo attr_accessor :password_confirmation, :no_xapian_reindex validates_confirmation_of :password, :message =>"^Please enter the same password twice" @@ -254,6 +255,16 @@ class User < ActiveRecord::Base return PublicBody.extract_domain_from_email(self.email) end + def set_profile_photo(new_profile_photo) + ActiveRecord::Base.transaction do + if !self.profile_photo.nil? + self.profile_photo.destroy + end + new_profile_photo.user = self + self.profile_photo = new_profile_photo + end + end + private def self.encrypted_password(password, salt) diff --git a/db/migrate/079_add_profile_photo.rb b/db/migrate/079_add_profile_photo.rb new file mode 100644 index 000000000..a6c031d89 --- /dev/null +++ b/db/migrate/079_add_profile_photo.rb @@ -0,0 +1,20 @@ +class AddProfilePhoto < ActiveRecord::Migration + def self.up + create_table :profile_photos do |t| + t.column :data, :binary, :null => false + t.column :user_id, :integer, :null => false + end + + add_column :users, :profile_photo_id, :integer, :null => true + + if ActiveRecord::Base.connection.adapter_name == "PostgreSQL" + execute "ALTER TABLE profile_photos ADD CONSTRAINT fk_profile_photos_user FOREIGN KEY (user_id) REFERENCES users(id)" + execute "ALTER TABLE users ADD CONSTRAINT fk_users_profile_photo FOREIGN KEY (profile_photo_id) REFERENCES profile_photos(id)" + end + end + + def self.down + remove_column :users, :profile_photo_id + drop_table :profile_photos + end +end diff --git a/db/schema.rb b/db/schema.rb index 7055727eb..78f0ed992 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 78) do +ActiveRecord::Schema.define(:version => 79) do create_table "acts_as_xapian_jobs", :force => true do |t| t.string "model", :null => false @@ -142,6 +142,11 @@ ActiveRecord::Schema.define(:version => 78) do add_index "post_redirects", ["token"], :name => "index_post_redirects_on_token" add_index "post_redirects", ["updated_at"], :name => "index_post_redirects_on_updated_at" + create_table "profile_photos", :force => true do |t| + t.binary "data", :null => false + t.integer "user_id", :null => false + end + create_table "public_bodies", :force => true do |t| t.text "name", :null => false t.text "short_name", :null => false @@ -236,6 +241,7 @@ ActiveRecord::Schema.define(:version => 78) do t.datetime "last_daily_track_email", :default => '2000-01-01 00:00:00' t.string "admin_level", :default => "none", :null => false t.text "ban_text", :default => "", :null => false + t.integer "profile_photo_id" end add_index "users", ["url_name"], :name => "index_users_on_url_name", :unique => true diff --git a/spec/fixtures/parrot.jpg b/spec/fixtures/parrot.jpg Binary files differnew file mode 100644 index 000000000..22fd8e4de --- /dev/null +++ b/spec/fixtures/parrot.jpg diff --git a/spec/fixtures/parrot.png b/spec/fixtures/parrot.png Binary files differnew file mode 100644 index 000000000..77442a3d5 --- /dev/null +++ b/spec/fixtures/parrot.png diff --git a/spec/models/profile_photo_spec.rb b/spec/models/profile_photo_spec.rb new file mode 100644 index 000000000..5b05c1205 --- /dev/null +++ b/spec/models/profile_photo_spec.rb @@ -0,0 +1,40 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe ProfilePhoto, "when constructing a new photo" do + + before do + #@request_event = mock_model(InfoRequestEvent, :xapian_mark_needs_index => true) + #@request = mock_model(InfoRequest, :info_request_events => [@request_event]) + #@user = mock_model(User) + end + + it 'should take no image as invalid' do + profile_photo = ProfilePhoto.new(:data => nil) + profile_photo.valid?.should == false + end + + it 'should take bad binary data as invalid' do + profile_photo = ProfilePhoto.new(:data => 'blahblahblah') + profile_photo.valid?.should == false + end + + it 'should accept and convert a PNG to right size' do + data = load_image_fixture("parrot.png") + profile_photo = ProfilePhoto.new(:data => data, :user => mock_model(User, :valid? => true)) + profile_photo.valid?.should == true + profile_photo.image.format.should == 'PNG' + profile_photo.image.columns.should == 96 + profile_photo.image.rows.should == 96 + end + + it 'should accept and convert a JPEG to right format and size' do + data = load_image_fixture("parrot.jpg") + profile_photo = ProfilePhoto.new(:data => data, :user => mock_model(User, :valid? => true)) + profile_photo.valid?.should == true + profile_photo.image.format.should == 'PNG' + profile_photo.image.columns.should == 96 + profile_photo.image.rows.should == 96 + end + +end + diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index db7753469..7de181300 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -216,3 +216,35 @@ describe User, " when making name and email address" do end +describe User, " when setting a profile photo" do + before do + @user = User.new + @user.name = "Sensible User" + @user.email = "sensible@localhost" + @user.password = "sensiblepassword" + end + + it "should attach it to the user" do + data = load_image_fixture("parrot.png") + profile_photo = ProfilePhoto.new(:data => data) + @user.set_profile_photo(profile_photo) + profile_photo.user.should == @user + end + +# it "should destroy old photos being replaced" do +# ProfilePhoto.count.should == 0 +# +# data_1 = load_image_fixture("parrot.png") +# profile_photo_1 = ProfilePhoto.new(:data => data_1) +# data_2 = load_image_fixture("parrot.jpg") +# profile_photo_2 = ProfilePhoto.new(:data => data_2) +# +# @user.set_profile_photo(profile_photo_1) +# @user.save! +# ProfilePhoto.count.should == 1 +# @user.set_profile_photo(profile_photo_2) +# @user.save! +# ProfilePhoto.count.should == 1 +# end +end + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6852909a6..2af585d7a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -31,6 +31,12 @@ def receive_incoming_mail(email_name, email_to, email_from = 'geraldinequango@lo RequestMailer.receive(content) end +def load_image_fixture(image_name) + image_name = File.join(Spec::Runner.configuration.fixture_path, image_name) + content = File.read(image_name) + return content +end + def rebuild_xapian_index rebuild_name = File.dirname(__FILE__) + '/../script/rebuild-xapian-index' Kernel.system(rebuild_name) or raise "failed to launch rebuild-xapian-index" |