diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/alert.rb | 28 | ||||
-rw-r--r-- | app/models/bracket.rb | 50 | ||||
-rw-r--r-- | app/models/bracket_match.rb | 28 | ||||
-rw-r--r-- | app/models/game.rb | 66 | ||||
-rw-r--r-- | app/models/game_setting.rb | 46 | ||||
-rw-r--r-- | app/models/match.rb | 146 | ||||
-rw-r--r-- | app/models/pm.rb | 40 | ||||
-rw-r--r-- | app/models/remote_username.rb | 40 | ||||
-rw-r--r-- | app/models/server.rb | 58 | ||||
-rw-r--r-- | app/models/session.rb | 65 | ||||
-rw-r--r-- | app/models/statistic.rb | 50 | ||||
-rw-r--r-- | app/models/team.rb | 30 | ||||
-rw-r--r-- | app/models/tournament.rb | 203 | ||||
-rw-r--r-- | app/models/tournament_setting.rb | 42 | ||||
-rw-r--r-- | app/models/tournament_stage.rb | 74 | ||||
-rw-r--r-- | app/models/user.rb | 232 |
16 files changed, 1191 insertions, 7 deletions
diff --git a/app/models/alert.rb b/app/models/alert.rb index 0516355..189dfde 100644 --- a/app/models/alert.rb +++ b/app/models/alert.rb @@ -1,3 +1,29 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Alert < ActiveRecord::Base - belongs_to :author + belongs_to :author, class_name: "User" + + def owned_by?(user) + self.author == user + end end diff --git a/app/models/bracket.rb b/app/models/bracket.rb index e8d9c5a..930015a 100644 --- a/app/models/bracket.rb +++ b/app/models/bracket.rb @@ -1,4 +1,54 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Bracket < ActiveRecord::Base belongs_to :user belongs_to :tournament + has_many :bracket_matches + + def owned_by?(tuser) + self.user == tuser + end + + def create_matches + tournament.stages.order(:id).first.matches.order(:id).each do |m| + bracket_matches.create(match: m) + end + end + + + def predict_winners(predictions) + (0..bracket_matches.count-1).each do |i| + bracket_matches.order(:match_id)[i].update(predicted_winner: Team.find(predictions[(i+1).to_s])); + end + return true + end + + + def calcResults + results = Array.new + (0..bracket_matches.count-1).each do |i| + results.push(bracket_matches.order(:match_id)[i].predicted_winner == tournament.stages.order(:id).first.matches.order(:id).winner) + end + return results + end end diff --git a/app/models/bracket_match.rb b/app/models/bracket_match.rb index 823bc40..d6e53c6 100644 --- a/app/models/bracket_match.rb +++ b/app/models/bracket_match.rb @@ -1,5 +1,31 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class BracketMatch < ActiveRecord::Base belongs_to :bracket belongs_to :match - belongs_to :predicted_winner + belongs_to :predicted_winner, class_name: "Team" + + def owned_by?(user) + self.bracket.owned_by?(user) + end end diff --git a/app/models/game.rb b/app/models/game.rb index 13520ac..f27f174 100644 --- a/app/models/game.rb +++ b/app/models/game.rb @@ -1,3 +1,67 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Game < ActiveRecord::Base - belongs_to :parent + belongs_to :parent, class_name: "Game" + + has_many :children, class_name: "Game" + + has_many :game_settings + validates_associated :game_settings + alias_attribute :settings, :game_settings + + validates(:name, + presence: true, + length: {minimum: 5}, + uniqueness: {case_sensitive: true}) + + validates(:min_players_per_team, + presence: true, + numericality: { + only_integer: true, + less_than_or_equal_to: :max_players_per_team, + }) + validates(:max_players_per_team, + presence: true, + numericality: { + only_integer: true, + greater_than_or_equal_to: :min_players_per_team, + }) + + validates(:min_teams_per_match, + presence: true, + numericality: { + only_integer: true, + less_than_or_equal_to: :max_teams_per_match, + }) + validates(:max_teams_per_match, + presence: true, + numericality: { + only_integer: true, + greater_than_or_equal_to: :min_teams_per_match, + }) + + validate :validate_scoring_method + def validate_scoring_method + (not self.scoring_method.try(:empty?)) and (Tournament.scoring_methods.include? scoring_method) + end end diff --git a/app/models/game_setting.rb b/app/models/game_setting.rb index bff8d97..514b57c 100644 --- a/app/models/game_setting.rb +++ b/app/models/game_setting.rb @@ -1,3 +1,49 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class GameSetting < ActiveRecord::Base belongs_to :game + + alias_attribute :value, :default + + validates(:vartype, presence: true, numericality: {only_integer: true}) + validates(:type_opt, presence: true, if: :needs_type_opt?) + + def needs_type_opt? + [ + GameSetting.types[:pick_one_radio], + GameSetting.types[:pick_one_dropdown], + GameSetting.types[:pick_several], + ].include? self.vartype + end + + def self.types + return { + :text_short => 0, + :text_long => 1, + :pick_one_radio => 2, + :pick_several => 3, + :true_false => 4, + :pick_one_dropdown => 5, + } + end end diff --git a/app/models/match.rb b/app/models/match.rb index b5f539b..27c4fbe 100644 --- a/app/models/match.rb +++ b/app/models/match.rb @@ -1,4 +1,148 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Match < ActiveRecord::Base belongs_to :tournament_stage - belongs_to :winner + has_many :statistics + has_and_belongs_to_many :teams + + belongs_to :winner, class_name: "Team" + + # status:integer + before_save { self.status ||= 0 } + + # tournament_stage:references + validates_presence_of :tournament_stage + + # winner:references + # not validated + + def owned_by?(user) + self.tournament_stage.owned_by?(user) + end + + ## + # Returns whether or not all the statistics have been collected + # such that the match may be considered finished. + def finished? + ok = true + self.tournament_stage.scoring.stats_needed(self).each do |stat| + self.users.each do |user| + ok &= self.statistics.where(user: user, name: stat).first + end + end + ok + end + + ## + # Returns all players involved in this match (from all teams). + def users + ret = [] + self.teams.each{|t| ret.concat(t.users)} + return ret + end + + ## + # Given a sampling class (a class that implements the interface + # described in `/lib/sampling/README.md`), this returns which + # statistics (in an Array of Strings) an instance of the class + # should collect. + def stats_from(sampling_class) + figure_sampling_methods.map{|stat,klass| (sampling_class==klass) ? stat : nil}.select{|s| not s.nil?} + end + + ## + # Delagates PUT/PATCH HTTP params to the appropriate sampling + # methods. + def handle_sampling(user, params) + method_classes.each do |klass| + klass.new(self).handle_user_interaction(user, params) + end + end + + ## + # Delagates out rendering forms to the appropriate sampling + # methods. + def render_sampling(user) + require 'set' + html = '' + + method_classes.each do |klass| + html += '<div>' + html += klass.new(self).render_user_interaction(user) + html += '</div>' + end + + return html.html_safe + end + + ## + # Calls `Sampling#start` on every sampling method that this match + # uses. + def start_sampling + method_classes.each do |klass| + klass.new(self).start + end + end + + private + def figure_sampling_methods + if @sampling_methods.nil? + data = {} + needed = self.tournament_stage.scoring.stats_needed(self) + methods_names = self.tournament_stage.tournament.sampling_methods + methods_names.each do |method_name| + method_class = "Sampling::#{method_name.camelcase}".constantize + needed.each do |stat| + data[stat] ||= {} + data[stat][method_class] = method_class.can_get?(stat) + end + end + + needed.each do |stat| + max_val = nil + max_pri = 0 + data[stat].each do |method,priority| + if priority > max_pri + max_val = method + max_pri = priority + end + end + data[stat] = max_val + end + @sampling_methods = data + end + return @sampling_methods + end + + def method_classes + if @method_classes.nil? + data = Set.new + figure_sampling_methods.each do |stat,method| + data.add(method) + end + @method_classes = data + end + return @method_classes + end + end diff --git a/app/models/pm.rb b/app/models/pm.rb index 0e60f3e..31a04b7 100644 --- a/app/models/pm.rb +++ b/app/models/pm.rb @@ -1,5 +1,41 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Pm < ActiveRecord::Base - belongs_to :author - belongs_to :recipient + belongs_to :author, class_name: "User" + belongs_to :recipient, class_name: "User" belongs_to :conversation + + def name + return current_user.name + end + + def owned_by?(user) + self.author == user + end + +=begin + def mailboxer_email(email) + return current_user.email + end +=end end diff --git a/app/models/remote_username.rb b/app/models/remote_username.rb index c477f8a..e952779 100644 --- a/app/models/remote_username.rb +++ b/app/models/remote_username.rb @@ -1,4 +1,42 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class RemoteUsername < ActiveRecord::Base belongs_to :game belongs_to :user -end + + def owned_by?(tuser) + self.user == tuser + end + + def value + begin + return JSON::restore(self.json_value) + rescue + return {} + end + end + + def value=(v) + self.json_value = v.to_json + end +end diff --git a/app/models/server.rb b/app/models/server.rb index 120f0fa..df053ca 100644 --- a/app/models/server.rb +++ b/app/models/server.rb @@ -1,2 +1,60 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Server < ActiveRecord::Base + def default_user_abilities + @abilities ||= User::Abilities.new(DefaultUser.new(self)) + end + def default_user_abilities=(new) + new.each do |k,v| + if v == "0" + v = false + end + default_user_abilities[k] = v + end + end + class DefaultUser + def initialize(server) + @server = server + end + def can?(action) + bit = User.permission_bits[action] + if bit.nil? + return false + else + return (@server.default_user_permissions & bit != 0) + end + end + def add_ability(action) + bit = User.permission_bits[action.to_sym] + unless bit.nil? + @server.default_user_permissions |= bit + end + end + def remove_ability(action) + bit = User.permission_bits[action.to_sym] + unless bit.nil? + @server.default_user_permissions &= ~ bit + end + end + end end diff --git a/app/models/session.rb b/app/models/session.rb index a5fd26e..a85e4fc 100644 --- a/app/models/session.rb +++ b/app/models/session.rb @@ -1,3 +1,68 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Session < ActiveRecord::Base belongs_to :user + + def owned_by?(tuser) + self.user == tuser + end + + ## + # Create a random remember token for the user. This will be + # changed every time the user creates a new session. + # + # If you want this value, hang on to it; the raw value is + # discarded afterward. + # + # By changing the cookie every new session, any hijacked sessions + # (where the attacker steals a cookie to sign in as a certain + # user) will expire the next time the user signs back in. + # + # The random string is of length 16 composed of A-Z, a-z, 0-9 + # This is the browser's cookie value. + def create_token() + t = SecureRandom.urlsafe_base64 + self.token = Session.hash_token(t) + t + end + + ## + # Encrypt the remember token. + # This is the encrypted version of the cookie stored on + # the database. + # + # The reasoning for storing a hashed token is so that even if + # the database is compromised, the attacker won't be able to use + # the remember tokens to sign in. + def Session.hash_token(token) + # SHA-1 (Secure Hash Algorithm) is a US engineered hash + # function that produces a 20 byte hash value which typically + # forms a hexadecimal number 40 digits long. + # The reason I am not using the Bcrypt algorithm is because + # SHA-1 is much faster and I will be calling this on + # every page a user accesses. + # + # https://en.wikipedia.org/wiki/SHA-1 + Digest::SHA1.hexdigest(token.to_s) + end end diff --git a/app/models/statistic.rb b/app/models/statistic.rb index 341fd9d..6a79e99 100644 --- a/app/models/statistic.rb +++ b/app/models/statistic.rb @@ -1,4 +1,54 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Statistic < ActiveRecord::Base belongs_to :user belongs_to :match + + validates(:name, presence: true, length: { minimum: 1 }) + + def value + begin + return JSON::restore(self.json_value) + rescue + return {} + end + end + + def value=(v) + self.json_value = v.to_json + end + + after_save :update_match + def update_match + ActiveRecord::Base.transaction do + if (self.name == "win") and (self.value) + self.match.winner = self.match.teams.find{|t| t.users.include? self.user} + end + if (self.match.status == 2) and (self.match.finished?) + self.match.status = 3 + self.match.tournament_stage.scheduling.finish_match(self.match) + end + self.match.save! + end + end end diff --git a/app/models/team.rb b/app/models/team.rb index fa7ba9e..76ee510 100644 --- a/app/models/team.rb +++ b/app/models/team.rb @@ -1,2 +1,32 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Team < ActiveRecord::Base + has_and_belongs_to_many :matches + has_and_belongs_to_many :users + + alias_attribute :players, :users + + def owned_by?(user) + self.users.include?(user) + end end diff --git a/app/models/tournament.rb b/app/models/tournament.rb index dcdb8d5..b18e359 100644 --- a/app/models/tournament.rb +++ b/app/models/tournament.rb @@ -1,3 +1,206 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class Tournament < ActiveRecord::Base belongs_to :game + + has_many :tournament_stages + # Don't validate presence of stages; sadly, it seems to break things + #validates_presence_of :tournament_stages + alias_attribute :stages, :tournament_stages + + has_many :brackets + + has_many :tournament_settings + + has_and_belongs_to_many :players, class_name: "User", association_foreign_key: "player_id", join_table: "players_tournaments" + + has_and_belongs_to_many :hosts, class_name: "User", association_foreign_key: "host_id", join_table: "hosts_tournaments" + validates_presence_of :hosts + + validates_presence_of :game + + before_save { self.status ||= 0 } + + validates(:name, + presence: true, + length: {minimum: 5}, + uniqueness: {case_sensitive: true}) + + validates(:min_players_per_team, + presence: true, + numericality: { + only_integer: true, + less_than_or_equal_to: :max_players_per_team, + }) + validates(:max_players_per_team, + presence: true, + numericality: { + only_integer: true, + greater_than_or_equal_to: :min_players_per_team, + }) + + validates(:min_teams_per_match, + presence: true, + numericality: { + only_integer: true, + less_than_or_equal_to: :max_teams_per_match, + }) + validates(:max_teams_per_match, + presence: true, + numericality: { + only_integer: true, + greater_than_or_equal_to: :min_teams_per_match, + }) + + validate :validate_scoring_method + def validate_scoring_method + (not self.scoring_method.try(:empty?)) and (scoring_methods.include? scoring_method) + end + + def owned_by?(user) + self.hosts.include?(user) + end + + # Settings ################################################################# + + def settings + @settings ||= Settings.new(self) + end + + def settings=(setting) + setting.each do |key, value| + value = false if value == "0" + settings[key] = value + end + end + + class Settings + def initialize(tournament) + @tournament = tournament + end + + def [](setting_name) + tournament_setting = @tournament.tournament_settings.find{|s|s.name==setting_name} + if tournament_setting.nil? + return nil + else + return tournament_setting.value + end + end + + def []=(setting_name, val) + tournament_setting = @tournament.tournament_settings.find{|s|s.name==setting_name} + if tournament_setting.nil? + game_setting = @tournament.game.settings.find_by_name(setting_name) + @tournament.tournament_settings.build(name: setting_name, value: val, + vartype: game_setting.vartype, + type_opt: game_setting.type_opt, + description: game_setting.description, + display_order: game_setting.display_order) + else + tournament_setting.value = val + end + end + + def keys + @tournament.tournament_settings.all.collect { |x| x.name } + end + + def empty?() keys.empty? end + def count() keys.count end + def length() count end + def size() count end + + def method_missing(name, *args) + if name.to_s.ends_with?('=') + self[name.to_s.sub(/=$/, '').to_s] = args.first + else + return self[name.to_s] + end + end + end + + # Joining/Leaving ########################################################## + + def joinable_by?(user) + return (status==0 and user.can?(:join_tournament) and !players.include?(user)) + end + + def join(user) + unless joinable_by?(user) + return false + end + players.push(user) + end + + def leave(user) + if players.include?(user) && status == 0 + players.delete(user) + end + end + + # Configured methods ####################################################### + + def scoring + @scoring ||= "Scoring::#{self.scoring_method.camelcase}".constantize + end + + # Options for configured methods/modules ################################### + # We're conflicted about whether these should be `self.` or not. ########### + + def self.scoring_methods + make_methods "scoring" + end + def scoring_methods + self.class.scoring_methods + end + + def sampling_methods + self.class.make_methods("sampling").select do |name| + "Sampling::#{name.camelcase}".constantize.works_with?(self.game) + end + end + + def self.scheduling_methods + make_methods "scheduling" + end + def scheduling_methods + self.class.scheduling_methods + end + + def self.seeding_methods + make_methods "seeding" + end + def seeding_methods + self.class.seeding_methods + end + + private + def self.make_methods(dir) + @methods ||= {} + if @methods[dir].nil? or Rails.env.development? + @methods[dir] = Dir.glob("#{Rails.root}/lib/#{dir}/*.rb").map{|filename| File.basename(filename, ".rb") } + end + return @methods[dir] + end end diff --git a/app/models/tournament_setting.rb b/app/models/tournament_setting.rb index b3e6ace..cbf607a 100644 --- a/app/models/tournament_setting.rb +++ b/app/models/tournament_setting.rb @@ -1,3 +1,45 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class TournamentSetting < ActiveRecord::Base belongs_to :tournament + + validates(:vartype, presence: true, numericality: {only_integer: true}) + validates(:type_opt, presence: true, if: :needs_type_opt?) + + def owned_by?(user) + self.tournament.owned_by?(user) + end + + def needs_type_opt? + [ + GameSetting.types[:pick_one_radio], + GameSetting.types[:pick_one_dropdown], + GameSetting.types[:pick_several], + ].include? self.vartype + end + + + def self.types + GameSetting.types + end end diff --git a/app/models/tournament_stage.rb b/app/models/tournament_stage.rb index 205c8cc..4695238 100644 --- a/app/models/tournament_stage.rb +++ b/app/models/tournament_stage.rb @@ -1,3 +1,77 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class TournamentStage < ActiveRecord::Base belongs_to :tournament + validates_presence_of :tournament + + has_many :matches + + validates(:scheduling_method, + presence: true, + inclusion: {in: Tournament.new.scheduling_methods}) + + validates(:seeding_method, + presence: true, + inclusion: {in: Tournament.new.seeding_methods}) + + def owned_by?(user) + self.tournament.owned_by?(user) + end + + # A 1-indexed hash of matches + def matches_ordered + h = {} + i = 1 + self.matches.order(:id).each do |m| + h[i] = m + i += 1 + end + return h + end + + def create_matches + scheduling.create_matches + end + + def to_svg(highlight_user) + return scheduling.graph(highlight_user) + end + + def seed + return seeding.seed.pair(matches, players) + end + + # Accessors to the configured methods + + def scoring + @scoring ||= tournament.scoring + end + + def scheduling + @scheduling ||= "Scheduling::#{self.scheduling_method.camelcase}".constantize.new(self) + end + + def seeding + @seeding ||= "Seeding::#{self.seeding_method.camelcase}".constantize + end end diff --git a/app/models/user.rb b/app/models/user.rb index 4a57cf0..effe166 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,2 +1,234 @@ +# Copyright (C) 2014 Andrew Murrell +# Copyright (C) 2014 Davis Webb +# Copyright (C) 2014 Guntas Grewal +# Copyright (C) 2014 Luke Shumaker +# Copyright (C) 2014 Nathaniel Foy +# Copyright (C) 2014 Tomer Kimia +# +# This file is part of Leaguer. +# +# Leaguer is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Leaguer is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the Affero GNU General Public License +# along with Leaguer. If not, see <http://www.gnu.org/licenses/>. + class User < ActiveRecord::Base + def owned_by?(tuser) + self == tuser + end + ################################################################## + # Relationships # + ################################################################## + has_and_belongs_to_many :tournaments_played, class_name: "Tournament", foreign_key: "player_id", join_table: "players_tournaments" + has_and_belongs_to_many :tournaments_hosted, class_name: "Tournament", foreign_key: "host_id", join_table: "hosts_tournaments" + has_and_belongs_to_many :teams + has_many :sessions + has_many :statistics + has_many :remote_usernames + + ################################################################## + # Attributes # + ################################################################## + + # name:string + validates(:name, presence: true, length: { maximum: 50 }) + + # email:string:uniq + before_save { self.email = email.downcase } + validates(:email, + presence: true, + # This regex is taken from http://www.w3.org/TR/html5/forms.html#e-mail-state-%28type=email%29 + format: { with: /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/ }, + uniqueness: { case_sensitive: false }) + + # user_name:string_uniq + validates(:user_name, + presence: true, + length:{maximum: 50}, + format: {with: /\A[a-zA-Z0-9_-]+\z/}, + uniqueness: {case_sensitive: false }) + + # password_digest:string + has_secure_password validations: false # maps :password and :password_confirmation to :password_digest + validates(:password, + length: { minimum: 6 }, + confirmation: true, + unless: Proc.new { |u| u.password.try(:empty?) and not u.password_digest.try(:empty?) }) + + # permissions:integer + before_save { self.permissions ||= Server.first.default_user_permissions } + + ################################################################## + # XXX: hard-coded-ish. It makes me feel dirty. # + ################################################################## + apply_simple_captcha + acts_as_messageable + def mailboxer_email(object) + return nil + end + + ################################################################## + # remote_usernames # + ################################################################## + + def set_remote_username(game, data) + remote = self.remote_usernames.where(:game => game).first + if remote.nil? + self.remote_usernames.create(game: game, value: data) + else + remote.value = data + remote.save + end + end + + def get_remote_username(game) + obj = self.remote_usernames.where(:game => game).first + if obj.nil? + if game.parent.nil? + return nil + else + return get_remote_username(game.parent) + end + else + return obj.value + end + end + + ################################################################## + # Permissions # + ################################################################## + + def self.permission_bits + return { + :create_tournament => (2**1), + :edit_tournament => (2**2), + :join_tournament => (2**3), + :delete_tournament => (2**4), + + :create_game => (2**5), + :edit_game => (2**6), + :delete_game => (2**7), + + :create_user => (2**8), + :edit_user => (2**9), + :delete_user => (2**10), + + :create_alert => (2**11), + :edit_alert => (2**12), + :delete_alert => (2**13), + + :create_pm => (2**14), + :edit_pm => (2**15), + :delete_pm => (2**16), + + :create_session => (2**17), + :delete_session => (2**18), + + :edit_permissions => (2**19), + :edit_server => (2**20), + + :create_bracket => (2**21), + :edit_bracket => (2**22), + :delete_bracket => (2**23) + } + end + + def can?(action) + bit = User.permission_bits[action] + if bit.nil? + return false + else + return (self.permissions & bit != 0) + end + end + + def add_ability(action) + bit = User.permission_bits[action.to_sym] + unless bit.nil? + self.permissions |= bit + end + end + + def remove_ability(action) + bit = User.permission_bits[action.to_sym] + unless bit.nil? + self.permissions &= ~ bit + end + end + + # A representation of the permission bits as a mock-array. + def abilities + @abilities ||= Abilities.new(self) + end + def abilities=(new) + new.each do |k,v| + if v == "0" + v = false + end + abilities[k] = v + end + end + + # A thin array-like wrapper around the permission bits to make it + # easy to modify them using a form. + class Abilities + def initialize(user) +o @user = user + end + def [](ability) + return @user.can?(ability) + end + def []=(ability, val) + if val + @user.add_ability(ability) + else + @user.remove_ability(ability) + end + end + def keys + User.permission_bits.keys + end + def method_missing(name, *args) + if name.to_s.ends_with?('=') + self[name.to_s.sub(/=$/, '').to_sym] = args.first + else + return self[name.to_sym] + end + end + end + + ################################################################## + # Null-object pattern # + ################################################################## + + class NilUser + def nil? + return true + end + def can?(action) + case action + when :create_user + return true + when :create_session + return true + else + return false + end + end + def method_missing(name, *args) + # Throw an error if User doesn't have this method + super unless User.new.respond_to?(name) + # User has this method -- return a blank value + # 'false' if the method ends with '?'; 'nil' otherwise. + name.to_s.ends_with?('?') ? false : nil + end + end end |