contributions viewing

This commit is contained in:
Emi Matchu 2010-11-06 11:52:58 -04:00
parent db56b0d218
commit a5b119a9bc
16 changed files with 323 additions and 1 deletions

View file

@ -0,0 +1,7 @@
class ContributionsController < ApplicationController
def index
@contributions = Contribution.recent.paginate :page => params[:page],
:include => :user
Contribution.preload_contributeds_and_parents @contributions
end
end

View file

@ -39,4 +39,8 @@ module ApplicationHelper
def origin_tag(value) def origin_tag(value)
hidden_field_tag 'origin', value, :id => nil hidden_field_tag 'origin', value, :id => nil
end end
def title(value)
content_for :title, value
end
end end

View file

@ -0,0 +1,40 @@
module ContributionHelper
def contributed_description(contributed)
case contributed
when Item
contributed_item(contributed, 'for the first time')
when SwfAsset
contributed_item(contributed.item, 'on a new body type')
when PetType
contributed_pet_type(contributed, :after => 'for the first time')
when PetState
contributed_pet_type(contributed.pet_type, :before => 'a new pose for')
end
end
def contributed_item(item, adverbial)
output do |html|
html << 'the'
html << link_to(item.name, item, :class => 'contributed-name')
html << adverbial
html << image_tag(item.thumbnail_url)
end
end
PET_TYPE_IMAGE_FORMAT = 'http://pets.neopets.com/cp/%s/1/3.png'
def contributed_pet_type(pet_type, options)
options[:before] ||= 'the'
output do |html|
html << options[:before]
html << content_tag(:span, pet_type.human_name, :class => 'contributed-name')
html << options[:after] if options[:after]
html << image_tag(sprintf(PET_TYPE_IMAGE_FORMAT, pet_type.image_hash))
end
end
private
def output(&block)
raw([].tap(&block).join(' '))
end
end

View file

@ -0,0 +1,84 @@
class Contribution < ActiveRecord::Base
POINT_VALUES = {
'Item' => 3,
'SwfAsset' => 2,
'PetType' => 15,
'PetState' => 10
}
attr_accessor :contributed
belongs_to :user
scope :recent, order('id DESC')
cattr_reader :per_page
@@per_page = 30
def point_value
POINT_VALUES[contributed_type]
end
CONTRIBUTED_RELATIONSHIPS = {
'SwfAsset' => 'Item',
'PetState' => 'PetType'
}
CONTRIBUTED_CHILDREN = CONTRIBUTED_RELATIONSHIPS.keys
CONTRIBUTED_TYPES = CONTRIBUTED_CHILDREN + CONTRIBUTED_RELATIONSHIPS.values
CONTRIBUTED_BASES = {}
CONTRIBUTED_TYPES.each do |type|
base = type == 'SwfAsset' ? SwfAsset.object_assets : type.constantize
CONTRIBUTED_BASES[type] = base
end
def self.preload_contributeds_and_parents(contributions)
# Initialize the groups we'll be using for quick access
contributions_by_type = {}
contributed_by_type = {}
contributed_by_type_and_id = {}
needed_ids_by_type = {}
CONTRIBUTED_TYPES.each do |type|
contributions_by_type[type] = []
contributed_by_type[type] = []
contributed_by_type_and_id[type] = {}
needed_ids_by_type[type] = []
end
# Go through the contributions to sort them for future contributed
# assignment, and so we can know what immediate contributed items we'll
# need to look up
contributions.each do |contribution|
type = contribution.contributed_type
contributions_by_type[type] << contribution
needed_ids_by_type[type] << contribution.contributed_id
end
# Load contributed objects without parents, prepare them for easy access
# for future assignment to contributions and looking up parents
CONTRIBUTED_CHILDREN.each do |type|
base = CONTRIBUTED_BASES[type]
base.find(needed_ids_by_type[type]).each do |contributed|
contributed_by_type[type] << contributed
contributed_by_type_and_id[type][contributed.id] = contributed
end
end
# Load both parents of the children we just got, and immediately
# contributed objects of that class. all_by_ids_or_children properly
# assigns parents to children, as well
CONTRIBUTED_RELATIONSHIPS.each do |child_type, type|
base = CONTRIBUTED_BASES[type]
ids = needed_ids_by_type[type]
children = contributed_by_type[child_type]
base.all_by_ids_or_children(ids, children).each do |contributed|
contributed_by_type_and_id[type][contributed.id] = contributed
end
end
# Assign contributed objects to contributions
contributions.each do |contribution|
type = contribution.contributed_type
id = contribution.contributed_id
contribution.contributed = contributed_by_type_and_id[type][id]
end
end
end

View file

@ -149,6 +149,34 @@ class Item < ActiveRecord::Base
@parent_swf_asset_relationships_to_update = rels @parent_swf_asset_relationships_to_update = rels
end end
def self.all_by_ids_or_children(ids, swf_assets)
swf_asset_ids = []
swf_assets_by_id = {}
swf_assets_by_parent_id = {}
swf_assets.each do |swf_asset|
id = swf_asset.id
swf_assets_by_id[id] = swf_asset
swf_asset_ids << id
end
SwfAsset.select('id, parent_id').object_assets.joins(:object_asset_relationships).
where(SwfAsset.arel_table[:id].in(swf_asset_ids)).each do |row|
item_id = row.parent_id.to_i
swf_assets_by_parent_id[item_id] ||= []
swf_assets_by_parent_id[item_id] << swf_assets_by_id[row.id.to_i]
ids << item_id
end
find(ids).tap do |items|
items.each do |item|
swf_assets = swf_assets_by_parent_id[item.id]
if swf_assets
swf_assets.each do |swf_asset|
swf_asset.item = item
end
end
end
end
end
def self.collection_from_pet_type_and_registries(pet_type, info_registry, asset_registry) def self.collection_from_pet_type_and_registries(pet_type, info_registry, asset_registry)
# bear in mind that registries are arrays with many nil elements, # bear in mind that registries are arrays with many nil elements,
# due to how the parser works # due to how the parser works

View file

@ -10,6 +10,16 @@ class PetAttribute < StaticResource
self.name.capitalize self.name.capitalize
end end
def self.find(id)
attribute = super
unless attribute
attribute = new
attribute.id = id
attribute.name = "color \##{id}"
end
attribute
end
def self.find_by_name(name) def self.find_by_name(name)
@objects_by_name[name.downcase] @objects_by_name[name.downcase]
end end

View file

@ -64,6 +64,10 @@ class PetType < ActiveRecord::Base
self['image_hash'] || BasicHashes[species.name][color.name] self['image_hash'] || BasicHashes[species.name][color.name]
end end
def human_name
self.color.human_name + ' ' + self.species.human_name
end
def add_pet_state_from_biology!(biology) def add_pet_state_from_biology!(biology)
pet_state = PetState.from_pet_type_and_biology_info(self, biology) pet_state = PetState.from_pet_type_and_biology_info(self, biology)
self.pet_states << pet_state self.pet_states << pet_state
@ -92,4 +96,24 @@ class PetType < ActiveRecord::Base
end end
end end
end end
def self.all_by_ids_or_children(ids, pet_states)
pet_states_by_pet_type_id = {}
pet_states.each do |pet_state|
id = pet_state.pet_type_id
ids << id
pet_states_by_pet_type_id[id] ||= []
pet_states_by_pet_type_id[id] << pet_state
end
find(ids).tap do |pet_types|
pet_types.each do |pet_type|
pet_states = pet_states_by_pet_type_id[pet_type.id]
if pet_states
pet_states.each do |pet_state|
pet_state.pet_type = pet_type
end
end
end
end
end
end end

View file

@ -3,6 +3,8 @@ class SwfAsset < ActiveRecord::Base
LOCAL_ASSET_DIR = Rails.root.join('public', PUBLIC_ASSET_DIR) LOCAL_ASSET_DIR = Rails.root.join('public', PUBLIC_ASSET_DIR)
set_inheritance_column 'inheritance_type' set_inheritance_column 'inheritance_type'
attr_accessor :item
has_many :object_asset_relationships, :class_name => 'ParentSwfAssetRelationship', has_many :object_asset_relationships, :class_name => 'ParentSwfAssetRelationship',
:conditions => {:swf_asset_type => 'object'} :conditions => {:swf_asset_type => 'object'}
@ -17,6 +19,8 @@ class SwfAsset < ActiveRecord::Base
where(arel_table[:body_id].in(BodyIdsFittingStandard)) where(arel_table[:body_id].in(BodyIdsFittingStandard))
} }
scope :object_assets, where(arel_table[:type].eq('object'))
def local_url def local_url
'/' + File.join(PUBLIC_ASSET_DIR, local_path_within_outfit_swfs) '/' + File.join(PUBLIC_ASSET_DIR, local_path_within_outfit_swfs)
end end

View file

@ -1,6 +1,8 @@
class User < ActiveRecord::Base class User < ActiveRecord::Base
DefaultAuthServerId = 1 DefaultAuthServerId = 1
has_many :contributions
scope :top_contributors, order('points DESC') scope :top_contributors, order('points DESC')
def self.find_or_create_from_remote_auth_data(user_data) def self.find_or_create_from_remote_auth_data(user_data)

View file

@ -0,0 +1,38 @@
body.contributions-index
text-align: center
.contributions
li
list-style: none
height: 80px
overflow: hidden
padding: 1em 0 0 100px
position: relative
text-align: left
.point-value
+header-text
color: #fff
font-size: 80px
left: 0
line-height: 1
position: absolute
text-align: center
text-shadow: 2px 2px 0 #000
top: 0
width: 80px
z-index: 3
&:hover
+opacity(0.5)
img
height: 80px
left: 0
position: absolute
top: 0
width: 80px
z-index: 2
span
&.username, &.contributed-name
font-weight: bold
&.time-ago
display: block
font-size: 75%

View file

@ -4,6 +4,7 @@
@import layout @import layout
@import contributions/index
@import items @import items
@import items/index @import items/index
@import items/show @import items/show

View file

@ -0,0 +1,10 @@
- contributed = contribution.contributed
= content_tag_for :li, contribution do
%span.point-value= contribution.point_value
%span.username
= link_to contribution.user.name, user_contributions_path(contribution.user)
showed us
= contributed_description contributed
%span.time-ago{:title => contribution.created_at.to_s}
= time_ago_in_words(contribution.created_at)
ago

View file

@ -0,0 +1,9 @@
- title 'Recent Contributions'
%ul.buttons
%li= link_to 'Top Contributors', top_contributors_path, :class => 'button'
- if @contributions.empty?
%p No contributions to see here!
- else
= will_paginate @contributions
%ul.contributions= render @contributions
= will_paginate @contributions

View file

@ -1,11 +1,17 @@
!!! 5 !!! 5
%html %html
%head %head
%title Dress to Impress %title
Dress to Impress
- if content_for? :title
&mdash;
= yield :title
= stylesheet_link_tag "compiled/screen" = stylesheet_link_tag "compiled/screen"
= javascript_include_tag "http://#{RemoteImpressHost}/assets/js/analytics.js" = javascript_include_tag "http://#{RemoteImpressHost}/assets/js/analytics.js"
%body{:class => body_class} %body{:class => body_class}
#container #container
- if content_for? :title
%h1#title= yield :title
= yield :before_flashes = yield :before_flashes
= flashes = flashes

View file

@ -86,3 +86,5 @@ Zombie
Onion Onion
Magma Magma
Relic Relic
Woodland
Transparent

View file

@ -367,6 +367,59 @@ dd {
src: local("Droid Sans"), url("http://themes.googleusercontent.com/font?kit=POVDFY-UUf0WFR9DIMCU8g") format("truetype"); src: local("Droid Sans"), url("http://themes.googleusercontent.com/font?kit=POVDFY-UUf0WFR9DIMCU8g") format("truetype");
} }
/* line 1, ../../../app/stylesheets/contributions/_index.sass */
body.contributions-index {
text-align: center;
}
/* line 5, ../../../app/stylesheets/contributions/_index.sass */
body.contributions-index .contributions li {
list-style: none;
height: 80px;
overflow: hidden;
padding: 1em 0 0 100px;
position: relative;
text-align: left;
}
/* line 12, ../../../app/stylesheets/contributions/_index.sass */
body.contributions-index .contributions .point-value {
font-family: Delicious, Helvetica, Arial, Verdana, sans-serif;
color: white;
font-size: 80px;
left: 0;
line-height: 1;
position: absolute;
text-align: center;
text-shadow: 2px 2px 0 black;
top: 0;
width: 80px;
z-index: 3;
}
/* line 24, ../../../app/stylesheets/contributions/_index.sass */
body.contributions-index .contributions .point-value:hover {
-moz-opacity: 0.5;
-webkit-opacity: 0.5;
-o-opacity: 0.5;
-khtml-opacity: 0.5;
}
/* line 26, ../../../app/stylesheets/contributions/_index.sass */
body.contributions-index .contributions img {
height: 80px;
left: 0;
position: absolute;
top: 0;
width: 80px;
z-index: 2;
}
/* line 34, ../../../app/stylesheets/contributions/_index.sass */
body.contributions-index .contributions span.username, body.contributions-index .contributions span.contributed-name {
font-weight: bold;
}
/* line 36, ../../../app/stylesheets/contributions/_index.sass */
body.contributions-index .contributions span.time-ago {
display: block;
font-size: 75%;
}
/* line 1, ../../../app/stylesheets/_items.sass */ /* line 1, ../../../app/stylesheets/_items.sass */
body.items { body.items {
text-align: center; text-align: center;