Compare commits
2 commits
0e32eb5d8f
...
1cfb5129fa
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cfb5129fa | |||
| 903d6a8a19 |
9 changed files with 40 additions and 16 deletions
|
|
@ -754,6 +754,11 @@
|
||||||
contactField.val(connection.id);
|
contactField.val(connection.id);
|
||||||
submitContactForm();
|
submitContactForm();
|
||||||
},
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
var data = JSON.parse(xhr.responseText);
|
||||||
|
var fullMessage = data.full_error_messages.join("\n");
|
||||||
|
alert("Oops, we couldn't save this username!\n\n" + fullMessage);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -218,12 +218,8 @@ class ClosetHangersController < ApplicationController
|
||||||
def enforce_shadowban
|
def enforce_shadowban
|
||||||
# If this user is shadowbanned, and this *doesn't* seem to be a request
|
# If this user is shadowbanned, and this *doesn't* seem to be a request
|
||||||
# from that user, render the 404 page.
|
# from that user, render the 404 page.
|
||||||
if @user.shadowbanned?
|
if !@user.visible_to?(current_user, request.remote_ip)
|
||||||
can_see = support_staff? ||
|
render file: "public/404.html", layout: false, status: :not_found
|
||||||
@user.likely_is?(current_user, request.remote_ip)
|
|
||||||
if !can_see
|
|
||||||
render file: "public/404.html", layout: false, status: :not_found
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ class ItemTradesController < ApplicationController
|
||||||
@type = type_from_params
|
@type = type_from_params
|
||||||
|
|
||||||
@item_trades = @item.closet_hangers.trading.includes(:user, :list).
|
@item_trades = @item.closet_hangers.trading.includes(:user, :list).
|
||||||
user_is_active.order('users.last_trade_activity_at DESC').to_trades
|
user_is_active.order('users.last_trade_activity_at DESC').
|
||||||
|
to_trades(current_user, request.remote_ip)
|
||||||
@trades = @item_trades[@type]
|
@trades = @item_trades[@type]
|
||||||
|
|
||||||
if user_signed_in?
|
if user_signed_in?
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,8 @@ class ItemsController < ApplicationController
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
@trades = @item.closet_hangers.trading.user_is_active.to_trades
|
@trades = @item.closet_hangers.trading.user_is_active.
|
||||||
|
to_trades(current_user, request.remote_ip)
|
||||||
|
|
||||||
@contributors_with_counts = @item.contributors_with_counts
|
@contributors_with_counts = @item.contributors_with_counts
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ class NeopetsConnectionsController < ApplicationController
|
||||||
if connection.save
|
if connection.save
|
||||||
render json: connection
|
render json: connection
|
||||||
else
|
else
|
||||||
render json: {error: 'failure'}, status: :internal_server_error
|
render json: {
|
||||||
|
errors: connection.errors,
|
||||||
|
full_error_messages: connection.errors.map(&:full_message)
|
||||||
|
}, status: :bad_request
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ class ClosetHanger < ApplicationRecord
|
||||||
#
|
#
|
||||||
# We don't preload anything here - if you want user names or list names, you
|
# We don't preload anything here - if you want user names or list names, you
|
||||||
# should `includes` them in the hanger scope first, to avoid extra queries!
|
# should `includes` them in the hanger scope first, to avoid extra queries!
|
||||||
def self.to_trades
|
def self.to_trades(current_user, remote_ip)
|
||||||
# Let's ensure that the `trading` filter is applied, to avoid data leaks.
|
# Let's ensure that the `trading` filter is applied, to avoid data leaks.
|
||||||
# (I still recommend doing it at the call site too for clarity, though!)
|
# (I still recommend doing it at the call site too for clarity, though!)
|
||||||
all_trading_hangers = trading.to_a
|
all_trading_hangers = trading.to_a
|
||||||
|
|
@ -164,17 +164,20 @@ class ClosetHanger < ApplicationRecord
|
||||||
owned_hangers = all_trading_hangers.filter(&:owned?)
|
owned_hangers = all_trading_hangers.filter(&:owned?)
|
||||||
wanted_hangers = all_trading_hangers.filter(&:wanted?)
|
wanted_hangers = all_trading_hangers.filter(&:wanted?)
|
||||||
|
|
||||||
# Group first into offering vs seeking, then by user.
|
# Group first into offering vs seeking, then by user. Only include trades
|
||||||
|
# visible to the current user.
|
||||||
offering, seeking = [owned_hangers, wanted_hangers].map do |hangers|
|
offering, seeking = [owned_hangers, wanted_hangers].map do |hangers|
|
||||||
hangers.group_by(&:user_id).map do |user_id, user_hangers|
|
hangers.group_by(&:user_id).
|
||||||
Trade.new(user_id, user_hangers)
|
map { |user_id, user_hangers| Trade.new(user_id, user_hangers) }.
|
||||||
end
|
filter { |trade| trade.visible_to?(current_user, remote_ip) }
|
||||||
end
|
end
|
||||||
|
|
||||||
{offering: offering, seeking: seeking}
|
{offering: offering, seeking: seeking}
|
||||||
end
|
end
|
||||||
|
|
||||||
Trade = Struct.new('Trade', :user_id, :hangers) do
|
Trade = Struct.new('Trade', :user_id, :hangers) do
|
||||||
|
delegate :visible_to?, to: :user
|
||||||
|
|
||||||
def user
|
def user
|
||||||
# Take advantage of `includes(:user)` on the hangers, if applied.
|
# Take advantage of `includes(:user)` on the hangers, if applied.
|
||||||
hangers.first.user
|
hangers.first.user
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
class NeopetsConnection < ApplicationRecord
|
class NeopetsConnection < ApplicationRecord
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
validates :neopets_username, uniqueness: {scope: :user_id}
|
validates :neopets_username, uniqueness: {scope: :user_id},
|
||||||
|
format: { without: /@/, message: 'must not be an email address, for user safety' }
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,17 @@ class User < ApplicationRecord
|
||||||
touch(:last_trade_activity_at)
|
touch(:last_trade_activity_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def visible_to?(current_user, remote_ip)
|
||||||
|
# Everyone is visible to support staff.
|
||||||
|
return true if current_user&.support_staff?
|
||||||
|
|
||||||
|
# Shadowbanned users are only visible to themselves.
|
||||||
|
return false if shadowbanned? && !likely_is?(current_user, remote_ip)
|
||||||
|
|
||||||
|
# Other than that, users are visible to everyone by default.
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
def self.points_required_to_pass_top_contributor(offset)
|
def self.points_required_to_pass_top_contributor(offset)
|
||||||
user = User.top_contributors.select(:points).limit(1).offset(offset).first
|
user = User.top_contributors.select(:points).limit(1).offset(offset).first
|
||||||
user ? user.points : 0
|
user ? user.points : 0
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@
|
||||||
'data-is-same-as-prev': same_vague_trade_timestamp?(trade, prev_trade)
|
'data-is-same-as-prev': same_vague_trade_timestamp?(trade, prev_trade)
|
||||||
}
|
}
|
||||||
= vague_trade_timestamp trade
|
= vague_trade_timestamp trade
|
||||||
%td= trade.user.name
|
%td
|
||||||
|
= trade.user.name
|
||||||
|
- if support_staff? && trade.user.shadowbanned?
|
||||||
|
%abbr{title: "Shadowbanned (Hidden from most viewers; you can see because you're Support staff"} 🕶️ SBan
|
||||||
%td
|
%td
|
||||||
- if trade.lists.present?
|
- if trade.lists.present?
|
||||||
%ul.trade-list-names
|
%ul.trade-list-names
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue