diff --git a/.sqlfluff b/.sqlfluff index a9b2870..0a33ea9 100644 --- a/.sqlfluff +++ b/.sqlfluff @@ -1,3 +1,5 @@ [sqlfluff] dialect = mariadb max_line_length = 100 +exlude_rules = PRS +ignore = parsing diff --git a/Dockerfile b/Dockerfile index 80d87a2..8b12385 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,23 +4,24 @@ FROM mariadb:11.5.2 # Set environment variables ENV TZ=America/Montreal -# Create a new user and group with limited privileges -RUN groupadd -r mariadbuser && useradd -r -g mariadbuser mariadbuser +# Create a non-root user and group +RUN groupadd -r dbuser && useradd -r -g dbuser dbuser -# Copy SQL files from the repository root into the container +# Copy SQL files and set ownership COPY create_database.sql /docker-entrypoint-initdb.d/ COPY create_tables.sql /docker-entrypoint-initdb.d/ -# COPY create_get_procedures.sql /docker-entrypoint-initdb.d/ +COPY create_get_procedures.sql /docker-entrypoint-initdb.d/ +RUN chown -R dbuser:dbuser /docker-entrypoint-initdb.d -# Adjust permissions on database init files and directories -RUN chown -R mariadbuser:mariadbuser /docker-entrypoint-initdb.d +# Ensure proper permissions for MariaDB directories +RUN chown -R dbuser:dbuser /var/lib/mysql /etc/mysql # Expose the default MariaDB port (3306) EXPOSE 3306 -# Switch to the new user -USER mariadbuser - # Add health check for the container HEALTHCHECK --interval=1m --timeout=10s --start-period=30s --retries=3 \ CMD mysqladmin ping -h localhost || exit 1 + +# Switch to the non-root user +USER dbuser diff --git a/create_get_procedures.sql b/create_get_procedures.sql new file mode 100644 index 0000000..bd1a3f7 --- /dev/null +++ b/create_get_procedures.sql @@ -0,0 +1,232 @@ +-- Use the database +USE 0ce; + +-- Player Procedures + +DELIMITER // + +CREATE OR REPLACE PROCEDURE get_all_players() +BEGIN + SELECT player_id, player_name, email, gold, created_at, last_login + FROM player; +END // + +CREATE OR REPLACE PROCEDURE get_player_by_id(IN p_player_id INT) +BEGIN + SELECT player_id, player_name, email, gold, created_at, last_login + FROM player + WHERE player_id = p_player_id; +END // + +-- This procedure is used to check if an email already exists in the database +CREATE OR REPLACE PROCEDURE get_player_by_email(IN p_email VARCHAR(100), OUT email_exists BOOLEAN) +BEGIN + SELECT EXISTS(SELECT 1 FROM player WHERE email = p_email) INTO email_exists; +END // + +CREATE OR REPLACE PROCEDURE get_player_by_name(IN p_player_name VARCHAR(100)) +BEGIN + SELECT player_id, player_name, email, gold, created_at, last_login + FROM player + WHERE player_name = p_player_name; +END // + +CREATE OR REPLACE PROCEDURE get_player_worlds(IN p_player_id INT) +BEGIN + SELECT w.world_id, w.world_name, w.world_description, w.created_at + FROM world w + JOIN player_world pw ON w.world_id = pw.world_id + WHERE pw.player_id = p_player_id; +END // + +CREATE OR REPLACE PROCEDURE get_player_cities(IN p_world_id INT, IN p_player_id INT) +BEGIN + SELECT c.city_id, c.city_name, c.x, c.y, c.island_id + FROM city c + JOIN world w ON c.world_id = w.world_id + WHERE c.owner_id = p_player_id + AND w.world_id = p_world_id; +END // + +CREATE OR REPLACE PROCEDURE get_player_battles(IN p_player_id INT) +BEGIN + SELECT battle_id, attacker_id, defender_id, battle_time, winner_id, loser_id, loot_wood, + loot_stone, loot_silver + FROM battle + WHERE attacker_id = p_player_id OR defender_id = p_player_id; +END // + +-- World Procedures + +CREATE OR REPLACE PROCEDURE get_all_worlds() +BEGIN + SELECT world_id, world_name, world_description, seed, action_speed, unit_speed, trade_speed, + night_bonus, beginner_protection, morale, world_status, created_at + FROM world; +END // + +CREATE OR REPLACE PROCEDURE get_world_by_id(IN p_world_id INT) +BEGIN + SELECT world_id, world_name, world_description, seed, action_speed, unit_speed, trade_speed, + night_bonus, beginner_protection, morale, world_status, created_at + FROM world + WHERE world_id = p_world_id; +END // + +CREATE OR REPLACE PROCEDURE get_active_worlds() +BEGIN + SELECT world_id, world_name, world_description, created_at + FROM world + WHERE world_status = 1; +END // + +CREATE OR REPLACE PROCEDURE get_players_in_world(IN p_world_id INT) +BEGIN + SELECT p.player_id, p.player_name, p.email, p.gold, p.created_at + FROM player p + JOIN p_player_world pw ON p.player_id = pw.player_id + WHERE pw.world_id = p_world_id; +END // + +CREATE OR REPLACE PROCEDURE get_islands_in_world(IN p_world_id INT) +BEGIN + SELECT island_id, x, y + FROM island + WHERE world_id = p_world_id; +END // + +CREATE OR REPLACE PROCEDURE get_cities_in_world(IN p_world_id INT) +BEGIN + SELECT c.city_id, c.city_name, c.x, c.y, c.owner_id, c.island_id + FROM city c + JOIN island i ON c.island_id = i.island_id + WHERE i.world_id = p_world_id; +END // + +-- Island Procedures + +CREATE OR REPLACE PROCEDURE get_all_islands() +BEGIN + SELECT island_id, x, y, world_id + FROM island; +END // + +CREATE OR REPLACE PROCEDURE get_island_by_id(IN p_island_id INT) +BEGIN + SELECT island_id, x, y, world_id + FROM island + WHERE island_id = p_island_id; +END // + +CREATE OR REPLACE PROCEDURE get_island_cities(IN p_island_id INT) +BEGIN + SELECT city_id, city_name, x, y, owner_id + FROM city + WHERE island_id = p_island_id; +END // + +-- City Procedures + +CREATE OR REPLACE PROCEDURE get_all_cities() +BEGIN + SELECT city_id, city_name, x, y, island_id, owner_id + FROM city; +END // + +CREATE OR REPLACE PROCEDURE get_city_by_id(IN p_city_id INT) +BEGIN + SELECT city_id, city_name, x, y, island_id, owner_id + FROM city + WHERE id = p_city_id; +END // + +CREATE OR REPLACE PROCEDURE get_city_buildings(IN p_city_id INT) +BEGIN + SELECT building_id, building_name, building_level, max_level + FROM building + WHERE city_id = p_city_id; +END // + +CREATE OR REPLACE PROCEDURE get_city_units(IN p_city_id INT) +BEGIN + SELECT u.unit_id, u.unit_name, cu.quantity + FROM unit u + JOIN city_unit cu ON u.unit_id = cu.unit_id + WHERE cu.city_id = p_city_id; +END // + +-- Building Procedures + +CREATE OR REPLACE PROCEDURE get_all_buildings() +BEGIN + SELECT building_id, building_name, building_level, max_level, city_id + FROM building; +END // + +CREATE OR REPLACE PROCEDURE get_building_by_id(IN p_building_id INT) +BEGIN + SELECT building_id, building_name, building_level, max_level, city_id + FROM building + WHERE id = p_building_id; +END // + +CREATE OR REPLACE PROCEDURE get_building_prerequisites(IN p_building_id INT) +BEGIN + SELECT prerequisite_id + FROM building_prerequisite + WHERE building_id = p_building_id; +END // + +-- Unit Procedures + +CREATE OR REPLACE PROCEDURE get_all_units() +BEGIN + SELECT unit_id, unit_name, unit_description, unit_type, wood_cost, stone_cost, silver_cost, + population_cost, training_time, damage, defense_blunt, defense_distance, defense_sharp, + speed, can_fly + FROM unit; +END // + +CREATE OR REPLACE PROCEDURE get_unit_by_id(IN p_unit_id INT) +BEGIN + SELECT unit_id, unit_name, unit_description, unit_type, wood_cost, stone_cost, silver_cost, + population_cost, training_time, damage, defense_blunt, defense_distance, defense_sharp, + speed, can_fly + FROM unit + WHERE id = p_unit_id; +END // + +-- Battle Procedures + +CREATE OR REPLACE PROCEDURE get_all_battles() +BEGIN + SELECT battle_id, attacker_id, defender_id, battle_time, winner_id, loser_id, loot_wood, + loot_stone, loot_silver + FROM battle; +END // + +CREATE OR REPLACE PROCEDURE get_battle_by_id(IN p_battle_id INT) +BEGIN + SELECT battle_id, attacker_id, defender_id, battle_time, winner_id, loser_id, loot_wood, + loot_stone, loot_silver + FROM battle + WHERE battle_id = p_battle_id; +END // + +CREATE OR REPLACE PROCEDURE get_battle_units(IN p_battle_id INT) +BEGIN + SELECT unit_id, quantity, side + FROM battle_unit + WHERE battle_id = p_battle_id; +END // + +-- Miscellaneous Procedures + +CREATE OR REPLACE PROCEDURE get_building_requirements(IN p_building_id INT) +BEGIN + SELECT required_wood, required_stone, required_silver, required_population + FROM building_requirement + WHERE building_id = p_building_id; +END // + +DELIMITER ; diff --git a/create_tables.sql b/create_tables.sql index c8d4a2a..6ae28cc 100644 --- a/create_tables.sql +++ b/create_tables.sql @@ -3,10 +3,10 @@ USE 0ce; CREATE TABLE IF NOT EXISTS player ( player_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, - player_name VARCHAR(100), - email VARCHAR(100) UNIQUE, + player_name VARCHAR(100) UNIQUE NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, hashed_password VARBINARY(255) NOT NULL, - salt VARBINARY(16), + salt VARBINARY(16) NOT NULL, gold INT DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP @@ -14,17 +14,16 @@ CREATE TABLE IF NOT EXISTS player ( CREATE TABLE IF NOT EXISTS world ( world_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, - world_name VARCHAR(100), + world_name VARCHAR(100) UNIQUE NOT NULL, world_description TEXT, - seed INT NOT NULL, - action_speed INT DEFAULT 1 NOT NULL, - unit_speed INT DEFAULT 1 NOT NULL, - trade_speed INT DEFAULT 1 NOT NULL, - night_bonus INT DEFAULT 0 NOT NULL, - beginner_protection INT DEFAULT 0 NOT NULL, - morale BOOL DEFAULT FALSE NOT NULL, - alliance_cap INT DEFAULT 0 NOT NULL, - world_status TINYINT DEFAULT 1 NOT NULL, + seed INT, + action_speed TINYINT UNSIGNED DEFAULT 1, + unit_speed TINYINT UNSIGNED DEFAULT 1, + trade_speed TINYINT UNSIGNED DEFAULT 1, + night_bonus INT DEFAULT 0, + beginner_protection INT DEFAULT 0, + morale BOOL DEFAULT FALSE, + world_status TINYINT DEFAULT 2, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE = InnoDB; @@ -51,8 +50,10 @@ CREATE TABLE IF NOT EXISTS city ( x INT NOT NULL, y INT NOT NULL, owner_id INT UNSIGNED NOT NULL, + world_id INT UNSIGNED NOT NULL, FOREIGN KEY (island_id) REFERENCES island (island_id), - FOREIGN KEY (owner_id) REFERENCES player (player_id) + FOREIGN KEY (owner_id) REFERENCES player (player_id), + FOREIGN KEY (world_id) REFERENCES world (world_id) ) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS building ( @@ -82,7 +83,7 @@ CREATE TABLE IF NOT EXISTS building_prerequisite ( ) ENGINE = InnoDB; CREATE TABLE IF NOT EXISTS unit ( - unit_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, + unit_id TINYINT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, unit_name VARCHAR(100), unit_description TEXT, unit_type TINYINT NOT NULL, @@ -91,7 +92,7 @@ CREATE TABLE IF NOT EXISTS unit ( silver_cost INT DEFAULT 0 NOT NULL, population_cost INT DEFAULT 0 NOT NULL, training_time INT DEFAULT 0 NOT NULL, - damage INT DEFAULT 1 NOT NULL, + damage INT DEFAULT 0 NOT NULL, defense_blunt INT DEFAULT 0 NOT NULL, defense_distance INT DEFAULT 0 NOT NULL, defense_sharp INT DEFAULT 0 NOT NULL, @@ -101,7 +102,7 @@ CREATE TABLE IF NOT EXISTS unit ( CREATE TABLE IF NOT EXISTS city_unit ( city_id INT UNSIGNED NOT NULL, - unit_id INT UNSIGNED NOT NULL, + unit_id TINYINT UNSIGNED NOT NULL, quantity INT DEFAULT 0 NOT NULL, PRIMARY KEY (city_id, unit_id), FOREIGN KEY (city_id) REFERENCES city (city_id), @@ -126,7 +127,7 @@ CREATE TABLE IF NOT EXISTS battle ( CREATE TABLE IF NOT EXISTS battle_unit ( battle_id INT UNSIGNED NOT NULL, - unit_id INT UNSIGNED NOT NULL, + unit_id TINYINT UNSIGNED NOT NULL, quantity INT DEFAULT 0 NOT NULL, side TINYINT NOT NULL, PRIMARY KEY (battle_id, unit_id),