From 964e6c28ee09be05c8b7650336e5ac9dfc31b9ed Mon Sep 17 00:00:00 2001 From: "Jill \"oatmealine\" Monoids" Date: Mon, 9 Jan 2023 14:18:43 +0300 Subject: [PATCH] basic rank system support --- config.example.toml | 37 ++++++++++++++++ db/migrations/19_user_ranks.sql | 7 +++ src/crystal-gauntlet.cr | 2 + src/lib/ranks.cr | 75 +++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 db/migrations/19_user_ranks.sql create mode 100644 src/lib/ranks.cr diff --git a/config.example.toml b/config.example.toml index fb3e440..acbb3de 100644 --- a/config.example.toml +++ b/config.example.toml @@ -37,6 +37,43 @@ spam_thres = -3 # allow new accounts to be created allow_registration = true +# determine what permissions different ranks of users get +# ranks (based on `position`) will get all perms of +# ranks below (<) their own +# todo: document this fully +[ranks.everyone] +position = 0 +[ranks.everyone.permissions] +upload_levels = true # todo: unimplemented +backup_save = true # todo: unimplemented +level_comment = true # todo: unimplemented +profile_comment = true # todo: unimplemented +leaderboard = true # todo: unimplemented +level_leaderboard = true # todo: unimplemented +send_friend_requests = true # todo: unimplemented +send_messages = true # todo: unimplemented + +reupload_songs = true # todo: unimplemented +reupload_levels = true # todo: unimplemented + +[ranks.mod] +position = 1 +badge = 1 # todo: unimplemented +is_mod = true # can request mod access ingame # todo: unimplemented +text_color = [200, 255, 200] +[ranks.mod.permissions] +rate_levels = true # todo: unimplemented +rate_levels_demon = true # todo: unimplemented + +[ranks.eldermod] +position = 2 +badge = 2 +is_mod = true +text_color = [75, 255, 75] +[ranks.eldermod.permissions] +delete_level_comments = true # todo: unimplemented +delete_others_levels = true # todo: unimplemented + [sessions] # allow sessions to be created (for 1.9, as it # doesn't send the password for authentication diff --git a/db/migrations/19_user_ranks.sql b/db/migrations/19_user_ranks.sql new file mode 100644 index 0000000..6c2f8c5 --- /dev/null +++ b/db/migrations/19_user_ranks.sql @@ -0,0 +1,7 @@ +-- +migrate up +ALTER TABLE accounts DROP COLUMN is_admin; +ALTER TABLE accounts ADD COLUMN rank TEXT; + +-- +migrate down +ALTER TABLE accounts DROP COLUMN rank; +ALTER TABLE accounts ADD COLUMN is_admin INTEGER NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/src/crystal-gauntlet.cr b/src/crystal-gauntlet.cr index 9d54f7d..ed99e8b 100644 --- a/src/crystal-gauntlet.cr +++ b/src/crystal-gauntlet.cr @@ -25,6 +25,7 @@ require "./lib/reupload" require "./lib/creator_points" require "./lib/versions" require "./lib/ips" +require "./lib/ranks" require "./patch-exe.cr" @@ -308,6 +309,7 @@ module CrystalGauntlet check_server_length(false) Reupload.init() + Ranks.init() @@up_at = Time.utc LOG.notice { "Listening on #{listen_on.to_s.colorize(:white)}" } diff --git a/src/lib/ranks.cr b/src/lib/ranks.cr new file mode 100644 index 0000000..860a454 --- /dev/null +++ b/src/lib/ranks.cr @@ -0,0 +1,75 @@ +module CrystalGauntlet::Ranks + extend self + + class Rank + getter name : String + getter position : Int64 = 0 + getter badge : Int64 = 0 + getter is_mod : Bool = false + getter text_color : Array(Int64)? = nil + getter permissions : Hash(String, Bool) = Hash(String, Bool).new + + def initialize(@name, @position = 0, @badge = 0, @is_mod = false, @text_color = nil, @permissions = Hash(String, Bool).new) + end + + def has_permission(key : String) + @permissions[key]? || false + end + end + + NULL_RANK = Rank.new(name: "null", position: -1) + + @@ranks = [] of Rank + + def init() + config_get("ranks").as(Hash(String, TOML::Type)).each() do |key, value_| + value = value_.as(Hash(String, TOML::Type)) + perms = value["permissions"]?.as?(Hash(String, TOML::Type)) || Hash(String, Bool).new + @@ranks << Rank.new( + name: key, + position: value["position"].as(Int64), + badge: value["badge"]?.as?(Int64) || 0_i64, + is_mod: value["is_mod"]?.as?(Bool) || false, + text_color: value["text_color"]?.as?(Array(Int64)), + permissions: perms.transform_values { |v| v.as?(Bool) || false } + ) + end + + if @@ranks.empty? + LOG.error { "Ranks are empty! Things might go very, very wrong" } + end + + @@ranks.sort! { |a, b| a.position <=> b.position } + end + + def get_rank(rank_name : String) : Rank? + @@ranks.find { |r| r.name == rank_name } + end + + def get_rank(account_id : Int32) : Rank + begin + rank_name = DATABASE.query_one("select rank from accounts where id = ?", account_id, as: {String}) + rescue + rank_name = "everyone" + end + + get_rank(rank_name) || @@ranks[0]? || NULL_RANK + end + + def get_permissions(rank : Rank) : Hash(String, Bool) + prev_ranks = @@ranks.select { |i| i.position < rank.position } + prev_ranks << rank + prev_ranks.reduce(Hash(String, Bool).new(false)) { |a, b| a.merge(b.permissions) } + end + + def get_permissions(account_id : Int32) + get_permissions(get_rank(account_id)) + end + + def has_permission(rank : Rank, perm : String) + get_permissions(rank)[perm]? || false + end + def has_permission(account_id : Int32, perm : String) + get_permissions(account_id)[perm]? || false + end +end