Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ gem "pundit", "~> 1.1.0"
gem "recaptcha", require: "recaptcha/rails"
gem "loofah", "<= 2.20.0"
gem "whenever", require: false # for cron jobs
gem "squeel" # , '~> 1.1.1' # until version 1.1.2 released
gem "tilt"
gem "simple-navigation", "3.11.0"
gem "simple_form", "3.2.1"
Expand Down
7 changes: 0 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,6 @@ GEM
pdfkit (0.8.2)
pg (0.21.0)
pkg-config (1.5.1)
polyamorous (1.1.0)
activerecord (>= 3.0)
prawn (2.2.2)
pdf-core (~> 0.7.0)
ttfunk (~> 1.5)
Expand Down Expand Up @@ -363,10 +361,6 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
squeel (1.2.3)
activerecord (>= 3.0)
activesupport (>= 3.0)
polyamorous (~> 1.1.0)
ssrf_filter (1.0.8)
standard (1.0.5)
rubocop (= 1.12.1)
Expand Down Expand Up @@ -468,7 +462,6 @@ DEPENDENCIES
simplecov
sinatra
spring
squeel
standard
strong_presenter (~> 0.2.2)
superfish-rails (~> 1.6.0)
Expand Down
19 changes: 15 additions & 4 deletions app/controllers/contests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,24 @@ def browse
case params[:filter].to_s
when "active"
raise Pundit::NotAuthorizedError unless user_signed_in?
@contests = Contest.joins(:contest_relations).where { (contest_relations.user_id == my { current_user.id }) & (contest_relations.finish_at > Time.now) }.order("end_time ASC")
@contests = Contest
.joins(:contest_relations)
.where(contest_relations: { user_id: current_user.id })
.where("contest_relations.finish_at > ?", Time.now)
.order("end_time ASC")
when "current"
@contests = visible_contests.where { (start_time < Time.now + 30.minutes) & (end_time > Time.now) }.order("end_time ASC")
@contests = visible_contests
.where("start_time < ?", Time.now + 30.minutes)
.where("end_time > ?", Time.now)
.order("end_time ASC")
when "upcoming"
@contests = visible_contests.where { (start_time > Time.now + 30.minutes) }.order("start_time ASC")
@contests = visible_contests
.where("start_time > ?", Time.now + 30.minutes)
.order("start_time ASC")
when "past"
@contests = visible_contests.where { (end_time < Time.now) }.order("end_time DESC")
@contests = visible_contests
.where("end_time < ?", Time.now)
.order("end_time DESC")
else
raise Pundit::NotAuthorizedError
end
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/groups/members_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ def invites
redirect_to(invites_members_group_path(@group), notice: "#{@user.username} has been invited to join this group")
end
else # get request
@pending_requests = @group.invitations.pending.order(:created_at).reverse_order
@requests = @group.invitations.closed.order(:created_at).reverse_order
@pending_requests = @group.invitations.merge(Request.pending).order(created_at: :desc)
@requests = @group.invitations.merge(Request.closed).order(created_at: :desc)
end
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ class HomeController < ApplicationController
def home
@mygroups = current_user.try(:groups)
@problem_set_associations = Group.find(0).problem_set_associations
@contests = policy_scope(Contest).where { (end_time > Time.now) }.order("end_time ASC")
@contests = policy_scope(Contest).not_ended.order("end_time ASC")
end
end
8 changes: 7 additions & 1 deletion app/controllers/problems_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ def submissions
if current_user.openbook?
@submissions = @problem.submission_history(current_user)
else
start_time = current_user.contest_relations.joins(contest: {problem_set: :problems}).where { (started_at <= DateTime.now) & (finish_at > DateTime.now) & (contest.problem_set.problems.id == my { params[:id] }) }.minimum(:started_at)
start_time = current_user
.contest_relations
.joins(contest: {problem_set: :problems})
.where("started_at <= :now AND finish_at > :now", now: DateTime.now)
.where(problems: {id: params[:id]})
.minimum(:started_at)

@submissions = @problem.submission_history(current_user, start_time)
end

Expand Down
7 changes: 6 additions & 1 deletion app/controllers/user_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ def permitted_params
def show
@user = User.find(params[:id])
authorize @user, :show?
@solved_problems = @user.user_problem_relations.where(ranked_score: 100).joins(:problem).select([:problem_id, :ranked_submission_id, {problem: :name}]).order("problems.name")
@solved_problems = @user
.user_problem_relations
.where(ranked_score: 100)
.joins(:problem)
.select("problems.name", "problem_id", "ranked_submission_id")
.order("problems.name")
end

def edit
Expand Down
3 changes: 3 additions & 0 deletions app/models/contest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class Contest < ActiveRecord::Base
# public = everyone, protected = in group, private = competitors
OBSERVATION = Enumeration.new 0 => :public, 1 => :protected, 2 => :private

scope :not_ended, -> { where("end_time > ?", Time.current) }
scope :publicly_observable, -> { where(observation: OBSERVATION[:public]) }

before_save do # update the end time that was cached
if duration_changed? || end_time_changed?
contest_relations.find_each do |relation|
Expand Down
2 changes: 1 addition & 1 deletion app/models/contest_relation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ContestRelation < ActiveRecord::Base
belongs_to :school
belongs_to :supervisor, class_name: :User

scope :active, -> { where { (started_at <= DateTime.now) & (finish_at > DateTime.now) } }
scope :active, -> { where("started_at <= :now AND finish_at > :now", now: DateTime.now) }
scope :absent, -> { where(checked_in: false) }
scope :user, ->(u_id) { where(user_id: u_id) }

Expand Down
5 changes: 4 additions & 1 deletion app/models/contest_supervisor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ def contest_relations

def potential_contestants
if site_type == "School"
User.where { |user| (user.school_id == site_id) & ((user.school_graduation >= contest.end_time) | ((user.school_graduation.nil?) & (user.created_at >= DateTime.now.advance(years: -1)))) & (user.id << contest.registrants) }
User
.where(school_id: site_id)
.where("(users.school_graduation >= :contest_end_time) OR ((users.school_graduation IS NULL) AND (users.created_at >= :year_ago))", contest_end_time: contest.end_time, year_ago: DateTime.now.advance(years: -1))
.where.not(id: contest.registrants)
else
[] # not implemented
end
Expand Down
14 changes: 11 additions & 3 deletions app/models/problem_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ class ProblemSet < ActiveRecord::Base
validates :name, presence: true

def problems_with_scores_by_user(user_id)
problems.joins("LEFT OUTER JOIN user_problem_relations ON user_problem_relations.problem_id = problems.id AND user_problem_relations.user_id = #{user_id} LEFT OUTER JOIN submissions ON submissions.id = user_problem_relations.submission_id").select([:id, :name, :test_error_count, :test_warning_count, :test_status, {submissions: [:points, :maximum_points], problem_set_problems: :weighting}])
problems
.joins("LEFT OUTER JOIN user_problem_relations ON user_problem_relations.problem_id = problems.id AND user_problem_relations.user_id = #{user_id} LEFT OUTER JOIN submissions ON submissions.id = user_problem_relations.submission_id")
.select(
"id", "name", "test_error_count", "test_warning_count", "test_status", "submissions.points", "submissions.maximum_points", "problem_set_problems.weighting"
)
end

def for_contestant? u_id
contests.joins(:contest_relations).where(contest_relations: {user_id: u_id}).where { {contest_relations => sift(:active)} }.any?
def for_contestant?(u_id)
contests
.joins(:contest_relations)
.where(contest_relations: {user_id: u_id})
.merge(ContestRelation.active)
.any?
end

def for_owner? u_id
Expand Down
20 changes: 17 additions & 3 deletions app/models/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,23 @@ class Request < ActiveRecord::Base
status == key
end
end
scope :pending, -> { where { (status == STATUS[:pending]) & (expired_at > DateTime.now) } }
scope :expired, -> { where { (status == STATUS[:pending]) & (expired_at <= DateTime.now) } }
scope :closed, -> { where { (status != STATUS[:pending]) | (expired_at <= DateTime.now) } }

# I would prefer to just use expired and not_expired, but these
# names are in used below for a slightly different use.
scope :past_expiry, -> { where("expired_at <= ?", DateTime.now) }
scope :not_past_expiry, -> { where("expired_at > ?", DateTime.now) }

# IMO a better name for this would be "pending", but see below
scope :status_pending, -> { where(status: STATUS[:pending]) }

# These scopes have weird names.
# * Pending is redefined a scope defined above.
# * Expired you wouldn't usually expect to check status
scope :pending, -> { status_pending.merge(not_past_expiry) }
scope :expired, -> { status_pending.merge(past_expiry) }

# TODO(Rails5): Convert to where.not(pending).or(past_expiry)
scope :closed, -> { where("status != ? OR expired_at <= ?", STATUS[:pending], DateTime.now) }

def pending?
status == STATUS[:pending] && (expired_at == Float::INFINITY || expired_at > DateTime.now)
Expand Down
59 changes: 37 additions & 22 deletions app/policies/contest_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@ def resolve
return scope.all
end

# following uses advanced squeel
scope.where do |contests|
public_observation = contests.observation == Contest::OBSERVATION[:public]
grouped = contests.id.in(GroupContest.where do |gc|
group_contests = (gc.group_id == 0)
group_contests |= (gc.group_id >> user.groups.select(:id)) if user
group_contests
end.select(:contest_id))
visible_contests = public_observation | grouped

if user
registered = contests.id.in(user.contest_relations.select(:contest_id))
owned = contests.owner_id == user.id
supervising = contests.id.in(user.contest_supervising.select(:contest_id))
visible_contests |= registered | owned | supervising
end

visible_contests
end
sql = <<~SQL
contests.observation = :public
OR contests.id IN (
SELECT
contest_id
FROM
group_contests
WHERE
group_id = 0
OR group_id IN (:user_groups)
)
OR contests.id IN (:allowed_contest_ids)
OR contests.owner_id = :user_id
SQL

allowed_contest_ids = []
allowed_contest_ids = user.contest_relations.pluck(:contest_id) + user.contest_supervising.pluck(:contest_id) if user

scope.where(sql, {
public: Contest::OBSERVATION[:public],
user_groups: user&.groups&.pluck(:id),
allowed_contest_ids: allowed_contest_ids,
user_id: user&.id,
})
end
end

Expand All @@ -34,12 +39,22 @@ def registered?

def current_contestant?
return false unless user # signed in
record.contest_relations.where { |relation| (relation.user_id == user.id) & (relation.started_at <= DateTime.now) & (relation.finish_at > DateTime.now) }.exists?

record
.contest_relations
.where(user_id: user.id)
.where("started_at <= :now AND finish_at > :now", DateTime.now)
.exists?
end

def current_or_past_contestant?
return false unless user # signed in
record.contest_relations.where { |relation| (relation.user_id == user.id) & (relation.started_at <= DateTime.now) }.exists?

record
.contest_relations
.where(user_id: user.id)
.where("started_at <= ?", DateTime.now)
.exists?
end

def index?
Expand Down Expand Up @@ -87,7 +102,7 @@ def unfinalize?

def startable?
return false unless user # signed in
user.is_staff? or registered? or record.groups.where(id: 0).exists? or record.groups.joins(:memberships).where(memberships: {member_id: user.id}).exists?
user.is_staff? || registered? || record.groups.where(id: 0).exists? || record.groups.joins(:memberships).where(group_memberships: { member_id: user.id }).exists?
end

def start?
Expand Down
6 changes: 5 additions & 1 deletion app/policies/group_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ def resolve(source = nil)
if user.is_staff?
scope.all
else
scope.where { |groups| (groups.id == 0) | (groups.visibility == Group::VISIBILITY[:public]) | (groups.owner_id == user.id) }
scope.where(
"id = 0 OR visibility = :public OR owner_id = :user_id",
public: Group::VISIBILITY[:public],
user_id: user.id
)
end
end
end
Expand Down
13 changes: 11 additions & 2 deletions app/policies/problem_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,21 @@ def show?
return true if user && user.is_staff?

if user && user.competing?
return record.contest_relations.where { |relation| (relation.user_id == user.id) & (relation.started_at <= DateTime.now) & (relation.finish_at > DateTime.now) }.exists?
return record
.contest_relations
.where(contest_relations: { user_id: user.id })
.where("started_at <= :now AND finish_at > :now", now: DateTime.now)
.exists?
end

return true if record.groups.where(id: 0).exists?
return false unless user # signed in
user.owns(record) or record.group_memberships.where { |membership| (membership.member_id == user.id) }.exists?
return true if user.owns(record)

record
.group_memberships
.where(group_memberships: { member_id: user.id })
.exists?
end

def access?
Expand Down
10 changes: 7 additions & 3 deletions app/policies/problem_set_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ def manage?
def show?
return true if user && user.is_staff?
if user && user.competing?
return user.contest_relations.where { |relation| (relation.started_at <= DateTime.now) & (relation.finish_at > DateTime.now) & (relation.contest_id >> record.contest_ids) }.exists?
return user
.contest_relations
.where("started_at <= :now AND finish_at > :now", now: DateTime.now)
.where("contest_relations.contest_id IN (:contest_ids)", contest_ids: record.contest_ids)
.exists?
end

return true if record.groups.where(id: 0).exists?
return false unless user # signed in
user.owns(record) or record.group_memberships.where { |membership| (membership.member_id == user.id) }.exists?
user.owns(record) || record.group_memberships.where(member_id: user.id).exists?
end

def create?
return false unless user # signed in
super or user.is_staff? or user.is_any?([:organiser, :author])
super || user.is_staff? || user.is_any?([:organiser, :author])
end
end
2 changes: 1 addition & 1 deletion app/policies/request_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ def resolve
if user.is_admin?
scope.all
else
scope.where { (requester_id == user.id) | (requestee_id == user.id) }
scope.where("requester_id = :user_id OR requestee_id = :user_id", user_id: user.id)
end
end
end
Expand Down
23 changes: 17 additions & 6 deletions app/policies/submission_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,39 @@ def resolve
if user.is_staff?
scope.all
elsif user.competing?
problem_set_ids = ContestRelation.where { |contest_relations| (contest_relations.user_id == user.id) & (contest_relations.started_at <= DateTime.now) & (contest_relations.finish_at > DateTime.now) }.joins(:contest).select(contest: :problem_set_id)
scope.joins(problem: :problem_sets).where(problem: {problem_sets: {id: problem_set_ids}}, user_id: user.id)
problem_set_ids = ContestRelation
.where(user_id: user.id)
.where("contest_relations.started_at <= ?", DateTime.now)
.where("contest_relations.finish_at > ?", DateTime.now)
.joins(:contest)
.select("contests.problem_set_id")

scope
.joins(problem: :problem_sets)
.where(user_id: user.id)
.where(problem_sets: {id: problem_set_ids})
else
scope.joins(:problem).where { |submission| (submission.user_id == user.id) | (submission.problem.owner_id == user.id) }
scope
.joins(:problem)
.where("submissions.user_id = :user_id OR problems.owner_id = :user_id", user_id: user.id)
end
end
end

def inspect?
super or (record.is_a?(Submission) && policy(record.problem).try(:inspect?) && !user.competing?)
super || (record.is_a?(Submission) && policy(record.problem).try(:inspect?) && !user.competing?)
end

def update?
super or (record.is_a?(Submission) && policy(record.problem).try(:update?) && !user.competing?)
super || (record.is_a?(Submission) && policy(record.problem).try(:update?) && !user.competing?)
end

def index?
true
end

def show?
inspect? or scope.where(id: record.id).exists?
inspect? || scope.where(id: record.id).exists?
end

def rejudge?
Expand Down
Loading