Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge remote-tracking branch 'ovh/master'

  • Loading branch information...
commit 74f5dab628506cb704eb5ea98027f9a0690a3759 2 parents 9c7695e + 6586088
Arthur PETRY authored

Showing 35 changed files with 784 additions and 127 deletions. Show diff stats Hide diff stats

  1. +36 5 app/controllers/albums_controller.rb
  2. +2 1  app/controllers/application_controller.rb
  3. +23 8 app/controllers/comments_controller.rb
  4. +2 0  app/controllers/home_controller.rb
  5. +66 0 app/controllers/lists_controller.rb
  6. +37 0 app/controllers/posts_controller.rb
  7. +8 20 app/controllers/sessions_controller.rb
  8. +15 4 app/helpers/application_helper.rb
  9. +4 1 app/models/album.rb
  10. +69 0 app/models/list.rb
  11. +30 0 app/models/modification.rb
  12. +32 0 app/models/paginator.rb
  13. +24 0 app/models/post.rb
  14. +11 6 app/models/session.rb
  15. +1 0  app/models/track.rb
  16. +1 1  app/models/track_listening.rb
  17. +16 2 app/models/user.rb
  18. +51 0 app/models/user_list.rb
  19. +0 8 app/views/albums/_last.html.haml
  20. +26 0 app/views/albums/_lists.html.haml
  21. +12 0 app/views/albums/_paginated.html.haml
  22. +5 7 app/views/albums/_randomly.html.haml
  23. +2 0  app/views/albums/show.html.haml
  24. +27 14 app/views/home/index.html.haml
  25. +1 2  app/views/layouts/application.html.haml
  26. +51 0 app/views/lists/index.html.haml
  27. +25 0 app/views/posts/index.html.haml
  28. +10 0 app/views/posts/new.html.haml
  29. +12 17 app/views/sessions/new.html.haml
  30. +4 0 app/views/sessions/waiting_activation.html.haml
  31. +12 1 config/routes.rb
  32. +13 11 public/javascripts/application.js
  33. +17 16 public/stylesheets/application.css
  34. +112 0 spec/models/list_spec.rb
  35. +27 3 spec/spec_helper.rb
41 app/controllers/albums_controller.rb
@@ -5,18 +5,49 @@ def index
5 5 if q = params[:q]
6 6 # conditions = {:artist => /#{q}/i, :name => /#{q}/i}
7 7 # see http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
8   - conditions = { "$where" => "this.name.match(/#{q}/i) || this.artist.match(/#{q}/i)" }
  8 + # this can shutdown the server !
  9 + # conditions = { "$where" => "this.name.match(/#{q}/i) || this.artist.match(/#{q}/i)" }
  10 + conditions = nil # disabled for now.
9 11 end
10 12 if params[:randomly]
11 13 @albums = Album.find_randomly
12 14 render :partial => "albums/randomly"
13 15 return
14 16 end
15   - if params[:last_page]
16   - @last_albums = Album.find_last(params[:last_page])
17   - render :partial => "albums/last"
  17 + if params[:last]
  18 + albums_params = {:last => true}
  19 + if params[:user_id]
  20 + user = User.find(params[:user_id])
  21 + albums_params[:user_id] = user.id
  22 + albums = user.last_uploaded_albums(params[:page])
  23 + else
  24 + albums = Album.find_last(params[:page])
  25 + end
  26 + render :partial => "albums/paginated", :locals => {:albums => albums, :albums_params => albums_params}
  27 + return
  28 + end
  29 + if params[:user_id] && params[:preferred]
  30 + user = User.find(params[:user_id])
  31 + votes = user.last_votes(params[:page])
  32 + render :partial => "albums/paginated", :locals => {
  33 + :albums => votes.map(&:album),
  34 + :paginator => votes,
  35 + :albums_params => {:user_id => user.id, :preferred => true}
  36 + }
18 37 return
19 38 end
  39 + if params[:user_id] && params[:list_id]
  40 + user = User.find(params[:user_id])
  41 + list = user.list_by_id(params[:list_id])
  42 + paginator = Paginator.new(list.album_ids, :class => Album, :page => params[:page])
  43 + render :partial => "albums/paginated", :locals => {
  44 + :albums => paginator.objects_in_page,
  45 + :paginator => paginator,
  46 + :albums_params => {:user_id => list.user.id, :list_id => list.list_id}
  47 + }
  48 + return
  49 + end
  50 +
20 51 @albums ||= Album.paginate(:order => 'artist, name', :per_page => params[:limit] || 50, :conditions => conditions, :page => params[:page])
21 52 end
22 53
@@ -76,4 +107,4 @@ def album
76 107 @album ||= Album.find(params[:id])
77 108 end
78 109
79   -end
  110 +end
3  app/controllers/application_controller.rb
@@ -34,7 +34,8 @@ def login_required
34 34
35 35 def ensure_activated
36 36 if current_user && !current_user.activated
37   - redirect_to root_path
  37 + render :file => "sessions/waiting_activation"
  38 + false
38 39 end
39 40 end
40 41
31 app/controllers/comments_controller.rb
@@ -6,12 +6,19 @@ def new
6 6 end
7 7
8 8 def create
9   - album.comments << Comment.new(params[:comment])
10   - @comment = album.comments.last
  9 + @comment = Comment.new(params[:comment])
11 10 @comment.author = current_user
12   - @album.save
13   - @album.save_user_comment_for @comment
14   - create_or_update_response
  11 +
  12 + if album
  13 + album.comments << @comment
  14 + @album.save
  15 + @album.save_user_comment_for @comment
  16 + create_or_update_response
  17 + elsif post
  18 + post.comments << @comment
  19 + post.save
  20 + redirect_to posts_path
  21 + end
15 22 end
16 23
17 24 def edit
@@ -35,12 +42,20 @@ def create_or_update_response
35 42 end
36 43 end
37 44
  45 + def comment_from_params_id
  46 + album_or_post.comments.detect{|c| c.id == params[:id]}
  47 + end
  48 +
  49 + def album_or_post
  50 + album || post
  51 + end
  52 +
38 53 def album
39   - @album ||= Album.find(params[:album_id])
  54 + @album ||= params[:album_id] && Album.find(params[:album_id])
40 55 end
41 56
42   - def comment_from_params_id
43   - album.comments.detect{|c| c.id == params[:id]}
  57 + def post
  58 + @post ||= params[:post_id] && Post.find(params[:post_id])
44 59 end
45 60
46 61 end
2  app/controllers/home_controller.rb
@@ -2,9 +2,11 @@ class HomeController < ApplicationController
2 2 skip_before_filter :ensure_activated
3 3
4 4 def index
  5 + @last_blog_post = Post.last
5 6 @last_listenings = TrackListening.find(:all, :order => 'created_at DESC', :limit => 10)
6 7 @last_comments = UserComment.find(:all, :order => 'created_at DESC', :limit => 10)
7 8 @last_albums = Album.find_last
  9 + @users = User.all.sort_by{|u| u.last_uploaded_albums.empty? ? 0 : u.last_uploaded_albums.total_entries}.reverse
8 10 end
9 11
10 12 end
66 app/controllers/lists_controller.rb
... ... @@ -0,0 +1,66 @@
  1 +class ListsController < ApplicationController
  2 +
  3 + def index
  4 + user = params[:user_id] ? User.find(params[:user_id]) : current_user
  5 + @lists = user.user_lists.each{|l| l.user = user}
  6 + @new_list = List.new
  7 + end
  8 +
  9 + def create
  10 + list = List.new(params[:list])
  11 + list.author = current_user
  12 + list.save
  13 + redirect_to :action => :index
  14 + end
  15 +
  16 + def add_album
  17 + list.add(:album_id => params[:album_id], :author => current_user)
  18 + list_in_album_update_response
  19 + end
  20 +
  21 + def remove_album
  22 + list.remove(:album_id => params[:album_id], :author => current_user)
  23 + list_in_album_update_response
  24 + end
  25 +
  26 + def accept_modification
  27 + logger
  28 + modification && modification.accept(:author => current_user)
  29 + redirect_to :action => :index
  30 + end
  31 +
  32 + def reject_modification
  33 + modification && modification.reject(:author => current_user)
  34 + redirect_to :action => :index
  35 + end
  36 +
  37 + def follow
  38 + list.follow_by(current_user)
  39 + redirect_to :action => :index
  40 + end
  41 +
  42 +protected
  43 +
  44 + def list_in_album_update_response
  45 + respond_to do |format|
  46 + format.js do
  47 + @album = Album.find(params[:album_id])
  48 + render :partial => "albums/lists"
  49 + end
  50 + format.html do
  51 + redirect_to album_path(params[:album_id])
  52 + end
  53 + end
  54 + end
  55 +
  56 + def list
  57 + @list ||= List.find(params[:id])
  58 + end
  59 +
  60 + def modification
  61 + @modification ||= list.modifications.detect{|m| m.id.to_s == params[:modification_id]}
  62 + @modification.list = list
  63 + @modification
  64 + end
  65 +
  66 +end
37 app/controllers/posts_controller.rb
... ... @@ -0,0 +1,37 @@
  1 +class PostsController < ApplicationController
  2 +
  3 + def index
  4 + @posts = Post.all
  5 + @comment = Comment.new
  6 + end
  7 +
  8 + def new
  9 + @post = Post.new
  10 + end
  11 +
  12 + def create
  13 + @post = Post.new(params[:post])
  14 + @post.author_id = current_user.id
  15 + if @post.save
  16 + redirect_to :action => :index
  17 + else
  18 + render :action => :new
  19 + end
  20 + end
  21 +
  22 + def edit
  23 + @post = Post.find(params[:id])
  24 + render :action => :new
  25 + end
  26 +
  27 + def update
  28 + @post = Post.find(params[:id])
  29 + @post.author_id = current_user.id
  30 + if @post.update_attributes(params[:post])
  31 + redirect_to :action => :index
  32 + else
  33 + render :action => :edit
  34 + end
  35 + end
  36 +
  37 +end
28 app/controllers/sessions_controller.rb
@@ -2,7 +2,6 @@
2 2 require 'openid/extensions/ax'
3 3 require 'openid/extensions/sreg'
4 4
5   -
6 5 class SessionsController < ApplicationController
7 6 skip_before_filter :login_required
8 7
@@ -12,19 +11,13 @@ def new
12 11
13 12 def create
14 13 session = Session.new(params[:session])
15   - logger.debug ["openid_url_or_gmail", session.openid_url_or_gmail].inspect
16   - open_id_request = consumer.begin(session.openid_url_or_gmail)
  14 + logger.debug ["openid_provider_url", session.openid_provider_url].inspect
  15 + open_id_request = consumer.begin(session.openid_provider_url)
  16 +
  17 + ax_request = OpenID::AX::FetchRequest.new
  18 + ax_request.add(OpenID::AX::AttrInfo.new("http://axschema.org/contact/email", nil, true ))
  19 + open_id_request.add_extension(ax_request)
17 20
18   - if session.gmail?
19   - ax_request = OpenID::AX::FetchRequest.new
20   - ax_request.add(OpenID::AX::AttrInfo.new("http://schema.openid.net/contact/email", nil, true ))
21   - open_id_request.add_extension(ax_request)
22   - else
23   - sregreq = OpenID::SReg::Request.new
24   - sregreq.request_fields(['email','nickname'], true)
25   - open_id_request.add_extension(sregreq)
26   - open_id_request.return_to_args['did_sreg'] = 'y'
27   - end
28 21 redirect_to open_id_request.redirect_url(root_url, openid_complete_session_url, params[:immediate])
29 22 end
30 23
@@ -47,14 +40,9 @@ def openid_complete
47 40 when OpenID::Consumer::SUCCESS
48 41 ax_response = OpenID::AX::FetchResponse.from_success_response(openid_response)
49 42 if ax_response && ax_response.data
50   - email = ax_response.data["http://schema.openid.net/contact/email"].first
  43 + email = ax_response.data["http://axschema.org/contact/email"].first
51 44 flash[:ax_response] = ax_response.data
52 45 end
53   - sreg_resp = OpenID::SReg::Response.from_success_response(openid_response)
54   - unless sreg_resp.empty?
55   - email = sreg_resp.data["email"]
56   - end
57   - flash[:sreg_results] = sreg_resp.data
58 46 when OpenID::Consumer::SETUP_NEEDED
59 47 flash[:alert] = "Immediate request failed - Setup Needed"
60 48 when OpenID::Consumer::CANCEL
@@ -76,4 +64,4 @@ def consumer
76 64 @consumer ||= OpenID::Consumer.new(session, OpenIdStore.new)
77 65 end
78 66
79   -end
  67 +end
19 app/helpers/application_helper.rb
@@ -15,17 +15,28 @@ def cover_img_tag(record_with_cover, size=40)
15 15 end
16 16 end
17 17
  18 + def album_name_with_link(album)
  19 + content_tag(:span, h(album.artist), :class => 'artist') +
  20 + link_to(h(album.name), album_path(album), :class => 'album_name')
  21 + end
  22 +
18 23 def album_div(album)
19 24 content_tag(:div,
20 25 content_tag(:div,
21 26 cover_img_tag(album) +
22 27 content_tag(:div, "▲", :class => "pointer"),
23 28 :class => 'in_first_line') +
24   - content_tag(:div,
25   - content_tag(:span, h(album.artist), :class => 'artist') +
26   - link_to(h(album.name), album_path(album), :class => 'album_name'),
27   - :class => "info"),
  29 + content_tag(:div, album_name_with_link(album), :class => "info"),
28 30 :class => 'cover_album')
29 31 end
30 32
  33 +
  34 + def no_one_or_n_comments(comments)
  35 + case comments.length
  36 + when 0 then "Aucun commentaire"
  37 + when 1 then "1 commentaire"
  38 + else "#{comments.length} commentaires"
  39 + end
  40 + end
  41 +
31 42 end
5 app/models/album.rb
@@ -12,6 +12,8 @@ class Album
12 12 key :amazon_asin, String
13 13 key :musicbrainz_release_id, String
14 14
  15 + key :user_id, String # author
  16 +
15 17 timestamps
16 18
17 19 many :votes
@@ -86,7 +88,8 @@ def hated_by(user)
86 88 UserVote.delete_all(:album_id => id, :author_id => user.id)
87 89 votes.delete_if{|v| v.author_id == user.id}
88 90 votes << Vote.new(:note => -1, :author => user)
89   - UserVote.create(:album_id => id, :author_id => user.id, :note => -1)
  91 + # only create UserVote for positive ones for now.
  92 + # UserVote.create(:album_id => id, :author_id => user.id, :note => -1)
90 93 end
91 94
92 95 def haters
69 app/models/list.rb
... ... @@ -0,0 +1,69 @@
  1 +class List
  2 + include MongoMapper::Document
  3 +
  4 + key :name, String, :required => true
  5 + many :modifications
  6 + key :author_id, String, :required => true
  7 + # belongs_to :author, :class_name => "User"
  8 +
  9 + include Timestamp
  10 + timestamps
  11 +
  12 + after_save :create_author_user_list
  13 +
  14 + def author=(author)
  15 + self.author_id = author.id
  16 + end
  17 +
  18 + def author
  19 + @author ||= author_id && User.find(author_id)
  20 + end
  21 +
  22 + def add(params)
  23 + add_or_remove(:add, params)
  24 + end
  25 +
  26 + def remove(params)
  27 + add_or_remove(:remove, params)
  28 + end
  29 +
  30 + def follow_by(user)
  31 + user_list = user.list_by_id(id)
  32 + return user_list if user_list
  33 + user_list = UserList.new(:name => name, :list_id => id)
  34 + user.user_lists << user_list
  35 + user.save
  36 + modifications.each do |modification|
  37 + modification.list = self
  38 + modification.accept(:author => user)
  39 + end
  40 + user_list
  41 + end
  42 +
  43 + def add_or_remove(action, params)
  44 + author_id = params[:author_id]
  45 + author_id ||= params[:author] && params[:author].id
  46 + album_id = params[:album_id]
  47 + raise "missing :author_id or author" unless author_id
  48 + raise "missing :album_id" unless author_id
  49 + author = params[:author] || User.find(author_id)
  50 + user_list = follow_by(author)
  51 + modification = Modification.new(:author_id => author_id, :action => action.to_s, :album_id => album_id)
  52 + modification.list = self
  53 + modifications << modification
  54 + save
  55 + modification.accept(:author => author)
  56 + end
  57 +
  58 +protected
  59 + def create_author_user_list
  60 + user_list = author.list_by_id(id)
  61 + unless user_list
  62 + user_list = UserList.new(:name => name, :list_id => id)
  63 + author.user_lists << user_list
  64 + author.save
  65 + end
  66 + end
  67 +
  68 +
  69 +end
30 app/models/modification.rb
... ... @@ -0,0 +1,30 @@
  1 +class Modification
  2 +
  3 + include MongoMapper::EmbeddedDocument
  4 + include Timestamp
  5 + # embedded_in :list
  6 + attr_accessor :list
  7 +
  8 + belongs_to :author, :class_name => "User"
  9 + belongs_to :album
  10 + key :author_id, String, :required => true
  11 + key :album_id, String, :required => true
  12 + key :action, String, :required => true # add or remove
  13 +
  14 + def accept(params)
  15 + accept_or_reject(:accept, params)
  16 + end
  17 +
  18 + def reject(params)
  19 + accept_or_reject(:reject, params)
  20 + end
  21 +
  22 + def accept_or_reject(action, params)
  23 + author_id = params[:author_id]
  24 + author_id ||= params[:author] && params[:author].id
  25 + raise "missing :author_id or author" unless author_id
  26 + author = params[:author] || User.find(author_id)
  27 + author.list_by_id(self.list.id).send(action, self)
  28 + end
  29 +
  30 +end
32 app/models/paginator.rb
... ... @@ -0,0 +1,32 @@
  1 +class Paginator
  2 +
  3 + def initialize(ids, options = {})
  4 + @ids = ids
  5 + @per_page = options[:per_page] ? options[:per_page].to_i : 10
  6 + @page = options[:page] ? options[:page].to_i : 1
  7 + @class = options[:class]
  8 + end
  9 +
  10 + attr_reader :ids, :page, :per_page
  11 +
  12 + def pages_count
  13 + (ids.length.to_f/per_page).ceil
  14 + end
  15 +
  16 + def previous_page
  17 + page > 1 ? page - 1 : nil
  18 + end
  19 +
  20 + def next_page
  21 + page < pages_count ? page + 1 : nil
  22 + end
  23 +
  24 + def ids_in_page
  25 + (((page - 1) * per_page)..((page*per_page) - 1)).map{ |i| ids[i] }.compact
  26 + end
  27 +
  28 + def objects_in_page
  29 + @objects_in_page ||= ids_in_page.map{|id| @class.find(id)}
  30 + end
  31 +
  32 +end
24 app/models/post.rb
... ... @@ -0,0 +1,24 @@
  1 +class Post
  2 +
  3 + include MongoMapper::Document
  4 + include Timestamp
  5 + timestamps
  6 +
  7 + key :title, String, :required => true
  8 + key :body, String, :required => true
  9 + key :author_id, String, :required => true
  10 + belongs_to :author, :class_name => "User"
  11 +
  12 + many :comments
  13 +
  14 + before_save :timestamps_in_comments
  15 +
  16 + def timestamps_in_comments
  17 + current_time = Time.now.utc
  18 + comments.each do |comment|
  19 + comment.created_at ||= current_time
  20 + comment.updated_at ||= current_time
  21 + end
  22 + end
  23 +
  24 +end
17 app/models/session.rb
@@ -2,19 +2,24 @@ class Session
2 2
3 3 attr_accessor :email
4 4 attr_accessor :openid_url
  5 + attr_accessor :openid_provider
5 6
6   - def gmail?
7   - openid_url.blank?
8   - end
9   -
10   - def openid_url_or_gmail
11   - openid_url.blank? ? "https://www.google.com/accounts/o8/id" : openid_url
  7 + def openid_provider_url
  8 + case openid_provider
  9 + when "google"
  10 + "https://www.google.com/accounts/o8/id"
  11 + when "yahoo"
  12 + "https://me.yahoo.com/"
  13 + else
  14 + openid_url
  15 + end
12 16 end
13 17
14 18 def initialize(attributes={})
15 19 attributes ||= {}
16 20 self.email = attributes[:email]
17 21 self.openid_url = attributes[:openid_url]
  22 + self.openid_provider = attributes[:openid_provider]
18 23 end
19 24
20 25 end
1  app/models/track.rb
@@ -59,6 +59,7 @@ def set_album
59 59 if album.nil? || album.artist != album_artist || album.name != album_name
60 60 old_album = album
61 61 self.album = Album.find_or_create_by_artist_and_name(album_artist, album_name)
  62 + album.user_id ||= user_id
62 63 album.add_track(self)
63 64 album.save
64 65 if old_album
2  app/models/track_listening.rb
@@ -15,4 +15,4 @@ def album
15 15 track && track.album
16 16 end
17 17
18   -end
  18 +end
18 app/models/user.rb
@@ -9,6 +9,8 @@ class User
9 9 key :activated, Boolean
10 10 key :roles, Array
11 11
  12 + many :user_lists
  13 +
12 14 def roles_str
13 15 roles.join(', ')
14 16 end
@@ -21,8 +23,20 @@ def admin?
21 23 roles.include?("admin")
22 24 end
23 25
24   - def last_preferred_albums
25   - UserVote.find_all_by_author_id(id, :order => 'created_at DESC', :limit => 10).select{|v| v.note > 0}.map(&:album_id).uniq.map{|album_id| Album.find(album_id)}
  26 + def last_votes(page = 1)
  27 + UserVote.paginate(:order => 'created_at DESC', :conditions => {:author_id => id}, :per_page => 10, :page => page)
  28 + # FIXME : conditions to have only positive votes
  29 + # .select{|v| v.note > 0}
  30 + end
  31 +
  32 + def last_uploaded_albums(page = 1)
  33 + Album.paginate(:order => 'created_at DESC', :conditions => {:user_id => id}, :per_page => 10, :page => page)
  34 + end
  35 +
  36 + def list_by_id(id)
  37 + list = user_lists.detect{|l| l.list_id == id}
  38 + list.user = self if list
  39 + list
26 40 end
27 41
28 42 end
51 app/models/user_list.rb
... ... @@ -0,0 +1,51 @@
  1 +class UserList
  2 +
  3 + include MongoMapper::EmbeddedDocument
  4 +
  5 + key :list_id, String, :required => true
  6 + key :name, String, :required => true
  7 + key :album_ids, Array
  8 + key :accepted_modification_ids, Array
  9 + key :rejected_modification_ids, Array
  10 +
  11 + attr_accessor :user
  12 +
  13 + def accept(modification)
  14 + if modification.action == "add"
  15 + album_ids << modification.album_id
  16 + else
  17 + album_ids.delete(modification.album_id)
  18 + end
  19 + accepted_modification_ids << modification.id
  20 + RAILS_DEFAULT_LOGGER.debug "accepted_modification #{modification.id} by #{user.id}"
  21 + user.save
  22 + end
  23 +
  24 + def reject(modification)
  25 + if modification.action == "remove"
  26 + album_ids << modification.album_id
  27 + else
  28 + album_ids.delete(modification.album_id)
  29 + end
  30 + rejected_modification_ids << modification.id
  31 + user.save
  32 + end
  33 +
  34 + def list
  35 + @list ||= List.find(list_id)
  36 + end
  37 +
  38 + def albums
  39 + @albums ||= album_ids.map{|id| Album.find(id)}.compact
  40 + end
  41 +
  42 + def pending_modifications(reload = false)
  43 + @pending_modifications = nil if reload
  44 + @pending_modifications ||= list.modifications.reject{|m| accepted_modification_ids.include?(m.id) || rejected_modification_ids.include?(m.id) }.each{|m| m.list = list}
  45 + end
  46 +
  47 + def to_param
  48 + id
  49 + end
  50 +
  51 +end
8 app/views/albums/_last.html.haml
... ... @@ -1,8 +0,0 @@
1   -.last_albums.albums_group
2   - %h3 les derniers albums importés:
3   - %ul.links
4   - %li= link_to "«", albums_path(:last_page => @last_albums.current_page - 1)
5   - %li= link_to "»", albums_path(:last_page => @last_albums.current_page + 1)
6   - %ul.albums
7   - - @last_albums.each do |album|
8   - %li= album_div(album)
26 app/views/albums/_lists.html.haml
... ... @@ -0,0 +1,26 @@
  1 +.lists
  2 + - in_lists = current_user.user_lists.select{|list| list.album_ids.include?(@album.id)}
  3 + - other_lists = current_user.user_lists - in_lists
  4 + .in_lists
  5 + - unless in_lists.blank?
  6 + %p Dans les listes suivantes :
  7 + %ul
  8 + - in_lists.each do |list|
  9 + %li
  10 + %span.name=h list.name
  11 + .remove
  12 + - form_tag remove_album_list_path(list.list_id), :method => :delete do
  13 + = hidden_field_tag :album_id, @album.id
  14 + = submit_tag "enlever"
  15 +
  16 + .not_in_lists
  17 + - unless other_lists.blank?
  18 + %p l'ajouter à une liste :
  19 + %ul
  20 + - other_lists.each do |list|
  21 + %li
  22 + %span.name=h list.name
  23 + .add
  24 + - form_tag add_album_list_path(list.list_id) do
  25 + = hidden_field_tag :album_id, @album.id
  26 + = submit_tag "ajouter"
12 app/views/albums/_paginated.html.haml
... ... @@ -0,0 +1,12 @@
  1 +- paginator ||= albums
  2 +%ul.links
  3 + %li{:class => "#{"empty" unless paginator.previous_page}"}
  4 + - if paginator.previous_page
  5 + = link_to "«", albums_path(albums_params.merge(:page => paginator.previous_page))
  6 + %li{:class => "#{"empty" unless paginator.next_page}"}
  7 + - if paginator.next_page
  8 + = link_to "»", albums_path(albums_params.merge(:page => paginator.next_page))
  9 +
  10 +%ul.albums
  11 + - albums.each do |album|
  12 + %li= album_div(album)
12 app/views/albums/_randomly.html.haml
... ... @@ -1,7 +1,5 @@
1   -.albums_group.randomly
2   - %h3 Albums choisis aléatoirement:
3   - %ul.links
4   - %li.last= link_to "∞", albums_path(:randomly => true)
5   - %ul.albums
6   - - Album.find_randomly.each do |album|
7   - %li= album_div(album)
  1 +%ul.links
  2 + %li.last= link_to "∞", albums_path(:randomly => true)
  3 +%ul.albums
  4 + - Album.find_randomly.each do |album|
  5 + %li= album_div(album)
2  app/views/albums/show.html.haml
@@ -32,3 +32,5 @@
32 32 = render :partial => "votes.html"
33 33
34 34 = render :partial => "comments.html"
  35 +
  36 + = render :partial => "lists.html"
41 app/views/home/index.html.haml
@@ -3,31 +3,44 @@
3 3 - form_tag albums_path, :method => :get do
4 4 = text_field_tag :q
5 5 = submit_tag "Rechercher"
6   -
  6 +
7 7
8 8 %p= link_to "liste (très moche) des albums", albums_path
9 9 %p= link_to "ajouter des fichiers", new_track_path
10 10
11 11 %ul.two_cols
12 12 %li.left_col
13   - =render :partial => "albums/randomly"
14   - =render :partial => "albums/last"
  13 + .randomly
  14 + %h3 Albums choisis aléatoirement:
  15 + .albums_group=render :partial => "albums/randomly"
  16 + .last_albums
  17 + %h3 les derniers albums importés:
  18 + .albums_group=render :partial => "albums/paginated", :locals => {:albums => @last_albums, :albums_params => {:last => true}}
15 19
16   - .preferred_albums
17   - %h3
18   - Albums préférés:
  20 + .users
  21 + %h2 Utilisateurs
19 22 %ul
20   - - User.all.each do |user|
21   - - albums = user.last_preferred_albums
22   - - unless albums.empty?
  23 + - @users.each do |user|
  24 + - votes = user.last_votes
  25 + - last_uploaded = user.last_uploaded_albums
  26 + - unless votes.empty? && last_uploaded.empty?
23 27 %li
24   - .albums_group
25   - =h(user.nickname)
26   - %ul.albums
27   - - albums.each do |album|
28   - %li= album_div(album)
  28 + %h3.nickname=h(user.nickname)
  29 + - unless votes.empty?
  30 + %p= "#{votes.total_entries} albums préférés."
  31 + .albums_group
  32 + = render :partial => "albums/paginated", :locals => {:albums => votes.map(&:album), :paginator => votes, :albums_params => {:user_id => user.id, :preferred => true}}
  33 + - unless last_uploaded.empty?
  34 + %p= "#{last_uploaded.total_entries} albums uploadés."
  35 + .albums_group
  36 + = render :partial => "albums/paginated", :locals => {:albums => last_uploaded, :albums_params => {:user_id => user.id, :last => true}}
29 37
30 38 %li.right_col
  39 + - if @last_blog_post
  40 + .last_blog_post
  41 + %h3 Sur le blog :
  42 + = link_to @last_blog_post.title, posts_path
  43 +
31 44 .last_comments.last_thing
32 45 %h3 derniers commentaires :
33 46 %ul
3  app/views/layouts/application.html.haml
@@ -29,7 +29,6 @@
29 29 = yield
30 30
31 31 #footer
32   - - if controller_name != "home"
  32 + - if controller_name != "home" and current_user
33 33 %p
34 34 = link_to "home", root_path
35   -
51 app/views/lists/index.html.haml
... ... @@ -0,0 +1,51 @@
  1 +
  2 +.mine
  3 + %h2 mes listes d'albums
  4 +
  5 + %ul
  6 + - @lists.each do |list|
  7 + %li
  8 + %h3=h list.name
  9 + %span.count= "(#{pluralize(list.album_ids.length, "album")})"
  10 + - if list.list.author.id != list.user.id
  11 + %span.participation= "Participation à la liste de #{list.list.author.nickname}"
  12 + - unless list.album_ids.blank?
  13 + - paginator = Paginator.new(list.album_ids, :class => Album)
  14 + .albums_group= render :partial => "albums/paginated", :locals => {:albums => paginator.objects_in_page, :paginator => paginator, :albums_params => {:user_id => list.user.id, :list_id => list.list_id}}
  15 +
  16 + - unless list.pending_modifications.blank?
  17 + %ul.pending_modifications
  18 + - list.pending_modifications.each do |modification|
  19 + %li
  20 + %span.author= modification.author.nickname
  21 + %span.action= modification.action == "add" ? "propose d'ajouter" : "propose d'enlever"
  22 + %span.album= "l'album : " + album_name_with_link(modification.album)
  23 + .accept
  24 + - form_tag accept_modification_list_path(modification.list) do
  25 + = hidden_field_tag "modification_id", modification.id
  26 + = submit_tag "accepter"
  27 + .reject
  28 + - form_tag reject_modification_list_path(modification.list), :method => :delete do
  29 + = hidden_field_tag "modification_id", modification.id
  30 + = submit_tag "rejeter"
  31 +
  32 +
  33 + .new
  34 + %h3 Ajouter une nouvelle liste
  35 + - form_for @new_list, :url => lists_path, :html => {:method => :POST} do |f|
  36 + .title
  37 + = f.text_field :name
  38 +
  39 + = submit_tag "Ajouter"
  40 +
  41 +
  42 +.others
  43 + %h2 Listes d'autres utilisateurs
  44 + %ul
  45 + - List.all.delete_if{|list| @lists.map(&:list_id).include?(list.id)}.each do |list|
  46 + %li
  47 + %span.name= list.name
  48 + %span.author= list.author.nickname
  49 + .follow
  50 + - form_tag follow_list_path(list) do
  51 + = submit_tag "participer"
25 app/views/posts/index.html.haml
... ... @@ -0,0 +1,25 @@
  1 +%ul.posts
  2 + - @posts.each do |post|
  3 + %li.post
  4 + %h1= post.title
  5 + - if current_user.admin?
  6 + .action= link_to "edit", edit_post_path(post)
  7 + .body= post.body
  8 + .author= post.author.nickname
  9 + .timestamp= post.created_at.to_s(:db)
  10 +
  11 + .comments
  12 + %p.summary= no_one_or_n_comments(post.comments)
  13 + %ul.comments
  14 + - post.comments.each do |comment|
  15 + %li
  16 + .body= comment.body
  17 + .author_and_date
  18 + %span.author= comment.author.nickname
  19 + ,
  20 + %span.date= comment.created_at.to_s(:db) if comment.created_at
  21 +
  22 + %li.new_comment
  23 + - form_for(@comment, :url => post_comments_path(post), :html => {:method => :post}) do |f|
  24 + = f.text_area :body
  25 + = f.submit "Send"
10 app/views/posts/new.html.haml
... ... @@ -0,0 +1,10 @@
  1 +- form_for @post do |f|
  2 + .title
  3 + = f.label :title, "Titre :"
  4 + = f.text_field :title
  5 +
  6 + .body
  7 + %div= f.text_area :body
  8 +
  9 + = submit_tag "Sauver"
  10 +
29 app/views/sessions/new.html.haml
... ... @@ -1,19 +1,14 @@
1   -- form_for(@session, :url => session_path, :html => {:method => :post}) do |f|
2   - %p
3   - = f.label :openid_url
4   - = f.text_field :openid_url
5   - %p
6   - = f.submit "Login with Gmail or OpenID"
7 1
  2 +.google
  3 + - form_for(@session, :url => session_path, :html => {:method => :post}) do |f|
  4 + = hidden_field_tag "session[openid_provider]", "google"
  5 + %p= f.submit "Signin with Google Account"
  6 + %p.hint si tu utilises GMail ou que tu as un compte Google
  7 +.yahoo
  8 + - form_for(@session, :url => session_path, :html => {:method => :post}) do |f|
  9 + = hidden_field_tag "session[openid_provider]", "yahoo"
  10 + %p= f.submit "Signin with Yahoo! Id"
  11 + %p.hint si tu utilises Yahoo Mail ou que tu as un compte Yahoo! Id
8 12
9   -%ul.hints
10   - %li
11   - %p
12   - Si tu utilises GMail, tu n'as qu'à cliquer en laissant le champ "Openid url" vide.
13   - %li
14   - %p
15   - Si tu n'utilises pas GMail, il te faut une adresse OpenID, tu peux t'en créer une facilement là :
16   - = link_to "Créer une adresse OpenID chez OpenID France", "http://www.openidfrance.fr/home-2/Creez+votre+OpenID.html"
17   - %p
18   - Ensuite il suffit de revenir ici, et de remplir le champ "Openid url", puis de cliquer sur le bouton de login !
19   -
  13 +.otherwise
  14 + Sinon, crée toi un compte google ou Yahoo pour utiliser onzeer.com !
4 app/views/sessions/waiting_activation.html.haml
... ... @@ -0,0 +1,4 @@
  1 +
  2 +%p.thanks Merci pour votre inscription sur onzeer.com.
  3 +
  4 +%p.wait Nous activerons votre inscription dés que possible, a bientôt sur onzeer.com !
13 config/routes.rb
@@ -4,12 +4,23 @@
4 4
5 5 map.resources :tokens
6 6
7   - map.resources :users
  7 + map.resources :users, :has_many => :lists
8 8
9 9 map.resources :tracks, :member => {:just_listened => :post}, :collection => {:wanted => :post}
10 10
11 11 map.resources :albums, :member => {:like => :post, :hate => :post, :destroy_vote => :delete, :mb_releases => :get}, :has_many => [:comments]
12 12
  13 + map.resources :posts, :has_many => [:comments]
  14 + map.connect 'blog', :controller => "posts"
  15 +
  16 + map.resources :lists, :member => {
  17 + :follow => :post,
  18 + :add_album => :post,
  19 + :remove_album => :delete,
  20 + :accept_modification => :post,
  21 + :reject_modification => :delete,
  22 + }
  23 +
13 24 map.root :controller => 'home'
14 25
15 26 end
24 public/javascripts/application.js
@@ -37,7 +37,7 @@ function playNow(id, auto) {
37 37 // set the class playing on the current track_li
38 38 track_element.addClass('playing');
39 39 }
40   - // audio.get(0).volume = 0.1;
  40 + audio.get(0).volume = 0.5;
41 41 audio.bind("ended", trackEnded);
42 42
43 43 setTimeout(function(){ $('#time_bar').trigger("showCurrentTime"); }, 100);
@@ -276,6 +276,14 @@ function setupPlayer(tracks) {
276 276 return false;
277 277 });
278 278
  279 + $('.album .lists input[type="submit"]').live('click', function(event) {
  280 + var form = $(this).parents('form');
  281 + $.post(form.attr('action'), form.serialize(), function (data) {
  282 + $('.lists').replaceWith(data);
  283 + });
  284 + return false;
  285 + });
  286 +
279 287 }
280 288
281 289 $(document).ready(function() {
@@ -296,6 +304,7 @@ $(document).ready(function() {
296 304 });
297 305
298 306 $(document).keypress(function (e) {
  307 + if (e.altKey || e.ctrlKey || e.metaKey) { return; }
299 308 if (e.target.tagName == "INPUT" || e.target.tagName == "TEXTAREA") { return ;}
300 309 if (e.which == 32 || (65 <= e.which && e.which <= 65 + 25) || (97 <= e.which && e.which <= 97 + 25)) {
301 310 if ( ' ' == String.fromCharCode(e.which) ) { togglePlayPause(); return false; }
@@ -304,18 +313,11 @@ $(document).ready(function() {
304 313 }
305 314 });
306 315
307   - $('.albums_group .links li').live('click', function(e) {
308   - var target = $(this);
309   - var url = target.find('a').attr('href');
310   - target.parents('.albums_group').load(url);
311   - });
312   -
313   - $('.albums_group .links li a').live('click', function(e) {
  316 + $('.albums_group .links li, .albums_group .links li a').live('click', function(e) {
  317 + e.preventDefault();
314 318 var target = $(this);
315   - var url = target.attr('href');
316   - console.log(["click", target, url]);
  319 + var url = target.attr('href') || target.find('a').attr('href');
317 320 target.parents('.albums_group').load(url);
318   - e.preventDefault();
319 321 });
320 322
321 323 });
33 public/stylesheets/application.css
... ... @@ -1,6 +1,8 @@
  1 +h1, h2, h3,
1 2 ul, li, p { margin: 0; padding: 0; }
2 3 ul li { list-style-type: none; }
3 4
  5 +
4 6 .header {position: absolute; top: 0; right: 0;}
5 7 .header > div { float:left; margin: .5em; padding: 0;}
6 8
@@ -65,7 +67,7 @@ div.album,
65 67 width: 500px; left: 200px;
66 68 background-color: #bbb;
67 69 border: 1px solid #fff;
68   - -webkit-border-radius: 5px;
  70 + -webkit-border-radius: 5px;
69 71 }
70 72 #player .info_box > div { position: absolute; }
71 73 #player .img {
@@ -100,9 +102,9 @@ div.album,
100 102 .album .tracks .album_name { display:none; }
101 103
102 104
103   -#browser > ul {
  105 +#browser > ul {
104 106 position: absolute;
105   - margin: 0; padding: 0;
  107 + margin: 0; padding: 0;
106 108 overflow-y: auto;
107 109 border: 2px solid #999;
108 110 }
@@ -155,7 +157,7 @@ li.playing {
155 157 width: 100%;
156 158 background-color: #bbb;
157 159 border: 1px solid #fff;
158   - -webkit-border-radius: 5px;
  160 + -webkit-border-radius: 5px;
159 161 }
160 162 .tracks ul li {
161 163 position: relative;
@@ -199,7 +201,8 @@ li.playing {
199 201 }
200 202
201 203 .comments li { position: relative; }
202   -.comments .author {
  204 +.comments .author_and_date,
  205 +.comments p.author {
203 206 position: absolute; right: 5px; bottom: -15px;
204 207 font-size: 12px;
205 208 font-style: italic;
@@ -297,17 +300,17 @@ div.album {
297 300 padding: 1em;
298 301 margin: 1em 3em 2em;
299 302 background-color: #E8E8E8;
300   - -webkit-border-radius: 1em;
  303 + -webkit-border-radius: 1em;
301 304 -webkit-box-shadow: rgb(0, 0, 0) 0px 2px 5px;
302 305 }
303 306
304   -#player {
  307 +#player {
305 308 margin-bottom: 0;
306 309 -webkit-border-bottom-left-radius: 0;
307 310 -webkit-border-bottom-right-radius: 0;
308 311 }
309 312
310   -div.album {
  313 +div.album {
311 314 margin-top: 0;
312 315 -webkit-border-top-left-radius: 0;
313 316 -webkit-border-top-right-radius: 0;
@@ -335,7 +338,7 @@ li.album {
335 338
336 339 .albums_group {
337 340 position: relative;
338   - height: 100px;
  341 + height: 50px;
339 342 }
340 343 /* we specified albums_group height because content are positionned in absolute in it */
341 344
@@ -344,23 +347,23 @@ li.album {
344 347 .albums_group .links,
345 348 .albums_group .albums {
346 349 position:absolute;
347   - top: 20px;
  350 + top: 0;
348 351 height: 46px;
349 352 }
350 353 .albums_group .albums {
351   - margin: 15px 40px;
  354 + margin: 0px 40px;
352 355 width: 460px;
353 356 border: 1px solid #999;
354 357 background-color: #DDD;
355 358 }
356 359 .albums_group .links {
357   - margin: 15px 20px;
  360 + margin: 0px 20px;
358 361 width: 500px;
359 362 /* border: 1px solid red;*/
360 363 }
361 364 .albums_group .albums li {
362 365 float: left;
363   - width: 42px;
  366 + width: 42px;
364 367 margin: 2px 1px;
365 368 padding: 0px 1px;
366 369 cursor: pointer;
@@ -423,8 +426,6 @@ li.album {
423 426 .albums_group ul:hover li .cover_album span { top: 0.1em; }
424 427 .albums_group ul:hover li .cover_album a { top: 1.1em; }
425 428
426   -.preferred_albums .albums_group { height: 80px; }
427   -.preferred_albums .albums_group ul { top: 20px; }
428 429
429 430 /* last_thing : last_listenings & last_comments styling */
430 431 .last_thing li { position: relative; width: 200px; height: 25px; border: 1px solid #999;}
@@ -456,7 +457,7 @@ li.album {
456 457 .last_listenings .more_info {
457 458 position: absolute;
458 459 top: -10px;
459   - right: 200px;
  460 + right: 185px;
460 461 padding: 0.5em 20px;
461 462 margin: 0 10px;
462 463 width: 390px;
112 spec/models/list_spec.rb
... ... @@ -0,0 +1,112 @@
  1 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
  2 +
  3 +# List:
  4 +# name
  5 +# modifications:
  6 +# action
  7 +# author_id
  8 +# album_id
  9 +#
  10 +# User:
  11 +# lists:
  12 +# id
  13 +# name
  14 +# albums_ids
  15 +# accepted_modification_ids
  16 +# rejected_modification_ids
  17