diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 0f50de6..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Lint & Test - -on: - - push - - pull_request - -jobs: - php-cs-fixer: - name: PHP-CS-Fixer - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: PHP-CS-Fixer - uses: docker://oskarstark/php-cs-fixer-ga - with: - args: --config=./web/.php-cs-fixer.php --diff --dry-run diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..c039780 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "linux-gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c47b193 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "intelephense.format.braces": "k&r", + "intelephense.completion.triggerParameterHints": false +} diff --git a/db/Dockerfile b/db/Dockerfile index 2ca033c..bd981c1 100644 --- a/db/Dockerfile +++ b/db/Dockerfile @@ -1,4 +1,4 @@ -FROM mysql:5.7 +FROM mysql:8.0 ADD . /opt/uoj_db WORKDIR /opt/uoj_db diff --git a/db/add_judger.sql b/db/add_judger.sql index 164db47..41b55f1 100644 --- a/db/add_judger.sql +++ b/db/add_judger.sql @@ -1,2 +1,2 @@ USE `app_uoj233`; -insert into judger_info (judger_name, password, ip) values ('compose_judger', '_judger_password_', 'uoj-judger'); +insert into judger_info (judger_name, password, ip, display_name, description) values ('compose_judger', '_judger_password_', 'uoj-judger', '内建 Judger', ''); diff --git a/db/app_uoj233.sql b/db/app_uoj233.sql index 7c0efe2..4aeabd4 100644 --- a/db/app_uoj233.sql +++ b/db/app_uoj233.sql @@ -30,18 +30,18 @@ USE `app_uoj233`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `best_ac_submissions` ( - `problem_id` int(11) NOT NULL, + `problem_id` int NOT NULL, `submitter` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `submission_id` int(11) NOT NULL, - `used_time` int(11) NOT NULL, - `used_memory` int(11) NOT NULL, - `tot_size` int(11) NOT NULL, - `shortest_id` int(11) NOT NULL, - `shortest_used_time` int(11) NOT NULL, - `shortest_used_memory` int(11) NOT NULL, - `shortest_tot_size` int(11) NOT NULL, + `submission_id` int NOT NULL, + `used_time` int NOT NULL, + `used_memory` int NOT NULL, + `tot_size` int NOT NULL, + `shortest_id` int NOT NULL, + `shortest_used_time` int NOT NULL, + `shortest_used_memory` int NOT NULL, + `shortest_tot_size` int NOT NULL, PRIMARY KEY (`problem_id`,`submitter`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci TABLESPACE `innodb_system`; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -60,16 +60,20 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `blogs` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int NOT NULL AUTO_INCREMENT, `title` text COLLATE utf8mb4_unicode_ci NOT NULL, - `content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, `post_time` datetime NOT NULL, + `active_time` datetime NOT NULL, `poster` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `content_md` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, - `zan` int(11) NOT NULL, + `content_md` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `zan` int NOT NULL DEFAULT '0', `is_hidden` tinyint(1) NOT NULL, `type` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'B', - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + KEY `post_time` (`post_time`), + KEY `active_time` (`active_time`), + KEY `poster` (`poster`,`is_hidden`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -89,14 +93,19 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `blogs_comments` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `blog_id` int(11) NOT NULL, + `id` int NOT NULL AUTO_INCREMENT, + `blog_id` int NOT NULL, `content` text COLLATE utf8mb4_unicode_ci NOT NULL, `post_time` datetime NOT NULL, `poster` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `zan` int(11) NOT NULL, - `reply_id` int(11) NOT NULL, - PRIMARY KEY (`id`) + `zan` int NOT NULL, + `reply_id` int NOT NULL, + `is_hidden` tinyint(1) NOT NULL DEFAULT '0', + `reason_to_hide` varchar(10000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `reply_id` (`reply_id`,`id`), + KEY `blog_id` (`blog_id`,`post_time`), + KEY `blog_id_2` (`blog_id`,`reply_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -116,8 +125,8 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `blogs_tags` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `blog_id` int(11) NOT NULL, + `id` int NOT NULL AUTO_INCREMENT, + `blog_id` int NOT NULL, `tag` varchar(30) NOT NULL, PRIMARY KEY (`id`), KEY `blog_id` (`blog_id`), @@ -143,8 +152,8 @@ UNLOCK TABLES; CREATE TABLE `click_zans` ( `type` char(2) COLLATE utf8mb4_unicode_ci NOT NULL, `username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `target_id` int(11) NOT NULL, - `val` tinyint(4) NOT NULL DEFAULT '1', + `target_id` int NOT NULL, + `val` tinyint NOT NULL DEFAULT '1', PRIMARY KEY (`type`,`target_id`,`username`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -165,15 +174,17 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(50) NOT NULL, + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, `start_time` datetime NOT NULL, - `last_min` int(11) NOT NULL, - `player_num` int(11) NOT NULL, - `status` varchar(50) NOT NULL, - `extra_config` varchar(200) NOT NULL, - `zan` int(11) NOT NULL, - PRIMARY KEY (`id`) + `end_time` datetime GENERATED ALWAYS AS ((`start_time` + interval `last_min` minute)) VIRTUAL NOT NULL, + `last_min` int NOT NULL, + `player_num` int NOT NULL DEFAULT '0', + `status` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `extra_config` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '{}', + `zan` int NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `status` (`status`,`id`) USING BTREE ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -193,15 +204,17 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests_asks` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `contest_id` int(11) NOT NULL, + `id` int NOT NULL AUTO_INCREMENT, + `contest_id` int NOT NULL, `username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, `question` text NOT NULL, `answer` text NOT NULL, `post_time` datetime NOT NULL, `reply_time` datetime NOT NULL, `is_hidden` tinyint(1) DEFAULT '0', - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + KEY `contest_id` (`contest_id`,`is_hidden`,`username`) USING BTREE, + KEY `username` (`username`,`contest_id`) USING BTREE ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -221,7 +234,7 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests_notice` ( - `contest_id` int(11) NOT NULL, + `contest_id` int NOT NULL, `title` varchar(30) NOT NULL, `content` varchar(500) NOT NULL, `time` datetime NOT NULL, @@ -246,7 +259,7 @@ UNLOCK TABLES; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests_permissions` ( `username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `contest_id` int(11) NOT NULL, + `contest_id` int NOT NULL, PRIMARY KEY (`username`,`contest_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -267,10 +280,11 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests_problems` ( - `problem_id` int(11) NOT NULL, - `contest_id` int(11) NOT NULL, - `dfn` int(11) NOT NULL DEFAULT 0, - PRIMARY KEY (`problem_id`,`contest_id`) + `problem_id` int NOT NULL, + `contest_id` int NOT NULL, + `level` int NOT NULL DEFAULT 0, + PRIMARY KEY (`problem_id`,`contest_id`), + KEY `contest_id` (`contest_id`,`problem_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -291,9 +305,9 @@ UNLOCK TABLES; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests_registrants` ( `username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `contest_id` int(11) NOT NULL, + `contest_id` int NOT NULL, `has_participated` tinyint(1) NOT NULL, - `rank` int(11) NOT NULL, + `final_rank` int NOT NULL, PRIMARY KEY (`contest_id`,`username`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -314,12 +328,14 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests_submissions` ( - `contest_id` int(11) NOT NULL, + `contest_id` int NOT NULL, `submitter` varchar(20) NOT NULL, - `problem_id` int(11) NOT NULL, - `submission_id` int(11) NOT NULL, - `score` int(11) NOT NULL, - `penalty` int(11) NOT NULL, + `problem_id` int NOT NULL, + `submission_id` int NOT NULL, + `score` int NOT NULL, + `penalty` int NOT NULL, + `cnt` int DEFAULT NULL, + `n_failures` int DEFAULT NULL, PRIMARY KEY (`contest_id`,`submitter`,`problem_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -340,11 +356,13 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `contests_reviews` ( - `contest_id` int(11) NOT NULL, - `problem_id` int(11) NOT NULL DEFAULT 0, + `contest_id` int NOT NULL, + `problem_id` int NOT NULL DEFAULT 0, `poster` varchar(20) NOT NULL, `content` text NOT NULL, - PRIMARY KEY (`contest_id`,`problem_id`,`poster`) + PRIMARY KEY (`contest_id`,`problem_id`,`poster`), + KEY `contest_id` (`contest_id`,`problem_id`), + KEY `poster` (`poster`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -364,7 +382,7 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `countdowns` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, `title` text NOT NULL, `end_time` datetime NOT NULL, PRIMARY KEY (`id`) @@ -387,8 +405,8 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `custom_test_submissions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `problem_id` int(10) unsigned NOT NULL, + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `problem_id` int UNSIGNED NOT NULL, `submit_time` datetime NOT NULL, `submitter` varchar(20) NOT NULL, `content` text NOT NULL, @@ -396,8 +414,10 @@ CREATE TABLE `custom_test_submissions` ( `result` blob NOT NULL, `status` varchar(20) NOT NULL, `status_details` varchar(100) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; + PRIMARY KEY (`id`), + KEY `submitter` (`submitter`,`problem_id`,`id`), + KEY `judge_time` (`judge_time`,`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -416,10 +436,10 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `friend_links` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `title` varchar(40) NOT NULL, `url` varchar(100) NOT NULL, - `level` int(10) NOT NULL DEFAULT 10, + `level` int NOT NULL DEFAULT 10, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -440,7 +460,7 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `groups` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int NOT NULL AUTO_INCREMENT, `title` text NOT NULL, `announcement` text NOT NULL DEFAULT '', `is_hidden` tinyint(1) NOT NULL DEFAULT 0, @@ -455,10 +475,11 @@ CREATE TABLE `groups` ( /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `groups_assignments` ( - `group_id` int(11) NOT NULL, - `list_id` int(11) NOT NULL, + `group_id` int NOT NULL, + `list_id` int NOT NULL, `end_time` datetime NOT NULL, - PRIMARY KEY (`group_id`, `list_id`) + PRIMARY KEY (`group_id`, `list_id`), + KEY `list_id` (`list_id`,`group_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -469,9 +490,11 @@ CREATE TABLE `groups_assignments` ( /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `groups_users` ( - `group_id` int(11) NOT NULL, + `group_id` int NOT NULL, `username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - PRIMARY KEY (`group_id`, `username`) + PRIMARY KEY (`group_id`, `username`), + KEY `group_id` (`group_id`, `username`), + KEY `username` (`username`, `group_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -482,23 +505,26 @@ CREATE TABLE `groups_users` ( /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `hacks` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `problem_id` int(10) unsigned NOT NULL, - `contest_id` int(10) unsigned DEFAULT NULL, - `submission_id` int(10) unsigned NOT NULL, - `hacker` varchar(20) NOT NULL, - `owner` varchar(20) NOT NULL, - `input` varchar(150) NOT NULL, - `input_type` char(20) NOT NULL, + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `problem_id` int UNSIGNED NOT NULL, + `contest_id` int UNSIGNED DEFAULT NULL, + `submission_id` int UNSIGNED NOT NULL, + `hacker` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `owner` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `input` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL, + `input_type` char(20) COLLATE utf8mb4_unicode_ci NOT NULL, `submit_time` datetime NOT NULL, `judge_time` datetime DEFAULT NULL, `success` tinyint(1) DEFAULT NULL, + `status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, `details` blob NOT NULL, `is_hidden` tinyint(1) NOT NULL, PRIMARY KEY (`id`), KEY `submission_id` (`submission_id`), - KEY `is_hidden` (`is_hidden`,`problem_id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; + KEY `is_hidden` (`is_hidden`,`problem_id`), + KEY `status` (`status`), + KEY `judge_time` (`judge_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -539,11 +565,14 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `judger_info` ( - `judger_name` varchar(50) NOT NULL, - `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, - `ip` char(20) NOT NULL, + `judger_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `ip` char(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `enabled` tinyint(1) NOT NULL DEFAULT '1', + `display_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `description` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`judger_name`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -555,6 +584,26 @@ LOCK TABLES `judger_info` WRITE; /*!40000 ALTER TABLE `judger_info` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `meta` +-- + +CREATE TABLE `meta` ( + `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, + `value` json NOT NULL, + `updated_at` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `meta` +-- + +LOCK TABLES `meta` WRITE; +/*!40000 ALTER TABLE `meta` DISABLE KEYS */; +/*!40000 ALTER TABLE `meta` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `problems` -- @@ -562,18 +611,20 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `problems` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `title` text NOT NULL, + `id` int unsigned NOT NULL AUTO_INCREMENT, + `title` text COLLATE utf8mb4_unicode_ci NOT NULL, `uploader` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, `is_hidden` tinyint(1) NOT NULL DEFAULT '0', - `submission_requirement` text, + `submission_requirement` mediumtext COLLATE utf8mb4_unicode_ci, `hackable` tinyint(1) NOT NULL DEFAULT '0', - `extra_config` varchar(500) NOT NULL DEFAULT '{"view_content_type":"ALL","view_details_type":"ALL"}', + `extra_config` varchar(500) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '{"view_content_type":"ALL","view_details_type":"ALL"}', `zan` int(11) NOT NULL DEFAULT '0', `ac_num` int(11) NOT NULL DEFAULT '0', `submit_num` int(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; + `assigned_to_judger` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'any', + PRIMARY KEY (`id`), + KEY `assigned_to_judger` (`assigned_to_judger`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci TABLESPACE `innodb_system`; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -592,11 +643,11 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `problems_contents` ( - `id` int(11) NOT NULL, - `statement` mediumtext NOT NULL, - `statement_md` mediumtext NOT NULL, + `id` int NOT NULL, + `statement` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `statement_md` longtext COLLATE utf8mb4_unicode_ci NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -616,9 +667,10 @@ UNLOCK TABLES; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `problems_permissions` ( `username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, - `problem_id` int(11) NOT NULL, - PRIMARY KEY (`username`,`problem_id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; + `problem_id` int NOT NULL, + PRIMARY KEY (`username`,`problem_id`), + KEY `problem_id` (`problem_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -637,9 +689,10 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `problems_solutions` ( - `problem_id` int(11) NOT NULL, - `blog_id` int(11) NOT NULL, - PRIMARY KEY (`problem_id`, `blog_id`) + `problem_id` int NOT NULL, + `blog_id` int NOT NULL, + PRIMARY KEY (`problem_id`, `blog_id`), + KEY `problem_id` (`problem_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -659,8 +712,8 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `problems_tags` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `problem_id` int(11) NOT NULL, + `id` int NOT NULL AUTO_INCREMENT, + `problem_id` int NOT NULL, `tag` varchar(30) NOT NULL, PRIMARY KEY (`id`), KEY `problem_id` (`problem_id`), @@ -684,7 +737,7 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `lists` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int NOT NULL AUTO_INCREMENT, `title` text NOT NULL, `description` text NOT NULL DEFAULT '', `is_hidden` tinyint(1) NOT NULL DEFAULT '0', @@ -699,9 +752,10 @@ CREATE TABLE `lists` ( /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `lists_problems` ( - `list_id` int(11) NOT NULL, - `problem_id` int(11) NOT NULL, - PRIMARY KEY (`list_id`, `problem_id`) + `list_id` int NOT NULL, + `problem_id` int NOT NULL, + PRIMARY KEY (`list_id`, `problem_id`), + KEY `list_id` (`list_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -712,8 +766,8 @@ CREATE TABLE `lists_problems` ( /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `lists_tags` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `list_id` int(11) NOT NULL, + `id` int NOT NULL AUTO_INCREMENT, + `list_id` int NOT NULL, `tag` varchar(30) NOT NULL, PRIMARY KEY (`id`), KEY `list_id` (`list_id`), @@ -728,14 +782,14 @@ CREATE TABLE `lists_tags` ( /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `search_requests` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int NOT NULL AUTO_INCREMENT, `created_at` datetime NOT NULL, - `remote_addr` varchar(50) NOT NULL, - `type` enum('search','autocomplete') NOT NULL, - `cache_id` int(11) NOT NULL, - `q` varchar(100) NOT NULL, - `content` text NOT NULL, - `result` mediumtext NOT NULL, + `remote_addr` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `type` enum('search','autocomplete') COLLATE utf8mb4_unicode_ci NOT NULL, + `cache_id` int NOT NULL, + `q` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, + `content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `result` json NOT NULL, PRIMARY KEY (`id`), KEY `remote_addr` (`remote_addr`,`created_at`), KEY `created_at` (`created_at`) @@ -758,27 +812,42 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `submissions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `problem_id` int(10) unsigned NOT NULL, - `contest_id` int(10) unsigned DEFAULT NULL, + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `problem_id` int UNSIGNED NOT NULL, + `contest_id` int UNSIGNED DEFAULT NULL, `submit_time` datetime NOT NULL, - `submitter` varchar(20) NOT NULL, - `content` text NOT NULL, - `language` varchar(15) NOT NULL, - `tot_size` int(11) NOT NULL, + `submitter` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `language` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL, + `tot_size` int NOT NULL, + `judge_reason` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', `judge_time` datetime DEFAULT NULL, - `result` blob NOT NULL, - `status` varchar(20) NOT NULL, - `result_error` varchar(20) DEFAULT NULL, - `score` int(11) DEFAULT NULL, - `used_time` int(11) NOT NULL DEFAULT '0', - `used_memory` int(11) NOT NULL DEFAULT '0', + `judger` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `result` mediumblob NOT NULL, + `status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `result_error` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `score` int DEFAULT NULL, + `hide_score_to_others` tinyint(1) NOT NULL DEFAULT '0', + `hidden_score` int DEFAULT NULL, + `used_time` int NOT NULL DEFAULT '0', + `used_memory` int NOT NULL DEFAULT '0', `is_hidden` tinyint(1) NOT NULL, - `status_details` varchar(100) NOT NULL, + `status_details` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', PRIMARY KEY (`id`), - KEY `is_hidden` (`is_hidden`,`problem_id`), - KEY `score` (`problem_id`, `submitter`, `score`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; + KEY `status` (`status`,`id`), + KEY `result_error` (`result_error`), + KEY `problem_id` (`problem_id`,`id`), + KEY `language` (`language`,`id`), + KEY `language2` (`is_hidden`,`language`,`id`), + KEY `user_score` (`problem_id`,`submitter`,`score`,`id`), + KEY `problem_id2` (`is_hidden`,`problem_id`,`id`), + KEY `id2` (`is_hidden`,`id`), + KEY `problem_score2` (`is_hidden`,`problem_id`,`score`,`id`), + KEY `contest_submission_status` (`contest_id`,`status`), + KEY `submitter2` (`is_hidden`,`submitter`,`id`), + KEY `submitter` (`submitter`,`id`) USING BTREE, + KEY `contest_id` (`contest_id`,`is_hidden`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -790,6 +859,83 @@ LOCK TABLES `submissions` WRITE; /*!40000 ALTER TABLE `submissions` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `submissions_history` +-- + +CREATE TABLE `submissions_history` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `submission_id` int UNSIGNED NOT NULL, + `judge_reason` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `judge_time` datetime DEFAULT NULL, + `judger` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `result` mediumblob NOT NULL, + `status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `status_details` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `result_error` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `score` int DEFAULT NULL, + `used_time` int NOT NULL DEFAULT '0', + `used_memory` int NOT NULL DEFAULT '0', + `major` tinyint(1) NOT NULL, + PRIMARY KEY (`id`), + KEY `submission_judge_time` (`submission_id`,`judge_time`,`id`), + KEY `submission` (`submission_id`,`id`), + KEY `status_major` (`status`,`major`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `submissions_history` +-- + +LOCK TABLES `submissions_history` WRITE; +/*!40000 ALTER TABLE `submissions_history` DISABLE KEYS */; +/*!40000 ALTER TABLE `submissions_history` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `system_updates` +-- + +CREATE TABLE `system_updates` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `time` datetime NOT NULL, + `type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `target_id` int UNSIGNED NOT NULL, + `message` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + KEY `type_id_time` (`type`,`target_id`,`time`), + KEY `type_time` (`type`,`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `system_updates` +-- + +LOCK TABLES `system_updates` WRITE; +/*!40000 ALTER TABLE `system_updates` DISABLE KEYS */; +/*!40000 ALTER TABLE `system_updates` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `upgrades` +-- + +CREATE TABLE `upgrades` ( + `name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `status` enum('up','down') COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Dumping data for table `upgrades` +-- + +LOCK TABLES `upgrades` WRITE; +/*!40000 ALTER TABLE `upgrades` DISABLE KEYS */; +/*!40000 ALTER TABLE `upgrades` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `user_info` -- @@ -797,32 +943,29 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `user_info` ( - `usergroup` char(1) NOT NULL DEFAULT 'U', + `usergroup` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'U', `username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, + `usertype` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'student', `realname` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', `school` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `usertype` varchar(250) NOT NULL DEFAULT 'student', - `email` varchar(50) NOT NULL, - `password` char(32) NOT NULL, - `svn_password` char(10) NOT NULL, - `qq` bigint(20) NOT NULL, - `sex` char(1) NOT NULL DEFAULT 'U', - `ac_num` int(11) NOT NULL, + `email` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL, + `password` char(32) COLLATE utf8mb4_unicode_ci NOT NULL, + `svn_password` char(10) COLLATE utf8mb4_unicode_ci NOT NULL, + `qq` bigint NOT NULL DEFAULT '0', + `sex` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'U', + `ac_num` int NOT NULL DEFAULT 0, `register_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `remote_addr` varchar(50) NOT NULL, - `http_x_forwarded_for` varchar(50) NOT NULL, - `remember_token` char(60) NOT NULL, - `motto` varchar(200) NOT NULL, - `last_login` timestamp NOT NULL DEFAULT 0, - `last_visited` timestamp NOT NULL DEFAULT 0, - `images_size_limit` int(11) UNSIGNED NOT NULL DEFAULT 104857600, /* 100 MiB */ - `codeforces_handle` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `github` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `website` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', - `avatar_source` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'gravatar', + `last_login_time` datetime DEFAULT CURRENT_TIMESTAMP, + `last_visit_time` datetime DEFAULT CURRENT_TIMESTAMP, + `expiration_time` datetime DEFAULT NULL, + `remote_addr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `http_x_forwarded_for` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `remember_token` char(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `motto` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `extra` json NOT NULL, PRIMARY KEY (`username`), KEY `ac_num` (`ac_num`,`username`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -841,13 +984,13 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `users_images` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, `path` varchar(100) NOT NULL, `uploader` varchar(20) NOT NULL, - `width` int(11) NOT NULL, - `height` int(11) NOT NULL, + `width` int NOT NULL, + `height` int NOT NULL, `upload_time` datetime NOT NULL, - `size` int(11) NOT NULL, + `size` int NOT NULL, `hash` varchar(100) NOT NULL, PRIMARY KEY (`id`), KEY `uploader` (`uploader`), @@ -874,13 +1017,16 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `user_msg` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, `sender` varchar(20) NOT NULL, `receiver` varchar(20) NOT NULL, `message` varchar(5000) NOT NULL, `send_time` datetime NOT NULL, `read_time` datetime DEFAULT NULL, - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + KEY `sender` (`sender`), + KEY `receiver` (`receiver`), + KEY `read_time` (`receiver`,`read_time`) USING BTREE ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; @@ -900,13 +1046,14 @@ UNLOCK TABLES; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8mb4 */; CREATE TABLE `user_system_msg` ( - `id` int(11) NOT NULL AUTO_INCREMENT, + `id` int NOT NULL AUTO_INCREMENT, `title` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, `content` text COLLATE utf8mb4_unicode_ci NOT NULL, `receiver` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL, `send_time` datetime NOT NULL, `read_time` datetime DEFAULT NULL, - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + KEY `receiver` (`receiver`,`read_time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/docker-compose.development.yml b/docker-compose.development.yml index 2158beb..90fb54b 100644 --- a/docker-compose.development.yml +++ b/docker-compose.development.yml @@ -24,6 +24,8 @@ services: build: context: ./judger/ dockerfile: Dockerfile + args: + - USE_MIRROR=1 container_name: uoj-judger restart: always stdin_open: true @@ -44,6 +46,8 @@ services: build: context: ./ dockerfile: web/Dockerfile + args: + - USE_MIRROR=1 container_name: uoj-web restart: always stdin_open: true diff --git a/judger/Dockerfile b/judger/Dockerfile index 693a8c2..e9662af 100644 --- a/judger/Dockerfile +++ b/judger/Dockerfile @@ -1,15 +1,24 @@ FROM ubuntu:22.04 ARG CLONE_ADDFLAG +ARG USE_MIRROR +ENV USE_MIRROR $USE_MIRROR +SHELL ["/bin/bash", "-c"] ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update && apt-get install -y vim ntp zip unzip curl wget build-essential fp-compiler python2.7 python3.10 python3-requests libseccomp-dev openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk +ENV PKGS="vim ntp zip unzip curl wget build-essential fp-compiler python2.7 python3.10 python3-requests libseccomp-dev openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk" +RUN if [[ "$USE_MIRROR" == "1" ]]; then\ + sed -i "s@http://.*archive.ubuntu.com@http://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list &&\ + sed -i "s@http://.*security.ubuntu.com@http://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list ;\ +fi &&\ +apt-get update &&\ +(apt-get install -y --allow-unauthenticated --no-install-recommends -o Dpkg::Options::="--force-overwrite" -o APT::Acquire::Retries="30" --fix-missing $PKGS || apt --fix-broken install -y || apt-get install -y --allow-unauthenticated --no-install-recommends -o Dpkg::Options::="--force-overwrite" -o APT::Acquire::Retries="30" --fix-missing $PKGS) ADD . /opt/uoj_judger WORKDIR /opt/uoj_judger # Install environment and set startup script -RUN sh install.sh -p && echo "\ +RUN sh install.sh -p && echo -e "\ #!/bin/sh\n\ if [ ! -f \"/opt/uoj_judger/.conf.json\" ]; then\n\ cd /opt/uoj_judger && sh install.sh -i\n\ diff --git a/judger/uoj_judger/run/compile.cpp b/judger/uoj_judger/run/compile.cpp index 35ef36b..aa53463 100644 --- a/judger/uoj_judger/run/compile.cpp +++ b/judger/uoj_judger/run/compile.cpp @@ -35,12 +35,15 @@ const std::vector> suffix_search_list = { {".code" , "" }, {"20.cpp" , "C++20" }, {"17.cpp" , "C++17" }, - {"14.cpp" , "C++14" }, + {"14.cpp" , "C++" }, {"11.cpp" , "C++11" }, - {".cpp" , "C++" }, + {"03.cpp" , "C++03" }, + {"98.cpp" , "C++98" }, + {".cpp" , "C++" }, {".c" , "C" }, {".pas" , "Pascal" }, {"2.7.py" , "Python2.7"}, + {"2.py" , "Python2.7"}, {".py" , "Python3" }, {"7.java" , "Java7" }, {"8.java" , "Java8" }, diff --git a/web/Dockerfile b/web/Dockerfile index 75a5dbe..94d5602 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -1,18 +1,30 @@ FROM ubuntu:22.04 ARG CLONE_ADDFLAG +ARG USE_MIRROR +ENV USE_MIRROR $USE_MIRROR +SHELL ["/bin/bash", "-c"] ENV DEBIAN_FRONTEND=noninteractive -RUN dpkg -s gnupg 2>/dev/null || (apt-get update && apt-get install -y gnupg) &&\ -echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu jammy main" | tee /etc/apt/sources.list.d/ondrej-php.list && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C &&\ -apt-get update --allow-unauthenticated &&\ -apt-get install -y --allow-unauthenticated -o Dpkg::Options::="--force-overwrite" php7.4 php7.4-yaml php7.4-xml php7.4-dev php7.4-zip php7.4-mysql php7.4-mbstring php7.4-gd php7.4-imagick libseccomp-dev git vim ntp zip unzip curl wget libapache2-mod-xsendfile mysql-server php-pear cmake fp-compiler re2c libyaml-dev python2.7 python3.10 python3-requests openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk +ENV PKGS="php7.4 php7.4-yaml php7.4-xml php7.4-dev php7.4-zip php7.4-mysql php7.4-mbstring php7.4-gd php7.4-imagick libseccomp-dev git vim ntp zip unzip curl wget apache2 libapache2-mod-xsendfile php-pear mysql-client build-essential fp-compiler re2c libseccomp-dev libyaml-dev python2.7 python3.10 python3-requests openjdk-8-jdk openjdk-11-jdk openjdk-17-jdk" +RUN if [[ "$USE_MIRROR" == "1" ]]; then\ + sed -i "s@http://.*archive.ubuntu.com@https://mirrors.aliyun.com@g" /etc/apt/sources.list &&\ + sed -i "s@http://.*security.ubuntu.com@https://mirrors.aliyun.com@g" /etc/apt/sources.list ;\ + fi &&\ + apt-get -o "Acquire::https::Verify-Peer=false" update && apt-get -o "Acquire::https::Verify-Peer=false" install -y --no-install-recommends gnupg ca-certificates &&\ + echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu jammy main" | tee /etc/apt/sources.list.d/ondrej-php.list && apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C &&\ + if [[ "$USE_MIRROR" == "1" ]]; then\ + find /etc/apt/sources.list.d/ -type f -name "*.list" -exec sed -i.bak -r 's#deb(-src)?\s*http(s)?://ppa.launchpad.net#deb\1 https://launchpad.proxy.ustclug.org#ig' {} \; &&\ + find /etc/apt/sources.list.d/ -type f -name "*.list" -exec sed -i.bak -r 's#deb(-src)?\s*http(s)?://ppa.launchpadcontent.net#deb\1 https://launchpad.proxy.ustclug.org#ig' {} \; ;\ + fi &&\ + apt-get update --allow-unauthenticated &&\ + (apt-get install -y --allow-unauthenticated --no-install-recommends -o Dpkg::Options::="--force-overwrite" -o APT::Acquire::Retries="30" --fix-missing $PKGS || apt-get install --fix-broken -y -o APT::Acquire::Retries="30") ADD . /opt/uoj WORKDIR /opt/uoj # Install environment and set startup script -RUN sh web/install.sh -p && echo "\ +RUN sh web/install.sh -p && echo -e "\ #!/bin/sh\n\ if [ ! -f \"/var/uoj_data/.UOJSetupDone\" ]; then\n\ cd /opt/uoj/web && sh install.sh -i\n\ diff --git a/web/app/.default-config.php b/web/app/.default-config.php index 808ef92..dc84dbf 100644 --- a/web/app/.default-config.php +++ b/web/app/.default-config.php @@ -21,12 +21,12 @@ return [ 'main' => [ 'protocol' => 'http', 'host' => '_httpHost_', - 'port' => 80 + 'port' => '80/443' ], 'blog' => [ 'protocol' => 'http', 'host' => '_httpHost_', - 'port' => 80 + 'port' => '80/443' ] ], 'security' => [ @@ -54,7 +54,6 @@ return [ ], 'switch' => [ 'blog-domain-mode' => 3, - 'force-login' => true, 'open-register' => false ] ]; diff --git a/web/app/controllers/add_contest.php b/web/app/controllers/add_contest.php index 11b2e13..d5eaa05 100644 --- a/web/app/controllers/add_contest.php +++ b/web/app/controllers/add_contest.php @@ -1,101 +1,103 @@ addVInput( - 'name', 'text', '比赛标题', 'New Contest', - function($name, &$vdata) { - if ($name == '') { - return '标题不能为空'; - } - - if (strlen($name) > 100) { - return '标题过长'; - } +$time_form = new UOJBs4Form('time'); +$time_form->addVInput( + 'name', + 'text', + '比赛标题', + 'New Contest', + function ($name, &$vdata) { + if ($name == '') { + return '标题不能为空'; + } - $name = HTML::escape($name); + if (strlen($name) > 100) { + return '标题过长'; + } - if ($name === '') { - return '无效编码'; - } + $name = HTML::escape($name); - $vdata['name'] = $name; + if ($name === '') { + return '无效编码'; + } - return ''; - }, - null - ); - $time_form->addVInput( - 'start_time', 'text', '开始时间', date("Y-m-d H:i:s"), - function($str, &$vdata) { - try { - $vdata['start_time'] = new DateTime($str); - } catch (Exception $e) { - return '无效时间格式'; - } - return ''; - }, - null - ); - $time_form->addVInput( - 'last_min', 'text', '时长(单位:分钟)', 180, - function($str, &$vdata) { - if (!validateUInt($str)) { - return '必须为一个整数'; - } + $vdata['name'] = $name; - $vdata['last_min'] = $str; + return ''; + }, + null +); +$time_form->addVInput( + 'start_time', + 'text', + '开始时间', + date("Y-m-d H:i:s"), + function ($str, &$vdata) { + try { + $vdata['start_time'] = new DateTime($str); + } catch (Exception $e) { + return '无效时间格式'; + } + return ''; + }, + null +); +$time_form->addVInput( + 'last_min', + 'text', + '时长(单位:分钟)', + 180, + function ($str, &$vdata) { + if (!validateUInt($str)) { + return '必须为一个整数'; + } - return ''; - }, - null - ); - $time_form->handle = function(&$vdata) { - $start_time_str = $vdata['start_time']->format('Y-m-d H:i:s'); - $esc_name = DB::escape($vdata['name']); - $esc_last_min = DB::escape($vdata['last_min']); - - DB::query("insert into contests (name, start_time, last_min, status) values ('$esc_name', '$start_time_str', $esc_last_min, 'unfinished')"); - }; - $time_form->succ_href = "/contests"; - $time_form->runAtServer(); - ?> + $vdata['last_min'] = $str; + + return ''; + }, + null +); +$time_form->handle = function (&$vdata) { + $start_time_str = $vdata['start_time']->format('Y-m-d H:i:s'); + + DB::insert([ + "insert into contests", + "(name, start_time, last_min, status)", "values", + DB::tuple([$vdata['name'], $start_time_str, $vdata['last_min'], 'unfinished']) + ]); +}; +$time_form->succ_href = "/contests"; +$time_form->runAtServer(); +?>
-
+ +
+
+
-
-
+

添加比赛

-

添加比赛

+
+ printHTML(); ?> +
-
-printHTML(); ?> -
- -
-
- -
- - - +
+
+
+ + +
diff --git a/web/app/controllers/announcements.php b/web/app/controllers/announcements.php index 68cd74b..3b836f3 100644 --- a/web/app/controllers/announcements.php +++ b/web/app/controllers/announcements.php @@ -1,73 +1,57 @@ + - if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) { - become403Page(); - } +
+ +
+

+ +

- requireLib('bootstrap5'); - requirePHPLib('form'); - - function echoBlogCell($blog) { - $level = $blog['level']; - - switch ($level) { - case 0: - $level_str = ''; - break; - case 1: - $level_str = '[三级置顶] '; - break; - case 2: - $level_str = '[二级置顶] '; - break; - case 3: - $level_str = '[一级置顶] '; - break; - } - - echo ''; - echo '' . $level_str . getBlogLink($blog['id']) . ''; - echo '' . getUserLink($blog['poster']) . ''; - echo '' . $blog['post_time'] . ''; - echo ''; - } - $header = << 0, + 'important_blogs.blog_id' => DB::raw('blogs.id') + ], + 'order by level desc, important_blogs.blog_id desc', + << 标题 发表者 发表日期 -EOD; - $config = [ - 'page_len' => 40, - 'div_classes' => ['card', 'my-3'], - 'table_classes' => ['table', 'uoj-table', 'mb-0'], - ]; - ?> - +EOD, + function ($info) { + $blog = new UOJBlog($info); -
- -
+ echo ''; + echo '' . $blog->getLink(['show_level' => true, 'show_new_tag' => true]) . ''; + echo '' . getUserLink($blog->info['poster']) . ''; + echo '' . $blog->info['post_time'] . ''; + echo ''; + }, + [ + 'page_len' => 40, + 'div_classes' => ['card', 'my-3'], + 'table_classes' => ['table', 'uoj-table', 'mb-0'], + ] + ); + ?> -

- -

- - - -
- - - - - +
+ + + +
diff --git a/web/app/controllers/blog_show.php b/web/app/controllers/blog_show.php index 641e624..4831255 100644 --- a/web/app/controllers/blog_show.php +++ b/web/app/controllers/blog_show.php @@ -1,15 +1,6 @@ +redirectTo(HTML::blog_url(UOJBlog::info('poster'), '/post/' . UOJBlog::info('id'), ['escape' => false])); diff --git a/web/app/controllers/blogs.php b/web/app/controllers/blogs.php index 33346e6..49839ed 100644 --- a/web/app/controllers/blogs.php +++ b/web/app/controllers/blogs.php @@ -1,83 +1,80 @@ +Auth::check() || redirectToLogin(); +?>
+ +
+ +
+

+ +

- - + - - - - - - 标题 - 发表者 - 发表日期 + 标题 + 发表者 + 发表日期 + 评价 EOD, - function($blog) { - echo ''; - echo ''; - echo getBlogLink($blog['id']); - if ($blog['is_hidden']) { - echo ' ', UOJLocale::get('hidden'), ' '; - } - echo ''; - echo '' . getUserLink($blog['poster']) . ''; - echo '' . $blog['post_time'] . ''; - echo ''; - }, - [ - 'page_len' => 10, - 'div_classes' => ['card', 'my-3', 'table-responsive'], - 'table_classes' => ['table', 'uoj-table', 'mb-0'], - ] -); - ?> + function ($info) { + $blog = new UOJBlog($info); -
+ echo ''; + echo ''; + echo $blog->getLink(); + if ($blog->info['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + echo ''; + echo '' . getUserLink($blog->info['poster']) . ''; + echo '' . $blog->info['post_time'] . ''; + echo '' . ClickZans::getCntBlock($blog->info['zan']) . ''; + echo ''; + }, + [ + 'page_len' => 10, + 'div_classes' => ['card', 'my-3', 'table-responsive'], + 'table_classes' => ['table', 'uoj-table', 'mb-0'], + ] + ); + ?> - - - +
+ + + +
diff --git a/web/app/controllers/captcha.php b/web/app/controllers/captcha.php index bc49e60..03cc1fc 100644 --- a/web/app/controllers/captcha.php +++ b/web/app/controllers/captcha.php @@ -9,5 +9,3 @@ $_SESSION['phrase'] = $builder->getPhrase(); header('Content-Type: image/jpeg'); $builder->build()->output(); - -?> diff --git a/web/app/controllers/check_notice.php b/web/app/controllers/check_notice.php new file mode 100644 index 0000000..c21f752 --- /dev/null +++ b/web/app/controllers/check_notice.php @@ -0,0 +1,3 @@ +failed
'); - } - if ($myUser == null) { - die('
please log in
'); - } - - $id = $_POST['id']; - $delta = $_POST['delta']; - $type = $_POST['type']; - $show_text = isset($_POST['show-text']) && $_POST['show-text'] != 'false'; - - switch ($type) { - case 'B': - $table_name = 'blogs'; - break; - case 'BC': - $table_name = 'blogs_comments'; - break; - case 'P': - $table_name = 'problems'; - break; - case 'C': - $table_name = 'contests'; - break; - } - - $cur = queryZanVal($id, $type, $myUser); - - if ($cur != $delta) { - $row = DB::selectFirst("select zan from $table_name where id = $id"); - if ($row == null) { - die('
failed
'); - } - $cur += $delta; - if ($cur == 0) { - DB::query("delete from click_zans where username = '{$myUser['username']}' and type = '$type' and target_id = $id"); - } elseif ($cur != $delta) { - DB::query("update click_zans set val = '$cur' where username = '{$myUser['username']}' and type = '$type' and target_id = $id"); - } else { - DB::query("insert into click_zans (username, type, target_id, val) values ('{$myUser['username']}', '$type', $id, $cur)"); - } - $cnt = $row['zan'] + $delta; - DB::query("update $table_name set zan = $cnt where id = $id"); - } else { - $row = DB::selectFirst("select zan from $table_name where id = $id"); - if ($row == null) { - die('
failed
'); - } - $cnt = $row['zan']; - } - ?> - + +function validateZan() { + if (!validateUInt($_POST['id'])) + return false; + if (!validateInt($_POST['delta'])) + return false; + if ($_POST['delta'] != 1 && $_POST['delta'] != -1) + return false; + if (!ClickZans::getTable($_POST['type'])) + return false; + return true; +} +if (!validateZan()) { + die('
failed
'); +} +if (!Auth::check()) { + die('
please log in
'); +} +if (!ClickZans::canClickZan($_POST['id'], $_POST['type'], Auth::user())) { + die('
no permission
'); +} + +die(ClickZans::click($_POST['id'], $_POST['type'], Auth::user(), $_POST['delta'], $_POST['show-text'])); diff --git a/web/app/controllers/contest_confirmation.php b/web/app/controllers/contest_confirmation.php index c72c39a..742c291 100644 --- a/web/app/controllers/contest_confirmation.php +++ b/web/app/controllers/contest_confirmation.php @@ -1,77 +1,65 @@ userCanParticipateNow(Auth::user()) || UOJResponse::page403(); +UOJContest::cur()->userHasMarkedParticipated(Auth::user()) && redirectTo(UOJContest::cur()->getUri()); - genMoreContestInfo($contest); - - if (!Auth::check()) { - redirectToLogin(); - } elseif (!hasRegistered($myUser, $contest)) { - redirectTo("/contest/{$contest['id']}/register"); - } elseif ($contest['cur_progress'] < CONTEST_IN_PROGRESS) { - redirectTo('/contests'); - } elseif (hasParticipated($myUser, $contest) || $contest['cur_progress'] > CONTEST_IN_PROGRESS) { - redirectTo("/contest/{$contest['id']}"); - } +$confirm_form = new UOJBs4Form('confirm'); +$confirm_form->submit_button_config['class_str'] = 'btn btn-primary mt-3'; +$confirm_form->submit_button_config['text'] = '我已核对信息,确认参加比赛'; +$confirm_form->handle = function () { + UOJContest::cur()->markUserAsParticipated(Auth::user()); +}; +$confirm_form->succ_href = '/contest/' . UOJContest::info('id'); +$confirm_form->runAtServer(); +?> - $confirm_form = new UOJForm('confirm'); - $confirm_form->submit_button_config['class_str'] = 'btn btn-primary'; - $confirm_form->submit_button_config['margin_class'] = 'mt-3'; - $confirm_form->submit_button_config['text'] = '我已核对信息,确认参加比赛'; - $confirm_form->handle = function() use ($myUser, $contest) { - DB::update("update contests_registrants set has_participated = 1 where username = '{$myUser['username']}' and contest_id = {$contest['id']}"); - }; - $confirm_form->succ_href = "/contest/{$contest['id']}"; - $confirm_form->runAtServer(); - ?> - - +
-
-

确认参赛

+
+

确认参赛

-

您即将参加比赛 “”,请在正式参赛前仔细核对以下比赛信息:

+

您即将参加比赛 “”,请在正式参赛前仔细核对以下比赛信息:

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
比赛名称
参赛选手
开始时间
结束时间
比赛赛制
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
比赛名称
参赛选手
开始时间
结束时间
比赛赛制basicRule() ?>
+
+ + printHTML() ?>
- - printHTML() ?> -
diff --git a/web/app/controllers/contest_inside.php b/web/app/controllers/contest_inside.php index cc0ccea..b4e901d 100644 --- a/web/app/controllers/contest_inside.php +++ b/web/app/controllers/contest_inside.php @@ -1,335 +1,277 @@ userCanView(Auth::user(), ['ensure' => true, 'check-register' => true]); - if (isset($_GET['tab'])) { - $cur_tab = $_GET['tab']; - } else { - $cur_tab = 'dashboard'; - } - - $tabs_info = array( - 'dashboard' => array( - 'name' => UOJLocale::get('contests::contest dashboard'), - 'url' => "/contest/{$contest['id']}" - ), - 'submissions' => array( - 'name' => UOJLocale::get('contests::contest submissions'), - 'url' => "/contest/{$contest['id']}/submissions" - ), - 'standings' => array( - 'name' => UOJLocale::get('contests::contest standings'), - 'url' => "/contest/{$contest['id']}/standings" - ), +$contest = UOJContest::info(); +$is_manager = UOJContest::cur()->userCanManage(Auth::user()); + +if (isset($_GET['tab'])) { + $cur_tab = $_GET['tab']; +} else { + $cur_tab = 'dashboard'; +} + +$tabs_info = [ + 'dashboard' => [ + 'name' => UOJLocale::get('contests::contest dashboard'), + 'url' => "/contest/{$contest['id']}" + ], + 'submissions' => [ + 'name' => UOJLocale::get('contests::contest submissions'), + 'url' => "/contest/{$contest['id']}/submissions" + ], + 'standings' => [ + 'name' => UOJLocale::get('contests::contest standings'), + 'url' => "/contest/{$contest['id']}/standings" + ], +]; + +if ($contest['cur_progress'] > CONTEST_TESTING) { + $tabs_info['after_contest_standings'] = array( + 'name' => UOJLocale::get('contests::after contest standings'), + 'url' => "/contest/{$contest['id']}/after_contest_standings" ); + $tabs_info['self_reviews'] = array( + 'name' => UOJLocale::get('contests::contest self reviews'), + 'url' => "/contest/{$contest['id']}/self_reviews" + ); +} - if ($contest['cur_progress'] > CONTEST_TESTING) { - $tabs_info['after_contest_standings'] = array( - 'name' => UOJLocale::get('contests::after contest standings'), - 'url' => "/contest/{$contest['id']}/after_contest_standings" +if ($is_manager) { + $tabs_info['backstage'] = array( + 'name' => UOJLocale::get('contests::contest backstage'), + 'url' => "/contest/{$contest['id']}/backstage" + ); +} + +isset($tabs_info[$cur_tab]) || UOJResponse::page404(); + +if (isSuperUser($myUser) || isContestJudger($myUser)) { + if (CONTEST_PENDING_FINAL_TEST <= $contest['cur_progress']) { + $start_test_form = new UOJBs4Form('start_test'); + $start_test_form->handle = function () { + UOJContest::finalTest(); + }; + $start_test_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100'; + $start_test_form->submit_button_config['smart_confirm'] = ''; + $start_test_form->submit_button_config['text'] = UOJContest::cur()->labelForFinalTest(); + $start_test_form->runAtServer(); + } + if ($contest['cur_progress'] >= CONTEST_TESTING) { + $publish_result_form = new UOJBs4Form('publish_result'); + $publish_result_form->handle = function () { + UOJContest::announceOfficialResults(); + }; + $publish_result_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100'; + $publish_result_form->submit_button_config['smart_confirm'] = ''; + $publish_result_form->submit_button_config['text'] = '公布成绩'; + + $publish_result_form->runAtServer(); + } +} + +if ($cur_tab == 'dashboard') { + if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) { + $post_question = new UOJBs4Form('post_question'); + $post_question->addVTextArea( + 'qcontent', + '问题', + '', + function ($content, &$vdata) { + if (!Auth::check()) { + return '您尚未登录'; + } + if (!$content || strlen($content) == 0) { + return '问题不能为空'; + } + if (strlen($content) > 140 * 4) { + return '问题太长'; + } + + $vdata['content'] = HTML::escape($content); + + return ''; + }, + null ); - $tabs_info['self_reviews'] = array( - 'name' => UOJLocale::get('contests::contest self reviews'), - 'url' => "/contest/{$contest['id']}/self_reviews" + $post_question->handle = function (&$vdata) use ($contest) { + DB::insert([ + "insert into contests_asks", + "(contest_id, question, answer, username, post_time, is_hidden)", + "values", DB::tuple([$contest['id'], $vdata['content'], '', Auth::id(), DB::now(), 1]) + ]); + }; + $post_question->runAtServer(); + } else { + $post_question = null; + } +} elseif ($cur_tab == 'backstage') { + if (isSuperUser(Auth::user())) { + $post_notice = new UOJBs4Form('post_notice'); + $post_notice->addInput( + 'title', + 'text', + '标题', + '', + function ($title, &$vdata) { + if (!$title) { + return '标题不能为空'; + } + + $vdata['title'] = HTML::escape($title); + + return ''; + }, + null ); - } - - if (hasContestPermission(Auth::user(), $contest)) { - $tabs_info['backstage'] = array( - 'name' => UOJLocale::get('contests::contest backstage'), - 'url' => "/contest/{$contest['id']}/backstage" + $post_notice->addTextArea( + 'content', + '正文', + '', + function ($content, &$vdata) { + if (!$content) { + return '公告不能为空'; + } + + $vdata['content'] = HTML::escape($content); + + return ''; + }, + null ); + $post_notice->handle = function (&$vdata) use ($contest) { + DB::insert([ + "insert into contests_notice", + "(contest_id, title, content, time)", + "values", DB::tuple([$contest['id'], $vdata['title'], $vdata['content'], DB::now()]) + ]); + }; + $post_notice->runAtServer(); + } else { + $post_notice = null; } - - if (!isset($tabs_info[$cur_tab])) { - become404Page(); - } - - if (isset($_POST['check_notice'])) { - $result = DB::query("select * from contests_notice where contest_id = '${contest['id']}' order by time desc limit 10"); - $ch = array(); - $flag = false; - try { - while ($row = DB::fetch($result)) { - if (new DateTime($row['time']) > new DateTime($_POST['last_time'])) { - $ch[] = $row['title'].': '.$row['content']; - } - } - } catch (Exception $e) { - } - global $myUser; - $result = DB::query("select * from contests_asks where contest_id='${contest['id']}' and username='${myUser['username']}' order by reply_time desc limit 10"); - try { - while ($row = DB::fetch($result)) { - if (new DateTime($row['reply_time']) > new DateTime($_POST['last_time'])) { - $ch[] = $row['question'].': '.$row['answer']; - } - } - } catch (Exception $e) { - } - if ($ch) { - die(json_encode(array('msg' => $ch, 'time' => UOJTime::$time_now_str))); - } else { - die(json_encode(array('time' => UOJTime::$time_now_str))); - } - } - - if (isSuperUser($myUser) || isContestJudger($myUser)) { - if (CONTEST_PENDING_FINAL_TEST <= $contest['cur_progress']) { - $start_test_form = new UOJForm('start_test'); - $start_test_form->handle = function() { - global $contest; - $result = DB::query("select id, problem_id, content from submissions where contest_id = {$contest['id']}"); - while ($submission = DB::fetch($result, MYSQLI_ASSOC)) { - if (!isset($contest['extra_config']["problem_{$submission['problem_id']}"])) { - $content = json_decode($submission['content'], true); - if (isset($content['final_test_config'])) { - $content['config'] = $content['final_test_config']; - unset($content['final_test_config']); - } - if (isset($content['first_test_config'])) { - unset($content['first_test_config']); - } - $esc_content = DB::escape(json_encode($content)); - DB::update("update submissions set judge_time = NULL, result = '', score = NULL, status = 'Waiting Rejudge', content = '$esc_content' where id = {$submission['id']}"); - } - } - DB::query("update contests set status = 'testing' where id = {$contest['id']}"); - }; - $start_test_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100'; - $start_test_form->submit_button_config['smart_confirm'] = ''; - if ($contest['cur_progress'] < CONTEST_TESTING) { - $start_test_form->submit_button_config['text'] = '开始最终测试'; - } else { - $start_test_form->submit_button_config['text'] = '重新开始最终测试'; - } - $start_test_form->runAtServer(); - } - if ($contest['cur_progress'] >= CONTEST_TESTING) { - $publish_result_form = new UOJForm('publish_result'); - $publish_result_form->handle = function() { - // time config - set_time_limit(0); - ignore_user_abort(true); - global $contest; - $contest_data = queryContestData($contest); - $problems_count = DB::selectCount("select count(*) from contests_problems where contest_id = {$contest['id']} order by dfn, problem_id"); - calcStandings($contest, $contest_data, $score, $standings, true); - - for ($i = 0; $i < count($standings); $i++) { - DB::query("update contests_registrants set rank = {$standings[$i][3]} where contest_id = {$contest['id']} and username = '{$standings[$i][2][0]}'"); - - $user_link = getUserLink($standings[$i][2][0]); - $total_score = $problems_count * 100; - $tail = $standings[$i][0] == $total_score ? ',请继续保持!' : ',请继续努力!'; - $content = <<{$user_link} 您好:

-

您参与的比赛 {$contest['name']} 现已结束,您的成绩为 {$standings[$i][0]}{$tail}

-EOD; - sendSystemMsg($standings[$i][2][0], '比赛成绩公布', $content); + if ($is_manager) { + $reply_question = new UOJBs4Form('reply_question'); + $reply_question->addHidden( + 'rid', + '0', + function ($id, &$vdata) use ($contest) { + if (!validateUInt($id)) { + return '无效ID'; + } + $q = DB::selectFirst([ + "select * from contests_asks", + "where", [ + "id" => $id, + "contest_id" => $contest['id'] + ] + ]); + if (!$q) { + return '无效ID'; + } + $vdata['id'] = $id; + return ''; + }, + null + ); + $reply_question->addVSelect('rtype', [ + 'public' => '公开(如果该问题反复被不同人提出,或指出了题目中的错误,请选择该项)', + 'private' => '非公开', + 'statement' => '请仔细阅读题面(非公开)', + 'no_comment' => '无可奉告(非公开)', + 'no_play' => '请认真比赛(非公开)', + ], '回复类型', 'private'); + $reply_question->addVTextArea( + 'rcontent', + '回复', + '', + function ($content, &$vdata) { + if (!Auth::check()) { + return '您尚未登录'; } - DB::query("update contests set status = 'finished' where id = {$contest['id']}"); - }; - $publish_result_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100'; - $publish_result_form->submit_button_config['smart_confirm'] = ''; - $publish_result_form->submit_button_config['text'] = '公布成绩'; - - $publish_result_form->runAtServer(); - } - } - - if ($cur_tab == 'dashboard') { - if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) { - $post_question = new UOJForm('post_question'); - $post_question->addVTextArea('qcontent', '问题', '', - function($content) { - if (!Auth::check()) { - return '您尚未登录'; - } - if (!$content || strlen($content) == 0) { - return '问题不能为空'; - } - if (strlen($content) > 140 * 4) { - return '问题太长'; - } - return ''; - }, - null - ); - $post_question->handle = function() { - global $contest; - $content = DB::escape($_POST['qcontent']); - $username = Auth::id(); - DB::query("insert into contests_asks (contest_id, question, username, post_time, is_hidden) values ('{$contest['id']}', '$content', '$username', now(), 1)"); - }; - $post_question->runAtServer(); - } else { - $post_question = null; - } - } elseif ($cur_tab == 'backstage') { - if (isSuperUser(Auth::user())) { - $post_notice = new UOJForm('post_notice'); - $post_notice->addVInput('title', 'text', '标题', '', - function($title) { - if (!$title) { - return '标题不能为空'; - } - return ''; - }, - null - ); - $post_notice->addVTextArea('content', '正文', '', - function($content) { - if (!$content) { - return '公告不能为空'; - } - return ''; - }, - null - ); - $post_notice->handle = function() { - global $contest; - $title = DB::escape($_POST['title']); - $content = DB::escape($_POST['content']); - DB::insert("insert into contests_notice (contest_id, title, content, time) values ('{$contest['id']}', '$title', '$content', now())"); - }; - $post_notice->runAtServer(); - } else { - $post_notice = null; - } - - if (hasContestPermission(Auth::user(), $contest)) { - $reply_question = new UOJForm('reply_question'); - $reply_question->addHidden('rid', '0', - function($id) { - global $contest; - - if (!validateUInt($id)) { - return '无效ID'; - } - $q = DB::selectFirst("select * from contests_asks where id = $id"); - if ($q['contest_id'] != $contest['id']) { - return '无效ID'; - } - return ''; - }, - null - ); - $reply_question->addVSelect('rtype', [ - 'public' => '公开', - 'private' => '非公开', - 'statement' => '请仔细阅读题面(非公开)', - 'no_comment' => '无可奉告(非公开)', - 'no_play' => '请认真比赛(非公开)', - ], '回复类型', 'private'); - $reply_question->addVTextArea('rcontent', '回复', '', - function($content) { - if (!Auth::check()) { - return '您尚未登录'; - } - switch ($_POST['rtype']) { - case 'public': - case 'private': - if (strlen($content) == 0) { - return '回复不能为空'; - } - break; - } - return ''; - }, - null - ); - $reply_question->handle = function() { - global $contest; - $content = DB::escape($_POST['rcontent']); - $is_hidden = 1; switch ($_POST['rtype']) { - case 'statement': - $content = '请仔细阅读题面'; - break; - case 'no_comment': - $content = '无可奉告 ╮(╯▽╰)╭ '; - break; - case 'no_play': - $content = '请认真比赛 ( ̄口 ̄)!!'; - break; case 'public': - $is_hidden = 0; - break; - default: + case 'private': + if (strlen($content) == 0) { + return '回复不能为空'; + } break; } - DB::update("update contests_asks set answer = '$content', reply_time = now(), is_hidden = {$is_hidden} where id = {$_POST['rid']}"); - }; - $reply_question->runAtServer(); - } else { - $reply_question = null; + $vdata['content'] = HTML::escape($content); + return ''; + }, + null + ); + $reply_question->handle = function (&$vdata) use ($contest) { + $content = $vdata['content']; + $is_hidden = 1; + switch ($_POST['rtype']) { + case 'statement': + $content = '请仔细阅读题面'; + break; + case 'no_comment': + $content = '无可奉告 ╮(╯▽╰)╭ '; + break; + case 'no_play': + $content = '请认真比赛 ( ̄口 ̄)!!'; + break; + case 'public': + $is_hidden = 0; + break; + default: + break; + } + DB::update([ + "update contests_asks", + "set", [ + "answer" => $content, + "reply_time" => DB::now(), + "is_hidden" => $is_hidden + ], "where", ["id" => $vdata['id']] + ]); + }; + $reply_question->runAtServer(); + } else { + $reply_question = null; + } +} elseif ($cur_tab == 'self_reviews') { + if (UOJContest::cur()->userHasMarkedParticipated(Auth::user())) { + $self_reviews_update_form = new UOJBs4Form('self_review_update'); + $self_reviews_update_form->ctrl_enter_submit = true; + + $contest_problems = DB::selectAll([ + "select problem_id", + "from", "contests_problems", + "where", ["contest_id" => $contest['id']], + "order by level, problem_id" + ]); + for ($i = 0; $i < count($contest_problems); $i++) { + $contest_problems[$i]['problem'] = UOJContestProblem::query($contest_problems[$i]['problem_id']); } - } elseif ($cur_tab == 'self_reviews') { - if (hasParticipated(Auth::user(), $contest)) { - $self_reviews_update_form = new UOJForm('self_review_update'); - $self_reviews_update_form->ctrl_enter_submit = true; - - $contest_problems = DB::selectAll("select problem_id from contests_problems where contest_id = {$contest['id']} order by dfn, problem_id"); - for ($i = 0; $i < count($contest_problems); $i++) { - $contest_problems[$i]['problem'] = queryProblemBrief($contest_problems[$i]['problem_id']); - } - - for ($i = 0; $i < count($contest_problems); $i++) { - $content = DB::selectFirst("select content from contests_reviews where contest_id = {$contest['id']} and problem_id = {$contest_problems[$i]['problem_id']} and poster = '{$myUser['username']}'")['content']; - $self_reviews_update_form->addVTextArea('self_review_update__problem_' . chr(ord('A') + $i), '' . chr(ord('A') + $i) . ': ' . $contest_problems[$i]['problem']['title'], $content, - function ($content) { - if (strlen($content) > 200) { - return '总结不能超过200字'; - } - return ''; - }, - null, - true - ); - } - - $content = DB::selectFirst("select content from contests_reviews where contest_id = {$contest['id']} and problem_id = -1 and poster = '{$myUser['username']}'")['content']; - $self_reviews_update_form->addVTextArea('self_review_update__overall', '比赛总结', $content, + for ($i = 0; $i < count($contest_problems); $i++) { + $content = DB::selectFirst([ + "select content", + "from", "contests_reviews", + "where", [ + "contest_id" => $contest['id'], + "problem_id" => $contest_problems[$i]['problem_id'], + "poster" => Auth::id(), + ], + ]); + $self_reviews_update_form->addVTextArea( + 'self_review_update__problem_' . $contest_problems[$i]['problem']->getLetter(), + '' . $contest_problems[$i]['problem']->getLetter() . ': ' . $contest_problems[$i]['problem']->info['title'], + $content['content'], function ($content) { if (strlen($content) > 200) { return '总结不能超过200字'; @@ -340,188 +282,223 @@ EOD; null, true ); + } - $self_reviews_update_form->handle = function() { - global $contest, $contest_problems, $myUser; - - for ($i = 0; $i < count($contest_problems); $i++) { - if (isset($_POST['self_review_update__problem_' . chr(ord('A') + $i)])) { - $esc_content = DB::escape($_POST['self_review_update__problem_' . chr(ord('A') + $i)]); - $problem_id = $contest_problems[$i]['problem_id']; - - DB::query("replace into contests_reviews (contest_id, problem_id, poster, content) values ({$contest['id']}, $problem_id, '{$myUser['username']}', '$esc_content')"); - } + $content = DB::selectFirst([ + "select content", + "from", "contests_reviews", + "where", [ + "contest_id" => $contest['id'], + "problem_id" => -1, + "poster" => Auth::id(), + ], + ]); + $self_reviews_update_form->addVTextArea( + 'self_review_update__overall', + '比赛总结', + $content['content'], + function ($content) { + if (strlen($content) > 200) { + return '总结不能超过200字'; } - if (isset($_POST['self_review_update__overall'])) { - $esc_content = DB::escape($_POST['self_review_update__overall']); - DB::query("replace into contests_reviews (contest_id, problem_id, poster, content) values ({$contest['id']}, -1, '{$myUser['username']}', '$esc_content')"); - } - }; - - $self_reviews_update_form->runAtServer(); - } - } - - function echoDashboard() { - global $contest, $post_notice, $post_question, $reply_question; - - $myname = Auth::id(); - $contest_problems = DB::selectAll("select contests_problems.problem_id, best_ac_submissions.submission_id from contests_problems left join best_ac_submissions on contests_problems.problem_id = best_ac_submissions.problem_id and submitter = '{$myname}' where contest_id = {$contest['id']} order by contests_problems.dfn, contests_problems.problem_id"); - - for ($i = 0; $i < count($contest_problems); $i++) { - $contest_problems[$i]['problem'] = queryProblemBrief($contest_problems[$i]['problem_id']); - } - - $contest_notice = DB::selectAll("select * from contests_notice where contest_id = {$contest['id']} order by time desc"); - - if (Auth::check()) { - $my_questions = DB::selectAll("select * from contests_asks where contest_id = {$contest['id']} and username = '{$myname}' order by post_time desc"); - $my_questions_pag = new Paginator([ - 'data' => $my_questions - ]); - } else { - $my_questions_pag = null; - } - - $others_questions_pag = new Paginator([ - 'col_names' => array('*'), - 'table_name' => 'contests_asks', - 'cond' => "contest_id = {$contest['id']} and username != '{$myname}' and is_hidden = 0", - 'tail' => 'order by reply_time desc', - 'page_len' => 10 - ]); - - uojIncludeView('contest-dashboard', [ - 'contest' => $contest, - 'contest_notice' => $contest_notice, - 'contest_problems' => $contest_problems, - 'post_question' => $post_question, - 'my_questions_pag' => $my_questions_pag, - 'others_questions_pag' => $others_questions_pag, - ]); - } - - function echoBackstage() { - global $contest, $post_notice, $reply_question; - - $questions_pag = new Paginator([ - 'col_names' => array('*'), - 'table_name' => 'contests_asks', - 'cond' => "contest_id = {$contest['id']}", - 'tail' => 'order by post_time desc', - 'page_len' => 50 - ]); - - if ($contest['cur_progress'] < CONTEST_TESTING) { - $contest_data = queryContestData($contest, ['pre_final' => true]); - calcStandings($contest, $contest_data, $score, $standings); - - $standings_data = [ - 'contest' => $contest, - 'standings' => $standings, - 'score' => $score, - 'contest_data' => $contest_data - ]; - } else { - $standings_data = null; - } - - uojIncludeView('contest-backstage', [ - 'contest' => $contest, - 'post_notice' => $post_notice, - 'reply_question' => $reply_question, - 'questions_pag' => $questions_pag, - 'standings_data' => $standings_data - ]); - } - - function echoMySubmissions() { - global $contest, $myUser; - - $show_all_submissions_status = Cookie::get('show_all_submissions') !== null ? 'checked="checked" ' : ''; - $show_all_submissions = UOJLocale::get('contests::show all submissions'); - echo << -
- - -
-
- -EOD; - - $config = array( - 'judge_time_hidden' => '', - 'table_config' => array( - 'div_classes' => array('card', 'mb-3', 'table-responsive'), - 'table_classes' => array('table', 'mb-0', 'uoj-table', 'text-center') - ), + return ''; + }, + null, + true ); - if (Cookie::get('show_all_submissions') !== null) { - echoSubmissionsList("contest_id = {$contest['id']}", 'order by id desc', $config, $myUser); - } else { - echoSubmissionsList("submitter = '{$myUser['username']}' and contest_id = {$contest['id']}", 'order by id desc', $config, $myUser); - } + $self_reviews_update_form->handle = function () use ($contest, $contest_problems) { + global $contest, $contest_problems, $myUser; + + for ($i = 0; $i < count($contest_problems); $i++) { + if (isset($_POST['self_review_update__problem_' . $contest_problems[$i]['problem']->getLetter()])) { + $esc_content = DB::escape($_POST['self_review_update__problem_' . $contest_problems[$i]['problem']->getLetter()]); + $problem_id = $contest_problems[$i]['problem_id']; + + DB::query([ + "replace into contests_reviews", + "(contest_id, problem_id, poster, content)", + "values", DB::tuple([$contest['id'], $problem_id, Auth::id(), $esc_content]), + ]); + } + } + + if (isset($_POST['self_review_update__overall'])) { + $esc_content = DB::escape($_POST['self_review_update__overall']); + DB::query([ + "replace into contests_reviews", + "(contest_id, problem_id, poster, content)", + "values", DB::tuple([$contest['id'], -1, Auth::id(), $esc_content]), + ]); + } + }; + + $self_reviews_update_form->runAtServer(); } - - function echoStandings($is_after_contest_query = false) { - global $contest; - - $contest_data = queryContestData($contest, array(), $is_after_contest_query); +} + +function echoDashboard() { + global $contest, $post_question; + + $contest_problems = DB::selectAll([ + "select contests_problems.problem_id, best_ac_submissions.submission_id", + "from", "contests_problems", "left join", "best_ac_submissions", + "on", [ + "contests_problems.problem_id" => DB::raw("best_ac_submissions.problem_id"), + "best_ac_submissions.submitter" => Auth::id() + ], "where", ["contest_id" => $contest['id']], + "order by contests_problems.level, contests_problems.problem_id" + ]); + + for ($i = 0; $i < count($contest_problems); $i++) { + $contest_problems[$i]['problem'] = UOJContestProblem::query($contest_problems[$i]['problem_id']); + $contest_problems[$i]['problem']->problem_number = $i; + } + + $contest_notice = DB::selectAll([ + "select * from contests_notice", + "where", ["contest_id" => $contest['id']], + "order by time desc" + ]); + + if (Auth::check()) { + $my_questions = DB::selectAll([ + "select * from contests_asks", + "where", [ + "contest_id" => $contest['id'], + "username" => Auth::id() + ], "order by post_time desc" + ]); + $my_questions_pag = new Paginator([ + 'data' => $my_questions + ]); + } else { + $my_questions_pag = null; + } + + $others_questions_pag = new Paginator([ + 'col_names' => ['*'], + 'table_name' => 'contests_asks', + 'cond' => [ + "contest_id" => $contest['id'], + ["username", "!=", Auth::id()], + "is_hidden" => 0 + ], + 'tail' => 'order by reply_time desc', + 'page_len' => 10 + ]); + + uojIncludeView('contest-dashboard', [ + 'contest' => $contest, + 'contest_notice' => $contest_notice, + 'contest_problems' => $contest_problems, + 'post_question' => $post_question, + 'my_questions_pag' => $my_questions_pag, + 'others_questions_pag' => $others_questions_pag + ]); +} + +function echoBackstage() { + global $contest, $post_notice, $reply_question; + + $questions_pag = new Paginator([ + 'col_names' => ['*'], + 'table_name' => 'contests_asks', + 'cond' => ["contest_id" => $contest['id']], + 'tail' => 'order by post_time desc', + 'page_len' => 50 + ]); + + if (UOJContest::cur()->managerCanSeeFinalStandingsTab(Auth::user())) { + $contest_data = queryContestData($contest, ['pre_final' => true]); calcStandings($contest, $contest_data, $score, $standings); - - uojIncludeView('contest-standings', [ + + $standings_data = [ 'contest' => $contest, 'standings' => $standings, 'score' => $score, 'contest_data' => $contest_data - ]); + ]; + } else { + $standings_data = null; } - - function echoReviews() { - global $contest; - - $contest_data = queryContestData($contest, array()); - calcStandings($contest, $contest_data, $score, $standings, false, true); - - uojIncludeView('contest-standings', [ - 'contest' => $contest, - 'standings' => $standings, - 'score' => $score, - 'contest_data' => $contest_data, - 'show_self_reviews' => true - ]); + + uojIncludeView('contest-backstage', [ + 'contest' => $contest, + 'post_notice' => $post_notice, + 'reply_question' => $reply_question, + 'questions_pag' => $questions_pag, + 'standings_data' => $standings_data + ]); +} + +function echoMySubmissions() { + $problems = UOJContest::cur()->getProblemIDs(); + + $options = []; + $options[] = ['value' => 'all', 'text' => '所有题目']; + for ($i = 0; $i < count($problems); $i++) { + $letter = chr(ord('A') + $i); + $options[] = ['value' => $letter, 'text' => "{$letter} 题"]; } - - $page_header = HTML::stripTags($contest['name']) . ' - '; - ?> + + $chosen = UOJRequest::get('p'); + $problem_id = null; + if (strlen($chosen) == 1) { + $num = ord($chosen) - ord('A'); + if (0 <= $num && $num < count($problems)) { + $problem_id = $problems[$num]; + } else { + $chosen = 'all'; + } + } else { + $chosen = 'all'; + } + + $conds = ['contest_id' => UOJContest::info('id')]; + if (Cookie::get('show_all_submissions') === null) { + $conds += ['submitter' => Auth::id()]; + } + if ($problem_id !== null) { + $conds += ['problem_id' => $problem_id]; + } + + uojIncludeView('contest-submissions', [ + 'show_all_submissions_status' => Cookie::get('show_all_submissions') !== null, + 'options' => $options, + 'chosen' => $chosen, + 'conds' => $conds + ]); +} + +function echoStandings($is_after_contest_query = false) { + global $contest; + uojIncludeView('contest-standings', ['contest' => $contest] + UOJContest::cur()->queryResult(['after_contest' => $is_after_contest_query])); +} + +function echoSelfReviews() { + global $contest; + + uojIncludeView('contest-reviews', ['contest' => $contest] + UOJContest::cur()->queryResult()); +} + +$page_header = HTML::stripTags($contest['name']) . ' - '; +?>
-

+

- + - + - + - + - +
@@ -529,32 +506,32 @@ EOD;
- -
- -
- - - -
-

-
- - - - - - - - - - - -
-
- -
- +
+ +
+ + + +
+

+
+ + + + + + + + + + + +
+
+ +
+ -
-
- - - - -
+ ?> +
+
-
-

修改我的赛后总结

-
赛后总结支持 Markdown 语法。
- printHTML(); ?> -
- - -
-
-
-
-
-
-

- - - -

-
- - - - - - - - - - (%) - - - + + + +
+ +
+

修改我的赛后总结

+
赛后总结支持 Markdown 语法。
+ printHTML(); ?> +
+ +
+
-
- +
+
+
+

+ + + +

+
+ + + + + + + + + + (%) + + + + +
+
+ +
+ + basicRule() === 'OI') : ?> +

此次比赛为 OI 赛制。

+

注意:比赛时只显示测样例的结果。

+ basicRule() === 'ACM') : ?> +

此次比赛为 ACM 赛制。

+

封榜时间:format('Y-m-d H:i:s') ?>

+ basicRule() === 'IOI') : ?> +

此次比赛为 IOI 赛制。

+

比赛时显示的得分即最终得分。

+ + + + + + + + 管理 + + + +
+ printHTML(); ?> +
+ + +
+ printHTML(); ?> +
+ + +
+
+

比赛资料

+
+
+ + + +
+
+ +
+
- -

此次比赛为 OI 赛制。

-

注意:比赛时只显示测样例的结果。

- -

此次比赛为 IOI 赛制。

-

注意:比赛时显示测试所有数据的结果,但无法看到详细信息。

- - - - - - - - 管理 - - - -
- printHTML(); ?> -
- - -
- printHTML(); ?> -
- - -
-
-

比赛资料

-
-
- - - -
-
- -
- -
- - + diff --git a/web/app/controllers/contest_manage.php b/web/app/controllers/contest_manage.php index 58f213c..9e062ed 100644 --- a/web/app/controllers/contest_manage.php +++ b/web/app/controllers/contest_manage.php @@ -1,109 +1,113 @@ [ + 'name' => '基本信息', + 'url' => "/contest/{$contest['id']}/manage/profile", + ], + 'problems' => [ + 'name' => '试题', + 'url' => "/contest/{$contest['id']}/manage/problems", + ], + 'managers' => [ + 'name' => '管理者', + 'url' => "/contest/{$contest['id']}/manage/managers", + ], + 'others' => [ + 'name' => '其他', + 'url' => "/contest/{$contest['id']}/manage/others", + ], +]; - $tabs_info = [ - 'profile' => [ - 'name' => '基本信息', - 'url' => "/contest/{$contest['id']}/manage/profile", - ], - 'problems' => [ - 'name' => '试题', - 'url' => "/contest/{$contest['id']}/manage/problems", - ], - 'managers' => [ - 'name' => '管理者', - 'url' => "/contest/{$contest['id']}/manage/managers", - ], - 'others' => [ - 'name' => '其他', - 'url' => "/contest/{$contest['id']}/manage/others", - ], - ]; - - if (!isset($tabs_info[$cur_tab])) { - become404Page(); - } - - if ($cur_tab == 'profile') { - $profile_form = new UOJForm('time'); - $profile_form->addVInput( - 'name', 'text', '比赛标题', $contest['name'], - function($name, &$vdata) { - if ($name == '') { - return '标题不能为空'; - } - - if (strlen($name) > 100) { - return '标题过长'; - } - - $name = HTML::escape($name); - - if ($name === '') { - return '无效编码'; - } - - $vdata['name'] = $name; - - return ''; - }, - null - ); - $profile_form->addVInput( - 'start_time', 'text', '开始时间', $contest['start_time_str'], - function($str, &$vdata) { - try { - $vdata['start_time'] = new DateTime($str); - } catch (Exception $e) { - return '无效时间格式'; - } - return ''; - }, - null - ); - $profile_form->addVInput( - 'last_min', 'text', '时长(单位:分钟)', $contest['last_min'], - function($str, &$vdata) { - if (!validateUInt($str)) { - return '必须为一个整数'; - } +if (!isset($tabs_info[$cur_tab])) { + become404Page(); +} - $vdata['last_min'] = $str; - - return ''; - }, - null - ); - $profile_form->handle = function(&$vdata) use ($contest) { - $start_time_str = $vdata['start_time']->format('Y-m-d H:i:s'); - $esc_name = DB::escape($vdata['name']); - $esc_last_min = DB::escape($vdata['last_min']); - - DB::update("update contests set start_time = '$start_time_str', last_min = {$_POST['last_min']}, name = '$esc_name' where id = {$contest['id']}"); +if ($cur_tab == 'profile') { + $profile_form = new UOJBs4Form('time'); + $profile_form->addVInput( + 'name', + 'text', + '比赛标题', + $contest['name'], + function ($name, &$vdata) { + if ($name == '') { + return '标题不能为空'; + } - dieWithJsonData(['status' => 'success', 'message' => '修改成功']); - }; - $profile_form->setAjaxSubmit(<< 100) { + return '标题过长'; + } + + $name = HTML::escape($name); + + if ($name === '') { + return '无效编码'; + } + + $vdata['name'] = $name; + + return ''; + }, + null + ); + $profile_form->addVInput( + 'start_time', + 'text', + '开始时间', + $contest['start_time_str'], + function ($str, &$vdata) { + try { + $vdata['start_time'] = new DateTime($str); + } catch (Exception $e) { + return '无效时间格式'; + } + return ''; + }, + null + ); + $profile_form->addVInput( + 'last_min', + 'text', + '时长(单位:分钟)', + $contest['last_min'], + function ($str, &$vdata) { + if (!validateUInt($str)) { + return '必须为一个整数'; + } + + $vdata['last_min'] = $str; + + return ''; + }, + null + ); + $profile_form->handle = function (&$vdata) use ($contest) { + DB::update([ + "update contests", + "set", [ + "name" => $vdata['name'], + "start_time" => $vdata['start_time']->format('Y-m-d H:i:s'), + "last_min" => $vdata['last_min'], + ], "where", ["id" => $contest['id']] + ]); + + dieWithJsonData(['status' => 'success', 'message' => '修改成功']); + }; + $profile_form->setAjaxSubmit(<<runAtServer(); - } elseif ($cur_tab == 'problems') { - if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') { - $problem_id = $_POST['problem_id']; + $profile_form->runAtServer(); +} elseif ($cur_tab == 'problems') { + if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') { + $problem_id = $_POST['problem_id']; + $problem = UOJProblem::query($problem_id); - if (!validateUInt($problem_id)) { - dieWithAlert('无效的题目 ID。'); - } - - if (!queryProblemBrief($problem_id)) { - dieWithAlert('题目不存在。'); - } - - if (!DB::selectFirst("SELECT * FROM contests_problems WHERE contest_id = {$contest['id']} AND problem_id = $problem_id")) { - dieWithAlert('题目不在比赛中。'); - } - - DB::delete("DELETE FROM contests_problems WHERE contest_id = {$contest['id']} AND problem_id = $problem_id"); - - unset($contest['extra_config']["problem_$problem_id"]); - $esc_extra_config = DB::escape(json_encode($contest['extra_config'])); - DB::update("UPDATE `contests` SET extra_config = '$esc_extra_config' WHERE id = {$contest['id']}"); - - dieWithAlert('移除成功!'); + if (!$problem) { + dieWithAlert('题目不存在'); } - $add_problem_form = new UOJForm('add_problem'); - $add_problem_form->addVInput('problem_id', 'text', '题目 ID', '', - function($problem_id, &$vdata) { - if (!validateUInt($problem_id)) { - return '无效的题目 ID。'; - } + if (!UOJContest::cur()->hasProblem($problem)) { + dieWithAlert('题目不在本场比赛中'); + } - $problem = queryProblemBrief($problem_id); - if (!$problem) { - return '题目不存在。'; - } - - if (!hasProblemPermission(Auth::user(), $problem)) { - return "无权添加题目 #$problem_id。"; - } + DB::delete([ + "delete from contests_problems", + "where", [ + "contest_id" => $contest['id'], + "problem_id" => $problem_id, + ], + ]); - $vdata['problem_id'] = $problem_id; - - return ''; - }, - null - ); - $add_problem_form->addVSelect('judge_config', [ - 'sample' => '只测样例', - 'no-details' => '测试全部数据,但不显示测试点详情', - 'full' => '测试全部数据', - ], '评测设置', 'sample'); - $add_problem_form->handle = function(&$vdata) use ($contest) { - $dfn = DB::selectFirst("SELECT max(dfn) FROM contests_problems WHERE contest_id = {$contest['id']}")['max(dfn)'] + 1; - DB::insert("INSERT INTO `contests_problems` (contest_id, problem_id, dfn) VALUES ({$contest['id']}, '{$vdata['problem_id']}', $dfn)"); + unset($contest['extra_config']["problem_$problem_id"]); + unset($contest['extra_config']['bonus']["problem_$problem_id"]); + unset($contest['extra_config']['submit_time_limit']["problem_$problem_id"]); - if ($_POST['judge_config'] != 'sample') { - $contest['extra_config']["problem_$problem_id"] = $_POST['judge_config']; - $esc_extra_config = DB::escape(json_encode($contest['extra_config'])); - DB::update("UPDATE `contests` SET extra_config = '$esc_extra_config' WHERE id = {$contest['id']}"); + $esc_extra_config = json_encode($contest['extra_config']); + DB::update([ + "update contests", + "set", ["extra_config" => $esc_extra_config], + "where", ["id" => $contest['id']] + ]); + + dieWithAlert('移除成功!'); + } + + $add_problem_form = new UOJBs4Form('add_problem'); + $add_problem_form->addVInput( + 'problem_id', + 'text', + '题目 ID', + '', + function ($problem_id, &$vdata) { + $problem = UOJProblem::query($problem_id); + if (!$problem) { + return '题目不存在。'; } - dieWithJsonData(['status' => 'success', 'message' => "题目 #{$vdata['problem_id']} 添加成功!"]); - }; - $add_problem_form->submit_button_config['text'] = '添加'; - $add_problem_form->submit_button_config['margin_class'] = 'mt-3'; - $add_problem_form->setAjaxSubmit(<<userCanManage(Auth::user())) { + return "无权添加此题目。"; + } + + if (UOJContest::cur()->hasProblem($problem)) { + return "题目已经在本场比赛中。"; + } + + $vdata['problem_id'] = $problem_id; + + return ''; + }, + null + ); + $add_problem_form->addVSelect('judge_config', [ + 'default' => '默认', + 'sample' => '只测样例', + 'no-details' => '测试全部数据,对于每个测试点显示得分但不显示详情', + 'full' => '测试全部数据', + ], '评测设置', 'default'); + $add_problem_form->addVCheckboxes('bonus', ['0' => '否', '1' => '是'], '是否为 bonus 题(ACM 赛制)', '0'); + $add_problem_form->handle = function (&$vdata) use ($contest) { + $level = DB::selectFirst([ + "select", "max(level)", + "from", "contests_problems", + "where", [ + "contest_id" => $contest['id'], + ] + ])["max(level)"]; + DB::insert([ + "insert ignore into contests_problems", + "(contest_id, problem_id, level)", + "values", DB::tuple([$contest['id'], $vdata['problem_id'], $level + 1]) + ]); + + $judge_type = $_POST['judge_config']; + if ($judge_type === 'default') { + unset($contest['extra_config']["problem_{$vdata['problem_id']}"]); + } else { + $contest['extra_config']["problem_{$vdata['problem_id']}"] = $judge_type; + } + + $esc_extra_config = json_encode($contest['extra_config']); + DB::update([ + "update contests", + "set", ["extra_config" => $esc_extra_config], + "where", ["id" => $contest['id']] + ]); + + dieWithJsonData(['status' => 'success', 'message' => "题目 #{$vdata['problem_id']} 添加成功!"]); + }; + $add_problem_form->submit_button_config['text'] = '添加'; + $add_problem_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3'; + $add_problem_form->setAjaxSubmit(<<runAtServer(); - } elseif ($cur_tab == 'managers') { - if (isset($_POST['submit-remove_manager']) && $_POST['submit-remove_manager'] == 'remove_manager') { - $username = $_POST['username']; + $add_problem_form->runAtServer(); +} elseif ($cur_tab == 'managers') { + if (isset($_POST['submit-remove_manager']) && $_POST['submit-remove_manager'] == 'remove_manager') { + $username = $_POST['username']; + $user = UOJUser::query($username); - if (!validateUsername($username)) { - dieWithAlert('用户名不合法。'); - } - - if (!queryUser($username)) { - dieWithAlert('用户不存在。'); - } - - if (!DB::selectFirst("SELECT * FROM contests_permissions WHERE contest_id = {$contest['id']} AND username = '$username'")) { - dieWithAlert('用户不是这场比赛的管理员。'); - } - - DB::delete("DELETE FROM `contests_permissions` WHERE contest_id = ${contest['id']} AND username = '$username'"); - dieWithAlert('移除成功!'); + if (!$user) { + dieWithAlert('用户不存在。'); } - $add_manager_form = new UOJForm('add_manager'); - $add_manager_form->addVInput('username', 'text', '用户名', '', - function($username, &$vdata) { - if (!validateUsername($username)) { - return '用户名不合法'; - } + if (!UOJContest::cur()->userCanManage($user)) { + dieWithAlert('用户不是这场比赛的管理员。'); + } - if (!queryUser($username)) { - return '用户不存在'; - } - if (DB::selectFirst("SELECT * FROM contests_permissions WHERE contest_id = {$contest['id']} AND username = '$username'")) { - return '用户已经是这场比赛的管理员'; - } + DB::delete([ + "delete from contests_permissions", + "where", [ + "contest_id" => $contest['id'], + "username" => $user['username'], + ] + ]); + dieWithAlert('移除成功!'); + } - $vdata['username'] = $username; + $add_manager_form = new UOJBs4Form('add_manager'); + $add_manager_form->addVInput( + 'username', + 'text', + '用户名', + '', + function ($username, &$vdata) use ($contest) { + $user = UOJUser::query($username); - return ''; - }, - null - ); - $add_manager_form->handle = function(&$vdata) use ($contest) { - DB::query("INSERT INTO `contests_permissions` (contest_id, username) VALUES (${contest['id']}, '{$vdata['username']}')"); + if (!$user) { + return '用户不存在'; + } - dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户设置为本场比赛的管理者。']); - }; - $add_manager_form->submit_button_config['text'] = '添加'; - $add_manager_form->submit_button_config['margin_class'] = 'mt-3'; - $add_manager_form->setAjaxSubmit(<<userCanManage($user)) { + return '用户已经是这场比赛的管理员'; + } + + $vdata['username'] = $username; + + return ''; + }, + null + ); + $add_manager_form->handle = function (&$vdata) use ($contest) { + DB::insert([ + "insert into contests_permissions", + "(contest_id, username)", + "values", DB::tuple([$contest['id'], $vdata['username']]) + ]); + + dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户设置为本场比赛的管理者。']); + }; + $add_manager_form->submit_button_config['text'] = '添加'; + $add_manager_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3'; + $add_manager_form->setAjaxSubmit(<<runAtServer(); - } elseif ($cur_tab == 'others') { - $version_form = new UOJForm('version'); - $version_form->addVSelect('standings_version', [ - '1' => '1', - '2' => '2', - ], '比赛排名版本', $contest['extra_config']['standings_version'] ?: '2'); - $version_form->handle = function() use ($contest) { - $contest['extra_config']['standings_version'] = $_POST['standings_version']; - $esc_extra_config = json_encode($contest['extra_config']); - $esc_extra_config = DB::escape($esc_extra_config); - DB::update("UPDATE contests SET extra_config = '$esc_extra_config' WHERE id = {$contest['id']}"); + $add_manager_form->runAtServer(); +} elseif ($cur_tab == 'others') { + $version_form = new UOJBs4Form('version'); + $version_form->addVSelect('standings_version', [ + '1' => '1', + '2' => '2', + ], '比赛排名版本', $contest['extra_config']['standings_version']); + $version_form->handle = function () use ($contest) { + $contest['extra_config']['standings_version'] = $_POST['standings_version']; + $esc_extra_config = json_encode($contest['extra_config']); + DB::update([ + "update contests", + "set", ["extra_config" => $esc_extra_config], + "where", ["id" => $contest['id']], + ]); - dieWithJsonData(['status' => 'success', 'message' => '修改成功']); - }; - $version_form->setAjaxSubmit(<< 'success', 'message' => '修改成功']); + }; + $version_form->setAjaxSubmit(<<runAtServer(); + $version_form->runAtServer(); - $contest_type_form = new UOJForm('contest_type'); - $contest_type_form->addVSelect('contest_type', [ - 'OI' => 'OI', - 'IOI' => 'IOI' - ], '比赛类型', $contest['extra_config']['contest_type'] ?: 'OI'); - $contest_type_form->handle = function() use ($contest) { - $contest['extra_config']['contest_type'] = $_POST['contest_type']; - $esc_extra_config = json_encode($contest['extra_config']); - $esc_extra_config = DB::escape($esc_extra_config); - DB::update("UPDATE contests set extra_config = '$esc_extra_config' where id = {$contest['id']}"); + $rule_form = new UOJBs4Form('basic_rule'); + $rule_form->addVSelect('basic_rule', [ + 'OI' => 'OI', + 'IOI' => 'IOI', + 'ACM' => 'ACM', + ], '比赛类型', $contest['extra_config']['basic_rule']); + $rule_form->addVSelect('free_registration', [ + 1 => '所有人都可以自由报名', + 0 => '只能由管理员帮选手报名' + ], "报名方式", $contest['extra_config']['free_registration']); + $rule_form->addVSelect('individual_or_team', [ + 'individual' => '个人赛', + 'team' => '团体赛' + ], "个人赛/团体赛", $contest['extra_config']['individual_or_team']); + $rule_form->addVInput( + 'max_n_submissions_per_problem', + 'text', + '每题最高提交次数(-1 表示不限制)', + $contest['extra_config']['max_n_submissions_per_problem'], + function ($str) { + return !validateUInt($str) && $str !== '-1' ? '必须为一个非负整数或 -1' : ''; + }, + null + ); + $rule_form->handle = function () use ($contest) { + $contest['extra_config']['basic_rule'] = $_POST['basic_rule']; + $contest['extra_config']['free_registration'] = (int)$_POST['free_registration']; + $contest['extra_config']['individual_or_team'] = $_POST['individual_or_team']; + $contest['extra_config']['max_n_submissions_per_problem'] = (int)$_POST['max_n_submissions_per_problem']; - dieWithJsonData(['status' => 'success', 'message' => '修改成功']); - }; - $contest_type_form->setAjaxSubmit(<< $esc_extra_config], + "where", ["id" => $contest['id']] + ]); + + dieWithJsonData(['status' => 'success', 'message' => '修改成功']); + }; + $rule_form->setAjaxSubmit(<<runAtServer(); - - $blog_link_contests = new UOJForm('blog_link_contests'); - $blog_link_contests->addVInput('blog_id', 'text', '博客 ID', '', - function ($blog_id, &$vdata) { - if (!validateUInt($blog_id)) { - return 'ID 不合法'; - } + $rule_form->runAtServer(); - if (!queryBlog($blog_id)) { - return '博客不存在'; - } + $blog_link_contests = new UOJBs4Form('blog_link_contests'); + $blog_link_contests->addVInput( + 'blog_id', + 'text', + '博客 ID', + '', + function ($blog_id, &$vdata) { + if (!validateUInt($blog_id)) { + return 'ID 不合法'; + } - $vdata['blog_id'] = $blog_id; - - return ''; - }, - null - ); - $blog_link_contests->addVInput('title', 'text', '名称', '', - function($title, &$vdata) { - if ($title == '') { - return '名称不能为空'; - } - - if (strlen($title) > 40) { - return '名称过长'; - } + if (!queryBlog($blog_id)) { + return '博客不存在'; + } - $title = HTML::escape($title); - if ($title === '') { - return '无效编码'; - } + $vdata['blog_id'] = $blog_id; - $vdata['title'] = $title; + return ''; + }, + null + ); + $blog_link_contests->addVInput( + 'title', + 'text', + '名称', + '', + function ($title, &$vdata) { + if ($title == '') { + return '名称不能为空'; + } - return ''; - }, - null - ); - $blog_link_contests->addVSelect('op_type', [ - 'add' => '添加', - 'del' => '移除', - ], '操作类型', ''); - $blog_link_contests->handle = function($vdata) use ($contest) { - if ($_POST['op_type'] == 'add') { - if (!isset($contest['extra_config']['links'])) { - $contest['extra_config']['links'] = []; - } + if (strlen($title) > 40) { + return '名称过长'; + } - $contest['extra_config']['links'][] = [$vdata['title'], $vdata['blog_id']]; - } elseif ($_POST['op_type'] == 'del') { - $n = count($contest['extra_config']['links']); - for ($i = 0; $i < $n; $i++) { - if ($contest['extra_config']['links'][$i][1] == $vdata['blog_id']) { - $contest['extra_config']['links'][$i] = $contest['extra_config']['links'][$n - 1]; - unset($contest['extra_config']['links'][$n - 1]); - break; - } - } + $title = HTML::escape($title); + if ($title === '') { + return '无效编码'; + } - if (!count($contest['extra_config']['links'])) { - unset($contest['extra_config']['links']); + $vdata['title'] = $title; + + return ''; + }, + null + ); + $blog_link_contests->addVSelect('op_type', [ + 'add' => '添加', + 'del' => '移除', + ], '操作类型', ''); + $blog_link_contests->handle = function ($vdata) use ($contest) { + if ($_POST['op_type'] == 'add') { + if (!isset($contest['extra_config']['links'])) { + $contest['extra_config']['links'] = []; + } + + $contest['extra_config']['links'][] = [$vdata['title'], $vdata['blog_id']]; + } elseif ($_POST['op_type'] == 'del') { + $n = count($contest['extra_config']['links']); + for ($i = 0; $i < $n; $i++) { + if ($contest['extra_config']['links'][$i][1] == $vdata['blog_id']) { + $contest['extra_config']['links'][$i] = $contest['extra_config']['links'][$n - 1]; + unset($contest['extra_config']['links'][$n - 1]); + break; } } - - $esc_extra_config = json_encode($contest['extra_config']); - $esc_extra_config = DB::escape($esc_extra_config); - DB::update("UPDATE contests set extra_config = '$esc_extra_config' where id = {$contest['id']}"); - dieWithJsonData(['status' => 'success', 'message' => '修改成功']); - }; - $blog_link_contests->setAjaxSubmit(<< 'success', 'message' => '修改成功']); + }; + $blog_link_contests->setAjaxSubmit(<<runAtServer(); + $blog_link_contests->runAtServer(); - $extra_registration_form = new UOJForm('extra_registration_form'); - $extra_registration_form->addVCheckboxes('extra_registration', [ - '0' => '禁止', - '1' => '允许' - ], '是否允许额外报名', isset($contest['extra_config']['extra_registration']) ? $contest['extra_config']['extra_registration'] : '1'); - $extra_registration_form->handle = function() use ($contest) { - $contest['extra_config']['extra_registration'] = $_POST['extra_registration']; - $esc_extra_config = DB::escape(json_encode($contest['extra_config'])); - DB::update("UPDATE contests SET extra_config = '$esc_extra_config' WHERE id = {$contest['id']}"); + $extra_registration_form = new UOJBs4Form('extra_registration_form'); + $extra_registration_form->addVCheckboxes('extra_registration', [ + '0' => '禁止', + '1' => '允许' + ], '是否允许额外报名', isset($contest['extra_config']['extra_registration']) ? $contest['extra_config']['extra_registration'] : '1'); + $extra_registration_form->handle = function () use ($contest) { + $contest['extra_config']['extra_registration'] = $_POST['extra_registration']; + $esc_extra_config = DB::escape(json_encode($contest['extra_config'])); + DB::update("UPDATE contests SET extra_config = '$esc_extra_config' WHERE id = {$contest['id']}"); - dieWithJsonData(['status' => 'success', 'message' => $_POST['extra_registration'] ? '已允许额外报名' : '已禁止额外报名']); - }; - $extra_registration_form->setAjaxSubmit(<< 'success', 'message' => $_POST['extra_registration'] ? '已允许额外报名' : '已禁止额外报名']); + }; + $extra_registration_form->setAjaxSubmit(<<runAtServer(); - } + $extra_registration_form->runAtServer(); +} - ?> +?> -

+

(ID: ) 管理

- -
+ + - - - -
- - -
-
- -
-
- printHTML(); ?> -
-
-
注意事项
-
    -
  • 请为选手预留合理的做题时间。一般而言,CSP 和 NOIP 的比赛时长为 4 小时,省选 / NOI 的比赛时长为 5 小时。
  • -
-
-
-
- -
-
- -
-
-
- + + +
+ + +
+
+ +
+
+ printHTML(); ?> +
+
+
注意事项
+
    +
  • 请为选手预留合理的做题时间。一般而言,CSP 和 NOIP 的比赛时长为 4 小时,省选 / NOI 的比赛时长为 5 小时。
  • +
+
+
+
+
+ +
+
+ +
+
+
+ ID 标题 @@ -543,187 +625,195 @@ EOD); 操作 EOD, - function($row) { - $problem = queryProblemBrief($row['problem_id']); - echo ''; - echo '', $row['problem_id'], ''; - echo '', getProblemLink($problem), ''; - echo '', isset($contest['extra_config']["problem_{$problem['id']}"]) ? $contest['extra_config']["problem_{$problem['id']}"] : 'sample', ''; - echo ''; - echo '
'; - echo ''; - echo ''; - echo ''; - echo '
'; - echo ''; - echo ''; - }, - [ - 'echo_full' => true, - 'div_classes' => ['table-responsive'], - 'table_classes' => ['table', 'align-middle'], - ] - ) - ?> -
-
- -
-
- printHTML() ?> -
-
-
注意事项
-
    -
  • 推荐在比赛结束前将题目设置为隐藏。
  • -
  • 对于「评测设置」选项,一般情况下保持默认(即只测样例)即可。
  • -
+ function ($row) { + $problem = UOJProblem::query($row['problem_id']); + echo ''; + echo '', $row['problem_id'], ''; + echo '', $problem->getLink(['with' => 'none']), ''; + echo '', isset($contest['extra_config']["problem_{$problem->info['id']}"]) ? $contest['extra_config']["problem_{$problem->info['id']}"] : 'default', ''; + echo ''; + echo '
info['id'], ' 从比赛中移除吗?")\'>'; + echo ''; + echo ''; + echo ''; + echo '
'; + echo ''; + echo ''; + }, + [ + 'echo_full' => true, + 'div_classes' => ['table-responsive'], + 'table_classes' => ['table', 'align-middle'], + ] + ) + ?> +
+
+ +
+
+ printHTML() ?> +
+
+
注意事项
+
    +
  • 推荐在比赛结束前将题目设置为隐藏。
  • +
  • 对于「评测设置」选项,一般情况下保持默认(即只测样例)即可。
  • +
  • 在 ACM 赛制中,如果设置一道题目为 bonus 题,那么获得 100 分后会总罚时会减少 20 分钟,但排名时不会将此题记入该选手通过的题目总数中。
  • +
+
+
+
-
-
-
- -
-
- -
-
-
- +
+
+ +
+
+
+ 用户名 操作 EOD, - function ($row) { - echo ''; - echo '', getUserLink($row['username']), ''; - echo ''; - echo '
'; - echo ''; - echo ''; - echo ''; - echo '
'; - echo ''; - echo ''; - }, - [ - 'echo_full' => true, - 'div_classes' => ['table-responsive'], - 'table_classes' => ['table'], - ] - ); - ?> + function ($row) { + echo ''; + echo '', getUserLink($row['username']), ''; + echo ''; + echo '
'; + echo ''; + echo ''; + echo ''; + echo '
'; + echo ''; + echo ''; + }, + [ + 'echo_full' => true, + 'div_classes' => ['table-responsive'], + 'table_classes' => ['table'], + ] + ); + ?> +
+
+ +
+
+ printHTML(); ?> +
+
+
注意事项
+
    +
  • 添加管理者前请确认用户名是否正确以免带来不必要的麻烦。
  • +
  • 比赛管理者如果报名了比赛仍可以正常参赛,但不报名比赛也可以查看并管理本场比赛。
  • +
+
+
+
+
+
+ +
+
+ +
+
+
+ +
+
+ printHTML(); ?> +
+
+
赛制解释
+
    +
  • OI 赛制: 比赛期间可设置题目只测样例,结束后会进行重测。按最后一次有效提交算分和算罚时。
  • +
  • ACM 赛制: 比赛期间所有题目显示最终测评结果。比赛结束前一小时封榜,比赛时间不足 5 小时则比赛过去五分之四后封榜。一道题的罚时为得分最高的提交的时间,加上在此之前没有使得该题分数增加的提交的次数乘以 20 分钟。
  • +
  • IOI 赛制: 比赛期间所有题目显示最终测评结果。按得分最高的有效提交算分和算罚时。
  • +
+
常见问题
+
    +
  • 暂无
  • +
+
+
+
+
+ +
+
+ printHTML(); ?> +
+
+
注意事项
+
    +
  • 正常情况下无需调整此项设置。
  • +
+
+
+
+
+ +
+
+ printHTML(); ?> +
+
+
注意事项
+
    +
  • 添加比赛资料前请确认博客是否处于公开状态。
  • +
+
+
+
+
+
-
- +
+
- printHTML(); ?> + printHTML(); ?>
注意事项
    -
  • 添加管理者前请确认用户名是否正确以免带来不必要的麻烦。
  • -
  • 比赛管理者如果报名了比赛仍可以正常参赛,但不报名比赛也可以查看并管理本场比赛。
  • +
  • 如果允许额外报名,则比赛开始后选手也可以报名参赛。
-
- -
-
- -
-
-
- -
-
- printHTML(); ?> -
-
-
注意事项
-
    -
  • 目前 S2OJ 支持 OI 和 IOI 赛制。
  • -
-
-
-
-
- -
-
- printHTML(); ?> -
-
-
注意事项
-
    -
  • 正常情况下无需调整此项设置。
  • -
-
-
-
-
- -
-
- printHTML(); ?> -
-
-
注意事项
-
    -
  • 添加比赛资料前请确认博客是否处于公开状态。
  • -
-
-
-
-
- -
-
- printHTML(); ?> -
-
-
注意事项
-
    -
  • 如果允许额外报名,则比赛开始后选手也可以报名参赛。
  • -
-
-
-
-
-
-
diff --git a/web/app/controllers/contest_members.php b/web/app/controllers/contest_members.php index 3689f99..7741cee 100644 --- a/web/app/controllers/contest_members.php +++ b/web/app/controllers/contest_members.php @@ -1,186 +1,167 @@ userCanManage(Auth::user()); +$show_ip = isSuperUser(Auth::user()); - genMoreContestInfo($contest); +if ($is_manager) { + $add_new_contestant_form = new UOJBs4Form('add_new_contestant_form'); + $add_new_contestant_form->addInput( + 'new_username', + 'text', + '用户名', + '', + function ($username, &$vdata) { + $user = UOJUser::query($username); - if (isSuperUser($myUser)) { - $add_new_contestant_form = new UOJForm('add_new_contestant_form'); - $add_new_contestant_form->addInput('new_username', 'text', '用户名', '', - function ($x) { - global $contest; - - if (!validateUsername($x)) { - return '用户名不合法'; - } - $user = queryUser($x); - if (!$user) { - return '用户不存在'; - } - - if (hasRegistered($user, $contest)) { - return '该用户已经报名'; - } - return ''; - }, - null - ); - $add_new_contestant_form->submit_button_config['align'] = 'compressed'; - $add_new_contestant_form->submit_button_config['text'] = '注册该用户'; - $add_new_contestant_form->handle = function() { - global $contest; - - $username = $_POST['new_username']; - - DB::query("replace into contests_registrants (username, contest_id, has_participated) values ('{$username}', {$contest['id']}, 0)"); - - updateContestPlayerNum($contest); - }; - $add_new_contestant_form->runAtServer(); - - $add_group_to_contest_form = new UOJForm('add_group_to_contest'); - $add_group_to_contest_form->addInput('group_id', 'text', '小组 ID', '', - function ($x) { - global $contest; - - if (!validateUInt($x)) { - return '小组 ID 不合法'; - } - $group = queryGroup($x); - if (!$group) { - return '小组不存在'; - } - - return ''; - }, - null - ); - $add_group_to_contest_form->submit_button_config['align'] = 'compressed'; - $add_group_to_contest_form->submit_button_config['text'] = '注册该小组中的用户'; - $add_group_to_contest_form->handle = function() { - global $contest; - $group_id = $_POST['group_id']; - - $users = DB::selectAll("select b.username as username from groups_users a inner join user_info b on a.username = b.username where a.group_id = $group_id"); - - foreach ($users as $user) { - DB::query("replace into contests_registrants (username, contest_id, has_participated) values ('{$user['username']}', {$contest['id']}, 0)"); + if (!$user) { + return '用户不存在'; } - updateContestPlayerNum($contest); - }; - $add_group_to_contest_form->runAtServer(); + if (UOJContest::cur()->userHasRegistered($user)) { + return '该用户已经报名'; + } - $remove_user_from_contest_form = new UOJForm('remove_user_from_contest'); - $remove_user_from_contest_form->addInput('remove_username', 'text', '用户名', '', - function ($x) { - global $contest; - if (!validateUsername($x)) { - return '用户名不合法'; - } + $vdata['user'] = $user; - $user = queryUser($x); - if (!$user) { - return '用户不存在'; - } + return ''; + }, + null + ); + $add_new_contestant_form->submit_button_config['align'] = 'compressed'; + $add_new_contestant_form->submit_button_config['text'] = '注册该用户'; + $add_new_contestant_form->handle = function (&$vdata) { + UOJContest::cur()->userRegister($vdata['user']); + }; + $add_new_contestant_form->runAtServer(); - if (!hasRegistered($user, $contest)) { - return '该用户未报名'; - } + $add_group_to_contest_form = new UOJBs4Form('add_group_to_contest'); + $add_group_to_contest_form->addInput( + 'group_id', + 'text', + '小组 ID', + '', + function ($group_id, &$vdata) { + if (!validateUInt($group_id)) { + return '小组 ID 不合法'; + } + $group = queryGroup($group_id); + if (!$group) { + return '小组不存在'; + } - return ''; - }, - null - ); - $remove_user_from_contest_form->submit_button_config['align'] = 'compressed'; - $remove_user_from_contest_form->submit_button_config['text'] = '移除该用户'; - $remove_user_from_contest_form->submit_button_config['class_str'] = 'mt-2 btn btn-danger'; - $remove_user_from_contest_form->handle = function() { - global $contest; - $username = $_POST['remove_username']; + $vdata['group_id'] = $group_id; - DB::query("delete from contests_registrants where username = '{$username}' and contest_id = {$contest['id']}"); - updateContestPlayerNum($contest); - }; - $remove_user_from_contest_form->runAtServer(); + return ''; + }, + null + ); + $add_group_to_contest_form->submit_button_config['align'] = 'compressed'; + $add_group_to_contest_form->submit_button_config['text'] = '注册该小组中的用户'; + $add_group_to_contest_form->handle = function (&$vdata) { + $users = queryGroupUsers($vdata['group_id']); - $force_set_user_participated_form = new UOJForm('force_set_user_participated'); - $force_set_user_participated_form->addInput('force_set_username', 'text', '用户名', '', - function ($x) { - global $contest; + foreach ($users as $user) { + UOJContest::cur()->userRegister($user); + } + }; + $add_group_to_contest_form->runAtServer(); - if (!validateUsername($x)) { - return '用户名不合法'; - } + $remove_user_from_contest_form = new UOJBs4Form('remove_user_from_contest'); + $remove_user_from_contest_form->addInput( + 'remove_username', + 'text', + '用户名', + '', + function ($username, &$vdata) { + $user = UOJUser::query($username); - $user = queryUser($x); - if (!$user) { - return '用户不存在'; - } + if (!$user) { + return '用户不存在'; + } - if (!hasRegistered($user, $contest)) { - return '该用户未报名'; - } + if (!UOJContest::cur()->userHasRegistered($user)) { + return '该用户未报名'; + } - return ''; - }, - null - ); - $force_set_user_participated_form->submit_button_config['align'] = 'compressed'; - $force_set_user_participated_form->submit_button_config['text'] = '强制参赛'; - $force_set_user_participated_form->submit_button_config['class_str'] = 'mt-2 btn btn-warning'; - $force_set_user_participated_form->handle = function() { - global $contest; - $username = $_POST['force_set_username']; + $vdata['user'] = $user; - DB::query("update contests_registrants set has_participated = 1 where username = '{$username}' and contest_id = {$contest['id']}"); - updateContestPlayerNum($contest); - }; - $force_set_user_participated_form->runAtServer(); - } + return ''; + }, + null + ); + $remove_user_from_contest_form->submit_button_config['align'] = 'compressed'; + $remove_user_from_contest_form->submit_button_config['text'] = '移除该用户'; + $remove_user_from_contest_form->submit_button_config['class_str'] = 'mt-2 btn btn-danger'; + $remove_user_from_contest_form->handle = function (&$vdata) { + UOJContest::cur()->userUnregister($vdata['user']); + }; + $remove_user_from_contest_form->runAtServer(); - $has_contest_permission = hasContestPermission($myUser, $contest); - $show_ip = $has_contest_permission; - - if ($contest['cur_progress'] == CONTEST_NOT_STARTED) { - $iHasRegistered = $myUser != null && hasRegistered($myUser, $contest); - - if ($iHasRegistered) { - $unregister_form = new UOJForm('unregister'); - $unregister_form->handle = function() { - global $myUser, $contest; - DB::query("delete from contests_registrants where username = '{$myUser['username']}' and contest_id = {$contest['id']}"); - updateContestPlayerNum($contest); + $force_set_user_participated_form = new UOJBs4Form('force_set_user_participated'); + $force_set_user_participated_form->addInput( + 'force_set_username', + 'text', + '用户名', + '', + function ($username, &$vdata) { + $user = UOJUser::query($username); + + if (!$user) { + return '用户不存在'; + } + + if (!UOJContest::cur()->userHasRegistered($user)) { + return '该用户未报名'; + } + + $vdata['user'] = $user; + + return ''; + }, + null + ); + $force_set_user_participated_form->submit_button_config['align'] = 'compressed'; + $force_set_user_participated_form->submit_button_config['text'] = '强制参赛'; + $force_set_user_participated_form->submit_button_config['class_str'] = 'mt-2 btn btn-warning'; + $force_set_user_participated_form->handle = function (&$vdata) { + UOJContest::cur()->markUserAsParticipated($vdata['user']); + }; + $force_set_user_participated_form->runAtServer(); +} + +if ($contest['cur_progress'] == CONTEST_NOT_STARTED) { + $iHasRegistered = UOJContest::cur()->userHasRegistered(Auth::user()); + + if ($iHasRegistered) { + if ($iHasRegistered && UOJContest::cur()->freeRegistration()) { + $unregister_form = new UOJBs4Form('unregister'); + $unregister_form->handle = function () { + UOJContest::cur()->userUnregister(Auth::user()); }; - $unregister_form->submit_button_config['align'] = 'right'; $unregister_form->submit_button_config['class_str'] = 'btn btn-danger btn-xs'; $unregister_form->submit_button_config['text'] = '取消报名'; $unregister_form->succ_href = "/contests"; - + $unregister_form->runAtServer(); } } - ?> +} +?> -

+

- - + +
已报名 @@ -189,64 +170,64 @@ printHTML(); ?>
- +
当前尚未报名,您可以 报名
-
+
#'.UOJLocale::get('username').''; - if ($show_ip) { - $header_row .= 'remote_addrhttp_x_forwarded_for'; - } - if ($has_contest_permission) { - $header_row .= '是否参赛'; - } - $header_row .= ''; +$header_row = '#' . UOJLocale::get('username') . ''; +if ($show_ip) { + $header_row .= 'remote_addrhttp_x_forwarded_for'; +} +if ($is_manager) { + $header_row .= '是否参赛'; +} +$header_row .= ''; - echoLongTable( - ['*'], - 'contests_registrants', - "contest_id = {$contest['id']}", - 'order by username desc', - $header_row, - function($contestant, $num) use ($myUser, $has_contest_permission, $show_ip, $has_participated) { - $user = queryUser($contestant['username']); +echoLongTable( + ['*'], + 'contests_registrants', + ['contest_id' => $contest['id']], + 'order by username desc', + $header_row, + function ($contestant, $num) use ($is_manager, $show_ip) { + $user = UOJUser::query($contestant['username']); - echo ''; - echo ''.$num.''; - echo ''.getUserLink($contestant['username']).''; - if ($show_ip) { - echo ''.$user['remote_addr'].''; - echo ''.$user['http_x_forwarded_for'].''; - } - if ($has_contest_permission) { - echo ''.($contestant['has_participated'] ? 'Yes' : 'No').''; - } - echo ''; - }, - [ - 'page_len' => 50, - 'get_row_index' => '', - 'div_classes' => ['table-responsive', 'card', 'mb-3'], - 'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'], - ] - ); - ?> + echo ''; + echo '' . $num . ''; + echo '' . getUserLink($user['username']) . ''; + if ($show_ip) { + echo '' . $user['remote_addr'] . ''; + echo '' . $user['http_x_forwarded_for'] . ''; + } + if ($is_manager) { + echo '' . ($contestant['has_participated'] ? 'Yes' : 'No') . ''; + } + echo ''; + }, + [ + 'page_len' => 50, + 'get_row_index' => '', + 'div_classes' => ['table-responsive', 'card', 'mb-3'], + 'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'], + ] +); +?> printHTML(); - } - if (isset($add_group_to_contest_form)) { - $add_group_to_contest_form->printHTML(); - } - if (isset($remove_user_from_contest_form)) { - $remove_user_from_contest_form->printHTML(); - } - if (isset($force_set_user_participated_form)) { - $force_set_user_participated_form->printHTML(); - } - ?> +if (isset($add_new_contestant_form)) { + $add_new_contestant_form->printHTML(); +} +if (isset($add_group_to_contest_form)) { + $add_group_to_contest_form->printHTML(); +} +if (isset($remove_user_from_contest_form)) { + $remove_user_from_contest_form->printHTML(); +} +if (isset($force_set_user_participated_form)) { + $force_set_user_participated_form->printHTML(); +} +?> diff --git a/web/app/controllers/contest_registration.php b/web/app/controllers/contest_registration.php index 674f069..9c0c832 100644 --- a/web/app/controllers/contest_registration.php +++ b/web/app/controllers/contest_registration.php @@ -1,75 +1,57 @@ CONTEST_IN_PROGRESS) { - redirectTo("/contest/{$contest['id']}"); - } - - $register_form = new UOJForm('register'); - $register_form->handle = function() use ($myUser, $contest) { - DB::query("replace into contests_registrants (username, contest_id, has_participated) values ('{$myUser['username']}', {$contest['id']}, 0)"); +Auth::check() || redirectToLogin(); +UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404(); +UOJContest::cur()->userCanRegister(Auth::user(), ['ensure' => true]); - updateContestPlayerNum($contest); - }; - $register_form->submit_button_config['class_str'] = 'btn btn-primary'; - $register_form->submit_button_config['text'] = '我已阅读规则,确认报名比赛'; - - if ($contest['cur_progress'] == CONTEST_IN_PROGRESS) { - $register_form->succ_href = "/contest/{$contest['id']}/confirm"; - } else { - $register_form->succ_href = "/contests"; - } - - $register_form->runAtServer(); - ?> - +$register_form = new UOJBs4Form('register'); +$register_form->handle = function () { + UOJContest::cur()->userRegister(Auth::user()); +}; +$register_form->submit_button_config['class_str'] = 'btn btn-primary'; +$register_form->submit_button_config['text'] = '我已阅读规则,确认报名比赛'; + +if (UOJContest::cur()->progress() == CONTEST_IN_PROGRESS) { + $register_form->succ_href = '/contest/' . UOJContest::info('id') . '/confirm'; +} else { + $register_form->succ_href = '/contests'; +} + +$register_form->runAtServer(); +?> + +
-
-

比赛规则

+
+

比赛规则

-

您即将报名比赛 “”,请在报名前仔细阅读以下比赛规则:

+

您即将报名比赛 “”,请在报名前仔细阅读以下比赛规则:

-
    - -
  • 本场比赛正在进行中,将于 结束。
  • - -
  • 本场比赛将于 开始,并于 结束。
  • - -
  • 比赛开始后点击 “确认参赛” 按钮才会被视为正式参赛,未正式参赛的选手不会显示在排行榜上。
  • - -
  • 本场比赛为 OI 赛制。比赛中途可以提交代码,但 只显示测样例的结果
  • - -
  • 本场比赛为 IOI 赛制。比赛时的提交会测试题目的全部数据,但无法查看数据点详情。
  • - -
  • 若选手在比赛中多次提交了同一题,则最后按照 最后一次不是 Compile Error 的提交 计算排行。
  • -
  • 比赛结束后会进行最终测试,最终测试后的排名为最终排名。
  • -
  • 比赛排名按分数为第一关键字,完成题目的总时间为第二关键字。完成题目的总时间等于完成每道题所花时间之和(无视掉爆零的题目)。
  • -
  • 请遵守比赛规则,一位选手在一场比赛内不得报名多个账号,选手之间不能交流或者抄袭代码,如果被检测到将以 0 分处理或者封禁。
  • -
+
    + progress() == CONTEST_IN_PROGRESS) : ?> +
  • 本场比赛正在进行中,将于 结束。
  • + +
  • 本场比赛将于 开始,并于 结束。
  • + +
  • 比赛开始后点击 “确认参赛” 按钮才会被视为正式参赛,未正式参赛的选手不会显示在排行榜上。
  • + basicRule() == 'OI') : ?> +
  • 本场比赛为 OI 赛制。比赛中途可以提交代码,但 只显示测样例的结果
  • + basicRule() == 'IOI') : ?> +
  • 本场比赛为 IOI 赛制。比赛时的提交会测试题目的全部数据,但无法查看数据点详情。
  • + basicRule() == 'ACM') : ?> +
  • 本场比赛为 ACM 赛制。
  • + +
  • 若选手在比赛中多次提交了同一题,则最后按照 最后一次不是 Compile Error 的提交 计算排行。
  • +
  • 比赛结束后会进行最终测试,最终测试后的排名为最终排名。
  • +
  • 比赛排名按分数为第一关键字,完成题目的总时间为第二关键字。完成题目的总时间等于完成每道题所花时间之和(无视掉爆零的题目)。
  • +
  • 请遵守比赛规则,一位选手在一场比赛内不得报名多个账号,选手之间不能交流或者抄袭代码,如果被检测到将以 0 分处理或者封禁。
  • +
- printHTML() ?> -
+ printHTML() ?> +
diff --git a/web/app/controllers/contests.php b/web/app/controllers/contests.php index aa8e348..1649ce8 100644 --- a/web/app/controllers/contests.php +++ b/web/app/controllers/contests.php @@ -1,108 +1,110 @@ {$contest['name']} -EOD; - genMoreContestInfo($contest); - if ($contest['cur_progress'] == CONTEST_NOT_STARTED) { - $cur_rest_second = $contest['start_time']->getTimestamp() - UOJTime::$time_now->getTimestamp(); - if ($cur_rest_second < $rest_second) { - $upcoming_contest_name = $contest['name']; - $upcoming_contest_href = "/contest/{$contest['id']}"; - $rest_second = $cur_rest_second; - } - if ($myUser != null && hasRegistered($myUser, $contest)) { - $contest_name_link .= ''.UOJLocale::get('contests::registered').''; - } else { - $contest_name_link .= ''.UOJLocale::get('contests::register').''; - } - } elseif ($contest['cur_progress'] == CONTEST_IN_PROGRESS) { - if (hasRegistered($myUser, $contest)) { - $contest_name_link .= ''.UOJLocale::get('contests::in progress').''; - } else { - $contest_name_link .= ''.UOJLocale::get('contests::in progress').''; - } - } elseif ($contest['cur_progress'] == CONTEST_PENDING_FINAL_TEST) { - $contest_name_link .= ''.UOJLocale::get('contests::pending final test').''; - } elseif ($contest['cur_progress'] == CONTEST_TESTING) { - $contest_name_link .= ''.UOJLocale::get('contests::final testing').''; - } elseif ($contest['cur_progress'] == CONTEST_FINISHED) { - $contest_name_link .= ''.UOJLocale::get('contests::ended').''; + $contest = new UOJContest($info); + + $contest_name_link = '' . $contest->info['name'] . ''; + + if ($contest->progress() == CONTEST_NOT_STARTED) { + $cur_rest_second = $contest->info['start_time']->getTimestamp() - UOJTime::$time_now->getTimestamp(); + if ($cur_rest_second < $rest_second) { + $upcoming_contest_name = $contest->info['name']; + $upcoming_contest_href = '/contest/' . $contest->info['id']; + $rest_second = $cur_rest_second; + } + if ($contest->userHasRegistered(Auth::user())) { + $contest_name_link .= '' . UOJLocale::get('contests::registered') . ''; + } else { + $contest_name_link .= '' . UOJLocale::get('contests::register') . ''; + } + } elseif ($contest->progress() == CONTEST_IN_PROGRESS) { + if ($contest->allowExtraRegistration() && !$contest->userHasRegistered(Auth::user())) { + $contest_name_link .= '' . UOJLocale::get('contests::register') . ' (' . UOJLocale::get('contests::in progress') . ')' . ''; + } else { + $contest_name_link .= '' . UOJLocale::get('contests::in progress') . ''; + } + } elseif ($contest->progress() == CONTEST_FINISHED) { + $contest_name_link .= '' . UOJLocale::get('contests::ended') . ''; + } else { + if ($contest->basicRule() == 'OI') { + if ($contest->progress() == CONTEST_PENDING_FINAL_TEST) { + $contest_name_link .= '' . UOJLocale::get('contests::pending final test') . ''; + } elseif ($contest->progress() == CONTEST_TESTING) { + $contest_name_link .= '' . UOJLocale::get('contests::final testing') . ''; + } + } elseif ($contest->basicRule() == 'ACM' || $contest->basicRule() == 'IOI') { + $contest_name_link .= '' . UOJLocale::get('contests::official results to be announced') . ''; } - - $last_hour = round($contest['last_min'] / 60, 2); - - $click_zan_block = getClickZanBlock('C', $contest['id'], $contest['zan']); - echo ''; - echo '', $contest_name_link, ''; - echo '', ''.$contest['start_time_str'].'', ''; - echo '', UOJLocale::get('hours', $last_hour), ''; - echo '', '', '', ' ×'.$contest['player_num'].'', ''; - echo '', '
'.$click_zan_block.'
', ''; - echo ''; } - ?> + + $last_hour = round($contest->info['last_min'] / 60, 2); + echo ''; + echo '', $contest_name_link, ''; + echo '', '' . $contest->info['start_time_str'] . '', ''; + echo '', UOJLocale::get('hours', $last_hour), ''; + echo '', '', '', ' ×' . $contest->info['player_num'] . '', ''; + echo '', '
' . ClickZans::getBlock('C', $contest->info['id'], $contest->info['zan']) . '
', ''; + echo ''; +} +?>
-

- -

+

+ +

- -
- -
- + +
+ +
+
-

+

'; - $table_header .= ''.UOJLocale::get('contests::contest name').''; - $table_header .= ''.UOJLocale::get('contests::start time').''; - $table_header .= ''.UOJLocale::get('contests::duration').''; - $table_header .= ''.UOJLocale::get('contests::the number of registrants').''; - $table_header .= ''.UOJLocale::get('appraisal').''; - $table_header .= ''; +$table_header = ''; +$table_header .= ''; +$table_header .= '' . UOJLocale::get('contests::contest name') . ''; +$table_header .= '' . UOJLocale::get('contests::start time') . ''; +$table_header .= '' . UOJLocale::get('contests::duration') . ''; +$table_header .= '' . UOJLocale::get('contests::the number of registrants') . ''; +$table_header .= '' . UOJLocale::get('appraisal') . ''; +$table_header .= ''; - $table_config = [ - 'page_len' => 40, - 'div_classes' => ['card', 'mb-3'], - 'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'], - ]; +$table_config = [ + 'page_len' => 40, + 'div_classes' => ['card', 'mb-3'], + 'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'], +]; - echoLongTable( - ['*'], - 'contests', - "status != 'finished'", - 'order by start_time asc, id asc', - $table_header, - echoContest, - $table_config - ); +echoLongTable( + ['*'], + 'contests', + [["status", "!=", 'finished']], + 'order by start_time asc, id asc', + $table_header, + 'echoContest', + $table_config +); - if ($rest_second <= 86400) { - $notification = json_encode($upcoming_contest_name . " 已经开始了。是否要跳转到比赛页面?"); - echo <<
$upcoming_contest_name 倒计时
@@ -115,21 +117,23 @@ $('#contest-countdown').countdown($rest_second, function() {
EOD; - } - ?> +} +?> -

+

+ +echoLongTable( + ['*'], + 'contests', + ['status' => 'finished'], + 'order by start_time desc, id desc', + $table_header, + 'echoContest', + $table_config +); +?> + diff --git a/web/app/controllers/download.php b/web/app/controllers/download.php index f888e00..77a854e 100644 --- a/web/app/controllers/download.php +++ b/web/app/controllers/download.php @@ -1,140 +1,61 @@ userCanDownloadAttachments(Auth::user()) || UOJResponse::page404(); + } - switch ($_GET['type']) { - case 'attachment': - if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) { - become404Page(); - } - - $visible = isProblemVisibleToUser($problem, $myUser); - if (!$visible && $myUser != null) { - $result = DB::query("select contest_id from contests_problems where problem_id = {$_GET['id']}"); - while (list($contest_id) = DB::fetch($result, MYSQLI_NUM)) { - $contest = queryContest($contest_id); - genMoreContestInfo($contest); - if ($contest['cur_progress'] != CONTEST_NOT_STARTED && hasRegistered($myUser, $contest) && queryContestProblemRank($contest, $problem)) { - $visible = true; - } - } - } - if (!$visible) { - become404Page(); - } + $file_name = UOJProblem::cur()->getDataFolderPath() . '/download.zip'; + $download_name = 'problem_' . UOJProblem::info('id') . '_attachment.zip'; - $id = $_GET['id']; - - $file_name = "/var/uoj_data/$id/download.zip"; - $download_name = "problem_{$id}_attachment.zip"; - break; + break; - case 'problem': - if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) { - become404Page(); - } + case 'problem': + UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404(); - if (!hasProblemPermission($myUser, $problem)) { - become403Page(); - } + if (!$auth) { + UOJProblem::cur()->userCanDownloadTestData(Auth::user()) || UOJResponse::page404(); + } - $id = $_GET['id']; - $file_name = "/var/uoj_data/$id.zip"; - $download_name = "problem_$id.zip"; + $file_name = UOJProblem::cur()->getDataZipPath(); + $download_name = 'problem_' . UOJProblem::info('id') . '.zip'; - break; + break; - case 'testcase': - if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) { - become404Page(); - } + case 'submission': + if (!$auth) { + isSuperUser(Auth::user()) || UOJResponse::page404(); + } + $file_name = UOJContext::storagePath() . "/submission/{$_GET['id']}/{$_GET['rand_str_id']}"; + $download_name = "submission.zip"; + break; - if (!hasProblemPermission($myUser, $problem)) { - become404Page(); - } + case 'tmp': + if (!$auth) { + isSuperUser(Auth::user()) || UOJResponse::page404(); + } + $file_name = UOJContext::storagePath() . "/tmp/{$_GET['rand_str_id']}"; + $download_name = "tmp"; + break; - $id = $_GET['id']; - $problem_conf = getUOJConf("/var/uoj_data/$id/problem.conf"); + case 'testlib.h': + $file_name = UOJLocalRun::$judger_include_path . '/testlib.h'; + $download_name = 'testlib.h'; + break; - if ($problem_conf == -1 || $problem_conf == -2) { - become404Page(); - } + default: + UOJResponse::page404(); +} - if (!validateUInt($_GET['testcase_id'])) { - become404Page(); - } - - $testcase_id = $_GET['testcase_id']; - $testcase_group = isset($_GET['testcase_group']) && $_GET['testcase_group'] == 'extra' ? 'extra' : 'normal'; - - if ($testcase_group == 'extra') { - $n_ex_tests = getUOJConfVal($problem_conf, 'n_ex_tests', 0); - - if ($testcase_id < 1 || $testcase_id > $n_ex_tests) { - become404Page(); - } - - switch ($_GET['testcase_type']) { - case 'input': - $file_name = "/var/uoj_data/$id/" . getUOJProblemExtraInputFileName($problem_conf, $testcase_id); - $download_name = getUOJProblemExtraInputFileName($problem_conf, $testcase_id); - break; - - case 'output': - $file_name = "/var/uoj_data/$id/" . getUOJProblemExtraOutputFileName($problem_conf, $testcase_id); - $download_name = getUOJProblemExtraOutputFileName($problem_conf, $testcase_id); - break; - - default: - become404Page(); - } - } else { - $n_tests = getUOJConfVal($problem_conf, 'n_tests', 10); - - if ($testcase_id < 1 || $testcase_id > $n_tests) { - become404Page(); - } - - switch ($_GET['testcase_type']) { - case 'input': - $file_name = "/var/uoj_data/$id/" . getUOJProblemInputFileName($problem_conf, $testcase_id); - $download_name = getUOJProblemInputFileName($problem_conf, $testcase_id); - break; - case 'output': - $file_name = "/var/uoj_data/$id/" . getUOJProblemOutputFileName($problem_conf, $testcase_id); - $download_name = getUOJProblemOutputFileName($problem_conf, $testcase_id); - break; - default: - become404Page(); - } - } - - break; - - case 'testlib.h': - $file_name = "/opt/uoj/judger/uoj_judger/include/testlib.h"; - $download_name = "testlib.h"; - break; - - default: - become404Page(); - } - - $finfo = finfo_open(FILEINFO_MIME); - $mimetype = finfo_file($finfo, $file_name); - if ($mimetype === false) { - become404Page(); - } - finfo_close($finfo); - - header("X-Sendfile: $file_name"); - header("Content-type: $mimetype"); - header("Content-Disposition: attachment; filename=$download_name"); - ?> +UOJResponse::xsendfile($file_name, ['attachment' => $download_name]); diff --git a/web/app/controllers/faq.php b/web/app/controllers/faq.php index 9647fce..557940f 100644 --- a/web/app/controllers/faq.php +++ b/web/app/controllers/faq.php @@ -1,122 +1,120 @@ +requireLib('bootstrap5'); +requireLib('hljs'); +requireLib('mathjax'); +?>
- -
+ +
+
+
+

常见问题及其解答 (FAQ)

-
-
-

常见问题及其解答 (FAQ)

+
是什么
+

+ 见 https://sjzezoj.com/blogs/1。 +

-
是什么
-

- 见 https://sjzezoj.com/blogs/1。 -

+
测评环境
+

评测机的系统版本是 Ubuntu Server 22.04 LTS。

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
语言版本编译命令
Cgcc 11.2.0gcc -o code code.c -lm -O2 -DONLINE_JUDGE
C++g++ 11.2.0g++ -o code code.cpp -lm -O2 -DONLINE_JUDGE(语言版本默认为 C++14,如选择其他版本还会添加 -std= 参数)
Pascalfpc 3.2.2fpc code.pas -O2
Python 2Python 2.7.18预先编译为优化过的字节码 .pyo 文件
Python 3Python 3.10.6
Java 8OpenJDK 1.8.0_342javac code.java
Java 11OpenJDK 11.0.16
Java 17OpenJDK 17.0.4
+
+

以上信息仅供参考,实际评测环境可能会有变动。

-
测评环境
-

评测机的系统版本是 Ubuntu Server 22.04 LTS。

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
语言版本编译命令
Cgcc 11.2.0gcc -o code code.c -lm -O2 -DONLINE_JUDGE
C++g++ 11.2.0g++ -o code code.cpp -lm -O2 -DONLINE_JUDGE(语言版本默认为 C++14,如选择其他版本还会添加 -std= 参数)
Pascalfpc 3.2.2fpc code.pas -O2
Python 2Python 2.7.18预先编译为优化过的字节码 .pyo 文件
Python 3Python 3.10.6
Java 8OpenJDK 1.8.0_342javac code.java
Java 11OpenJDK 11.0.16
Java 17OpenJDK 17.0.4
+
如何上传头像
+

+ 不提供头像存储服务。每到一个网站都要上传一个头像挺烦的对不对?我们支持 Gravatar,请使用 Gravatar 吧!Gravatar 是一个全球的头像存储服务,你的头像将会与你的电子邮箱绑定。在各大网站比如各种 Wordpress 还有各种 OJ 比如 Vijos、Contest Hunter 上,只要你电子邮箱填对了,那么你的头像也就立即能显示了! +

+

+ 快使用 Gravatar 吧!Gravatar 地址:https://cn.gravatar.com。进去后注册个帐号然后与邮箱绑定并上传头像,就 OK 啦! +

+

+ 上不去 Gravatar?没关系,我们现在也支持 QQ 头像了!你只需要前往 “更改个人信息” 页面填写自己的 QQ 号,并将 “头像来源” 选为 “QQ” 就可以让你的 QQ 头像显示在 S2OJ 上啦! +

+ +
递归 107 层怎么没爆栈啊
+

+ 没错就是这样!除非是特殊情况, 测评程序时的栈大小与该题的空间限制是相等的! +

+ +
联系方式
+

+ 题目相关问题请联系各校区的竞赛教练以及题目管理员。 +

+

+ 系统相关问题请邮件联系 baoshuoi@baoshuo.ren) + 和 nekko1139855151@qq.com)。 +

+ +
开源项目
+

+ 的源代码存放于 + https://github.com/renbaoshuo/S2OJ。 + 如果你网不太好,打不开 GitHub 的话,也可以点击 https://git.m.ac/baoshuo/S2OJ 查看哦!这两个仓库的内容是一模一样的。 +

+ +
用户手册
+

+ 请移步 S2OJ 使用文档。 +

+
+
+
-

以上信息仅供参考,实际评测环境可能会有变动。

-
如何上传头像
-

- 不提供头像存储服务。每到一个网站都要上传一个头像挺烦的对不对?我们支持 Gravatar,请使用 Gravatar 吧!Gravatar 是一个全球的头像存储服务,你的头像将会与你的电子邮箱绑定。在各大网站比如各种 Wordpress 还有各种 OJ 比如 Vijos、Contest Hunter 上,只要你电子邮箱填对了,那么你的头像也就立即能显示了! -

-

- 快使用 Gravatar 吧!Gravatar 地址:https://cn.gravatar.com。进去后注册个帐号然后与邮箱绑定并上传头像,就 OK 啦! -

-

- 上不去 Gravatar?没关系,我们现在也支持 QQ 头像了!你只需要前往 “更改个人信息” 页面填写自己的 QQ 号,并将 “头像来源” 选为 “QQ” 就可以让你的 QQ 头像显示在 S2OJ 上啦! -

- -
递归 107 层怎么没爆栈啊
-

- 没错就是这样!除非是特殊情况, 测评程序时的栈大小与该题的空间限制是相等的! -

- -
联系方式
-

- 题目相关问题请联系各校区的竞赛教练以及题目管理员。 -

-

- 系统相关问题请邮件联系 baoshuoi@baoshuo.ren) - 和 nekko1139855151@qq.com)。 -

- -
开源项目
-

- 的源代码存放于 - https://github.com/renbaoshuo/S2OJ。 - 如果你网不太好,打不开 GitHub 的话,也可以点击 https://git.m.ac/baoshuo/S2OJ 查看哦!这两个仓库的内容是一模一样的。 -

- -
用户手册
-

- 请移步 S2OJ 使用文档。 -

- -
- - -
- - - + +
diff --git a/web/app/controllers/forgot_pw.php b/web/app/controllers/forgot_pw.php index 357bbd4..f0fa505 100644 --- a/web/app/controllers/forgot_pw.php +++ b/web/app/controllers/forgot_pw.php @@ -1,7 +1,7 @@ addInput('username', 'text', '用户名', '', function($username, &$vdata) { if (!validateUsername($username)) { diff --git a/web/app/controllers/group.php b/web/app/controllers/group.php index 7855f51..fa26f7e 100644 --- a/web/app/controllers/group.php +++ b/web/app/controllers/group.php @@ -4,14 +4,10 @@ requirePHPLib('judger'); requirePHPLib('data'); - if (!Auth::check() && UOJConfig::$data['switch']['force-login']) { + if (!Auth::check()) { redirectToLogin(); } - if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) { - become403Page(); - } - $group_id = $_GET['id']; if (!validateUInt($group_id) || !($group = queryGroup($group_id))) { become404Page(); @@ -30,7 +26,7 @@
-

+

[隐藏] @@ -51,7 +47,7 @@
-

+

@@ -68,7 +64,7 @@
-

+

    @@ -92,7 +88,7 @@
    -

    +

    -

    +

    -

    +

    作业:

      diff --git a/web/app/controllers/group_manage.php b/web/app/controllers/group_manage.php index d06ed82..deca22d 100644 --- a/web/app/controllers/group_manage.php +++ b/web/app/controllers/group_manage.php @@ -43,7 +43,7 @@ } if ($cur_tab == 'profile') { - $update_profile_form = new UOJForm('update_profile'); + $update_profile_form = new UOJBs4Form('update_profile'); $update_profile_form->addVInput('name', 'text', '名称', $group['title'], function($title, &$vdata) { if ($title == '') { @@ -107,7 +107,7 @@ function(res) { $(window).scrollTop(0); } EOD); - $update_profile_form->submit_button_config['margin_class'] = 'mt-3'; + $update_profile_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3'; $update_profile_form->submit_button_config['text'] = '更新'; $update_profile_form->runAtServer(); } elseif ($cur_tab == 'assignments') { @@ -127,7 +127,7 @@ EOD); dieWithAlert('移除成功!'); } - $add_new_assignment_form = new UOJForm('add_new_assignment'); + $add_new_assignment_form = new UOJBs4Form('add_new_assignment'); $add_new_assignment_form->addVInput('new_assignment_list_id', 'text', '题单 ID', '', function ($list_id, &$vdata) use ($group) { if (!validateUInt($list_id)) { @@ -177,7 +177,7 @@ EOD); 'message' => '题单 #' . $vdata['list_id'] . ' 已经被添加到作业列表中,结束时间为 ' . $vdata['end_time']->format('Y-m-d H:i:s') . '。' ]); }; - $add_new_assignment_form->submit_button_config['margin_class'] = 'mt-3'; + $add_new_assignment_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3'; $add_new_assignment_form->submit_button_config['text'] = '添加'; $add_new_assignment_form->setAjaxSubmit(<<addVInput('new_username', 'text', '用户名', '', function ($username, &$vdata) { global $group_id; @@ -246,7 +246,7 @@ EOD); }, null ); - $add_new_user_form->submit_button_config['margin_class'] = 'mt-3'; + $add_new_user_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3'; $add_new_user_form->submit_button_config['text'] = '添加'; $add_new_user_form->handle = function(&$vdata) use ($group) { DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')"); @@ -277,7 +277,7 @@ EOD); ?> -

      +

      (ID: #) 管理 diff --git a/web/app/controllers/groups.php b/web/app/controllers/groups.php index 0a856d9..e645d0d 100644 --- a/web/app/controllers/groups.php +++ b/web/app/controllers/groups.php @@ -1,57 +1,50 @@ handle = function() { - DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)"); - }; - $new_group_form->submit_button_config['align'] = 'right'; - $new_group_form->submit_button_config['class_str'] = 'btn btn-primary'; - $new_group_form->submit_button_config['text'] = UOJLocale::get('add new group'); - $new_group_form->submit_button_config['smart_confirm'] = ''; - $new_group_form->runAtServer(); - } - ?> +if (isSuperUser($myUser)) { + $new_group_form = new UOJBs4Form('new_group'); + $new_group_form->handle = function () { + DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)"); + }; + $new_group_form->submit_button_config['align'] = 'right'; + $new_group_form->submit_button_config['class_str'] = 'btn btn-primary'; + $new_group_form->submit_button_config['text'] = UOJLocale::get('add new group'); + $new_group_form->submit_button_config['smart_confirm'] = ''; + $new_group_form->runAtServer(); +} +?>
      + +
      + +
      +

      + +

      - -
      + +
      + printHTML(); ?> +
      + - -
      +
      + -

      - -

      - - -
      - printHTML(); ?> -
      - - -
      - - - ID {$groups_caption} @@ -59,52 +52,58 @@ EOD; - if (isSuperUser($myUser)) { - $cond = "1"; - } else { - $cond = 'is_hidden = 0'; - } + if (isSuperUser(Auth::user())) { + $cond = "1"; + } else { + $cond = ["is_hidden" => false]; + } - echoLongTable( - ['a.id as group_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.username) as user_count'], - "`groups` a left join groups_users b on a.id = b.group_id", - $cond, - 'group by a.id order by a.id asc', - $header, - function ($group) use ($myUser) { - echo ''; - echo ''; - echo '#', $group['group_id'], ''; - - echo ''; - echo '', $group['title'], ''; - if ($group['is_hidden']) { - echo ' ', UOJLocale::get('hidden'), ' '; - } - echo ''; - - echo "{$group['user_count']}"; - - echo ''; - }, - [ - 'page_len' => 40, - 'div_classes' => ['card', 'my-3'], - 'table_classes' => ['table', 'uoj-table', 'mb-0'], - 'head_pagination' => true, - 'pagination_table' => "`groups`", - ] - ); - ?> + echoLongTable( + ['id', 'title', 'is_hidden'], + "`groups`", + $cond, + 'order by id asc', + $header, + function ($group) { + $users_count = DB::selectCount([ + "select count(*)", + "from", "groups_users", + "where", [ + "group_id" => $group['id'], + ], + ]); - -
      + echo ''; + echo ''; + echo '#', $group['id'], ''; - - + echo ''; + echo '', $group['title'], ''; + if ($group['is_hidden']) { + echo ' ', UOJLocale::get('hidden'), ' '; + } + echo ''; + echo "{$users_count}"; + + echo ''; + }, + [ + 'page_len' => 40, + 'div_classes' => ['card', 'my-3'], + 'table_classes' => ['table', 'uoj-table', 'mb-0'], + 'head_pagination' => true, + ] + ); + ?> + +
      + + + +
      diff --git a/web/app/controllers/hack.php b/web/app/controllers/hack.php index 0977354..5d7b48e 100644 --- a/web/app/controllers/hack.php +++ b/web/app/controllers/hack.php @@ -1,101 +1,117 @@ setProblem() || UOJResponse::page404(); +UOJHack::cur()->userCanView(Auth::user(), ['ensure' => true]); - if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) { - become403Page(); - } +if (UOJHack::cur()->setSubmission()) { + UOJHack::cur()->submission->setAsCur(); + UOJSubmission::cur()->setProblem(['problem' => UOJHack::cur()->problem]) || UOJResponse::page404(); + UOJSubmission::cur()->userCanView(Auth::user(), ['ensure' => true]); +} - if (!validateUInt($_GET['id']) || !($hack = queryHack($_GET['id']))) { - become404Page(); - } +if (UOJHack::cur()->userCanDelete(Auth::user())) { + $delete_form = new UOJBs4Form('delete'); + $delete_form->handle = function () { + DB::delete([ + "delete from hacks", + "where", ["id" => UOJHack::info('id')] + ]); + }; + $delete_form->submit_button_config['class_str'] = 'btn btn-danger'; + $delete_form->submit_button_config['text'] = '删除此 Hack'; + $delete_form->submit_button_config['align'] = 'end'; + $delete_form->submit_button_config['smart_confirm'] = ''; + $delete_form->succ_href = "/hacks"; + $delete_form->runAtServer(); +} - $submission = querySubmission($hack['submission_id']); - $problem = queryProblemBrief($submission['problem_id']); - $problem_extra_config = getProblemExtraConfig($problem); +if (UOJHack::cur()->userCanReview(Auth::user())) { + $addex_form = new UOJBs4Form('addex'); + $addex_form->handle = function () { + $input = UOJContext::storagePath() . UOJHack::info('input'); + $new_in = "{$input}_in"; + $new_out = "{$input}_out"; + $reason = null; + $err = dataAddHackPoint(UOJHack::cur()->problem->info, $new_in, $new_out, $reason, Auth::user()); + $err === '' || UOJResponse::message($err); + unlink($new_in); + unlink($new_out); + DB::update([ + "update hacks", + "set", [ + 'status' => 'Judged', + ], "where", ['id' => UOJHack::info('id')] + ]); + }; + $addex_form->submit_button_config['class_str'] = 'btn btn-danger mt-3'; + $addex_form->submit_button_config['text'] = '确认无误,添加到测试数据'; + $addex_form->submit_button_config['align'] = 'end'; + $addex_form->submit_button_config['smart_confirm'] = ''; + $addex_form->succ_href = "/hacks"; + $addex_form->runAtServer(); +} - if ($submission['contest_id']) { - $contest = queryContest($submission['contest_id']); - genMoreContestInfo($contest); - } else { - $contest = null; - } +$perm = UOJHack::cur()->viewerCanSeeComponents(Auth::user()); +?> + - if (!isHackVisibleToUser($hack, $problem, $myUser)) { - become403Page(); - } - - if (isSuperUser($myUser)) { - $delete_form = new UOJForm('delete'); - $delete_form->handle = function() { - global $hack; - DB::query("delete from hacks where id = {$hack['id']}"); - }; - $delete_form->submit_button_config['class_str'] = 'btn btn-danger'; - $delete_form->submit_button_config['text'] = '删除此Hack'; - $delete_form->submit_button_config['align'] = 'right'; - $delete_form->submit_button_config['smart_confirm'] = ''; - $delete_form->succ_href = "/hacks"; - $delete_form->runAtServer(); - } - - $should_show_content = hasViewPermission($problem_extra_config['view_content_type'], $myUser, $problem, $submission); - $should_show_all_details = hasViewPermission($problem_extra_config['view_all_details_type'], $myUser, $problem, $submission); - $should_show_details = hasViewPermission($problem_extra_config['view_details_type'], $myUser, $problem, $submission); - $should_show_details_to_me = isSuperUser($myUser); - if ($hack['success'] === null) { - $should_show_all_details = false; - } - if (!isSubmissionFullVisibleToUser($submission, $contest, $problem, $myUser) - || !isHackFullVisibleToUser($hack, $contest, $problem, $myUser)) { - $should_show_content = $should_show_all_details = false; - } - - if ($should_show_all_details) { - $styler = new HackDetailsStyler(); - if (!$should_show_details) { - $styler->fade_all_details = true; - $styler->show_small_tip = false; - } - } - ?> - - -

      - +

      +

      - ''), $myUser) ?> - -
      -
      -

      + + +hasJudged()) : ?> + +
      +
      + +
      +
      + fade_all_details = true; + $styler->show_small_tip = false; + } + echoJudgmentDetails(UOJHack::info('details'), $styler, 'details'); + ?> + +
      +

      全部详细信息(仅管理员可见)

      + + +
      - - - fade_all_details): ?> -
      - - - -
      + -

      - +

      +

      - - - + + echoStatusTable(['show_actual_score' => $perm['score']], Auth::user()) ?> + + echoContent() ?> + + +

      提交记录信息损坏

      - + printHTML() ?> + + + printHTML() ?> + + diff --git a/web/app/controllers/hack_list.php b/web/app/controllers/hack_list.php index 938d4c3..4352082 100644 --- a/web/app/controllers/hack_list.php +++ b/web/app/controllers/hack_list.php @@ -1,60 +1,54 @@ $q_problem_id]; +} +if ($q_submission_id != null) { + $conds[] = ["submission_id" => $q_submission_id]; +} +if ($q_hacker != null) { + $conds[] = ["hacker" => $q_hacker]; +} +if ($q_owner != null) { + $conds[] = ["owner" => $q_owner]; +} - $q_problem_id = isset($_GET['problem_id']) && validateUInt($_GET['problem_id']) ? $_GET['problem_id'] : null; - $q_submission_id = isset($_GET['submission_id']) && validateUInt($_GET['submission_id']) ? $_GET['submission_id'] : null; - $q_hacker = isset($_GET['hacker']) && validateUsername($_GET['hacker']) ? $_GET['hacker'] : null; - $q_owner = isset($_GET['owner']) && validateUsername($_GET['owner']) ? $_GET['owner'] : null; - if ($q_problem_id != null) { - $conds[] = "problem_id = $q_problem_id"; +$selected_all = ' selected="selected"'; +$selected_succ = ''; +$selected_fail = ''; +if (isset($_GET['status']) && validateUInt($_GET['status'])) { + if ($_GET['status'] == 1) { + $selected_all = ''; + $selected_succ = ' selected="selected"'; + $conds[] = 'success = 1'; } - if ($q_submission_id != null) { - $conds[] = "submission_id = $q_submission_id"; + if ($_GET['status'] == 2) { + $selected_all = ''; + $selected_fail = ' selected="selected"'; + $conds[] = 'success = 0'; } - if ($q_hacker != null) { - $conds[] = "hacker = '$q_hacker'"; - } - if ($q_owner != null) { - $conds[] = "owner = '$q_owner'"; - } - - $selected_all = ' selected="selected"'; - $selected_succ =''; - $selected_fail =''; - if (isset($_GET['status']) && validateUInt($_GET['status'])) { - if ($_GET['status'] == 1) { - $selected_all = ''; - $selected_succ =' selected="selected"'; - $conds[] = 'success = 1'; - } - if ($_GET['status'] == 2) { - $selected_all = ''; - $selected_fail = ' selected="selected"'; - $conds[] = 'success = 0'; - } - } - - if ($conds) { - $cond = join($conds, ' and '); - } else { - $cond = '1'; - } - - ?> +} + +if ($conds) { + $cond = $conds; +} else { + $cond = '1'; +} + +?> -

      - +

      +

      @@ -77,10 +71,10 @@ diff --git a/web/app/controllers/image_hosting/get_image.php b/web/app/controllers/image_hosting/get_image.php index 1b8c2bb..589663c 100644 --- a/web/app/controllers/image_hosting/get_image.php +++ b/web/app/controllers/image_hosting/get_image.php @@ -1,24 +1,23 @@ Auth::id(), + ], +]); +$count = DB::selectCount([ + "select count(*)", + "from users_images", + "where", [ + "uploader" => Auth::id(), + ], +]); + +function throwError($msg) { + dieWithJsonData(['status' => 'error', 'message' => $msg]); +} + +$allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_WEBP]; +if ($_POST['image_upload_file_submit'] == 'submit') { + if (!crsf_check()) { + throwError('expired'); } - if (!isNormalUser($myUser)) { - become403Page(); + if (!isset($_SESSION['phrase']) || !PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha'])) { + throwError("bad_captcha"); } - $limit = $myUser['images_size_limit']; - $_result = DB::selectFirst("SELECT SUM(size), count(*) FROM `users_images` WHERE uploader = '{$myUser['username']}'"); - $used = $_result["SUM(size)"]; - $count = $_result["count(*)"]; - - function throwError($msg) { - dieWithJsonData(['status' => 'error', 'message' => $msg]); + if ($_FILES["image_upload_file"]["error"] > 0) { + throwError($_FILES["image_upload_file"]["error"]); } - $allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG]; - if ($_POST['image_upload_file_submit'] == 'submit') { - if (!crsf_check()) { - throwError('expired'); - } + if ($_FILES["image_upload_file"]["size"] > 5242880) { // 5 MB + throwError('too_large'); + } - if (!isset($_SESSION['phrase']) || !PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha'])) { - throwError("bad_captcha"); - } + if ($used + $_FILES["image_upload_file"]["size"] > $limit) { + throwError('storage_limit_exceeded'); + } - if ($_FILES["image_upload_file"]["error"] > 0) { - throwError($_FILES["image_upload_file"]["error"]); - } + $size = getimagesize($_FILES['image_upload_file']['tmp_name']); - if ($_FILES["image_upload_file"]["size"] > 5242880) { // 5 MB - throwError('too_large'); - } - - if ($used + $_FILES["image_upload_file"]["size"] > $limit) { - throwError('storage_limit_exceeded'); - } - - $size = getimagesize($_FILES['image_upload_file']['tmp_name']); - - if (!$size || !in_array($size[2], $allowedTypes)) { - throwError('not_a_image'); - } + if (!$size || !in_array($size[2], $allowedTypes)) { + throwError('not_a_image'); + } list($width, $height, $type) = $size; $hash = hash_file("sha256", $_FILES['image_upload_file']['tmp_name']) . Auth::id(); @@ -59,177 +65,177 @@ $watermark_text = ""; $hash .= "__no_watermark"; } elseif ($_POST['watermark'] == 'site_shortname_and_username') { - $watermark_text .= ' @'.Auth::id(); + $watermark_text .= ' @' . Auth::id(); $hash .= "__id"; } - $existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'"); + $existing_image = DB::selectFirst("SELECT * FROM users_images WHERE `hash` = '$hash'"); - if ($existing_image) { - dieWithJsonData(['status' => 'success', 'path' => $existing_image['path']]); - } + if ($existing_image) { + dieWithJsonData(['status' => 'success', 'path' => $existing_image['path']]); + } - $image = new Imagick($_FILES["image_upload_file"]["tmp_name"]); - $draw = new ImagickDraw(); - $draw->setFont(UOJContext::documentRoot().'/fonts/roboto-mono/RobotoMono-Bold.ttf'); - $draw->setFontSize($scale * 14); - $draw->setGravity(Imagick::GRAVITY_SOUTHEAST); - $draw->setFillColor("rgba(100,100,100,0.5)"); - $image->annotateImage($draw, 15, 10, 0, $watermark_text); - $draw->setFillColor("rgba(255,255,255,0.65)"); - $image->annotateImage($draw, 15 + $scale, 10 + $scale, 0, $watermark_text); - $image->setImageFormat('png'); - $image->writeImage(); + $image = new Imagick($_FILES["image_upload_file"]["tmp_name"]); + $draw = new ImagickDraw(); + $draw->setFont(UOJContext::documentRoot() . '/fonts/roboto-mono/RobotoMono-Bold.ttf'); + $draw->setFontSize($scale * 14); + $draw->setGravity(Imagick::GRAVITY_SOUTHEAST); + $draw->setFillColor("rgba(100,100,100,0.5)"); + $image->annotateImage($draw, 15, 10, 0, $watermark_text); + $draw->setFillColor("rgba(255,255,255,0.65)"); + $image->annotateImage($draw, 15 + $scale, 10 + $scale, 0, $watermark_text); + $image->setImageFormat('png'); + $image->writeImage(); - if (($size = filesize($_FILES["image_upload_file"]["tmp_name"])) > 5242880) { // 5 MB - throwError('too_large'); - } + if (($size = filesize($_FILES["image_upload_file"]["tmp_name"])) > 5242880) { // 5 MB + throwError('too_large'); + } - $filename = uojRandAvaiableFileName('/image_hosting/', 10, '.png'); - if (!move_uploaded_file($_FILES["image_upload_file"]["tmp_name"], UOJContext::storagePath().$filename)) { - throwError('unknown error'); - } + $filename = uojRandAvaiableFileName('/image_hosting/', 10, '.png'); + if (!move_uploaded_file($_FILES["image_upload_file"]["tmp_name"], UOJContext::storagePath() . $filename)) { + throwError('unknown error'); + } - DB::insert("INSERT INTO users_images (`path`, uploader, width, height, upload_time, size, `hash`) VALUES ('$filename', '{$myUser['username']}', $width, $height, now(), {$_FILES["image_upload_file"]["size"]}, '$hash')"); + DB::insert("INSERT INTO users_images (`path`, uploader, width, height, upload_time, size, `hash`) VALUES ('$filename', '{$myUser['username']}', $width, $height, now(), {$_FILES["image_upload_file"]["size"]}, '$hash')"); - dieWithJsonData(['status' => 'success', 'path' => $filename]); - } elseif ($_POST['image_delete_submit'] == 'submit') { - crsf_defend(); + dieWithJsonData(['status' => 'success', 'path' => $filename]); +} elseif ($_POST['image_delete_submit'] == 'submit') { + crsf_defend(); - $id = $_POST['image_delete_id']; - if (!validateUInt($id)) { - becomeMsgPage('ID 不合法。返回'); + $id = $_POST['image_delete_id']; + if (!validateUInt($id)) { + becomeMsgPage('ID 不合法。返回'); + } else { + $result = DB::selectFirst("SELECT * from users_images WHERE id = $id"); + if (!$result) { + becomeMsgPage('图片不存在。返回'); } else { - $result = DB::selectFirst("SELECT * from users_images WHERE id = $id"); - if (!$result) { - becomeMsgPage('图片不存在。返回'); - } else { - unlink(UOJContext::storagePath().$result['path']); - DB::delete("DELETE FROM users_images WHERE id = $id"); + unlink(UOJContext::storagePath() . $result['path']); + DB::delete("DELETE FROM users_images WHERE id = $id"); - header("Location: ". UOJContext::requestURI()); - die(); - } + header("Location: " . UOJContext::requestURI()); + die(); } } - ?> +} +?> -

      +

      -
      -
      -
      - - 点击此处选择图片 -
      - -