contributions viewing
This commit is contained in:
parent
db56b0d218
commit
a5b119a9bc
16 changed files with 323 additions and 1 deletions
7
app/controllers/contributions_controller.rb
Normal file
7
app/controllers/contributions_controller.rb
Normal 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
|
|
@ -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
|
||||||
|
|
40
app/helpers/contribution_helper.rb
Normal file
40
app/helpers/contribution_helper.rb
Normal 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
|
84
app/models/contribution.rb
Normal file
84
app/models/contribution.rb
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
38
app/stylesheets/contributions/_index.sass
Normal file
38
app/stylesheets/contributions/_index.sass
Normal 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%
|
|
@ -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
|
||||||
|
|
10
app/views/contributions/_contribution.html.haml
Normal file
10
app/views/contributions/_contribution.html.haml
Normal 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
|
9
app/views/contributions/index.html.haml
Normal file
9
app/views/contributions/index.html.haml
Normal 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
|
|
@ -1,11 +1,17 @@
|
||||||
!!! 5
|
!!! 5
|
||||||
%html
|
%html
|
||||||
%head
|
%head
|
||||||
%title Dress to Impress
|
%title
|
||||||
|
Dress to Impress
|
||||||
|
- if content_for? :title
|
||||||
|
—
|
||||||
|
= 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
|
||||||
|
|
||||||
|
|
|
@ -86,3 +86,5 @@ Zombie
|
||||||
Onion
|
Onion
|
||||||
Magma
|
Magma
|
||||||
Relic
|
Relic
|
||||||
|
Woodland
|
||||||
|
Transparent
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue