mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-11-08 10:18:42 +00:00
refactor: sync code from uoj.ac
This commit is contained in:
parent
26809917a1
commit
844c93da84
16
.github/workflows/test.yml
vendored
16
.github/workflows/test.yml
vendored
@ -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
|
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
uoj_data/
|
uoj_data/
|
||||||
|
uoj_data_1/
|
||||||
|
uoj_data_2/
|
||||||
.php-cs-fixer.cache
|
.php-cs-fixer.cache
|
||||||
docker-compose.local.yml
|
docker-compose.local.yml
|
||||||
|
16
.vscode/c_cpp_properties.json
vendored
Normal file
16
.vscode/c_cpp_properties.json
vendored
Normal file
@ -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
|
||||||
|
}
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"intelephense.format.braces": "k&r",
|
||||||
|
"intelephense.completion.triggerParameterHints": false
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
FROM mysql:5.7
|
FROM mysql:8.0
|
||||||
|
|
||||||
ADD . /opt/uoj_db
|
ADD . /opt/uoj_db
|
||||||
WORKDIR /opt/uoj_db
|
WORKDIR /opt/uoj_db
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
USE `app_uoj233`;
|
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', '');
|
||||||
|
@ -30,18 +30,18 @@ USE `app_uoj233`;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `best_ac_submissions` (
|
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,
|
`submitter` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`submission_id` int(11) NOT NULL,
|
`submission_id` int NOT NULL,
|
||||||
`used_time` int(11) NOT NULL,
|
`used_time` int NOT NULL,
|
||||||
`used_memory` int(11) NOT NULL,
|
`used_memory` int NOT NULL,
|
||||||
`tot_size` int(11) NOT NULL,
|
`tot_size` int NOT NULL,
|
||||||
`shortest_id` int(11) NOT NULL,
|
`shortest_id` int NOT NULL,
|
||||||
`shortest_used_time` int(11) NOT NULL,
|
`shortest_used_time` int NOT NULL,
|
||||||
`shortest_used_memory` int(11) NOT NULL,
|
`shortest_used_memory` int NOT NULL,
|
||||||
`shortest_tot_size` int(11) NOT NULL,
|
`shortest_tot_size` int NOT NULL,
|
||||||
PRIMARY KEY (`problem_id`,`submitter`)
|
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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -60,16 +60,20 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `blogs` (
|
CREATE TABLE `blogs` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`title` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
`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,
|
`post_time` datetime NOT NULL,
|
||||||
|
`active_time` datetime NOT NULL,
|
||||||
`poster` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`poster` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`content_md` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
`content_md` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`zan` int(11) NOT NULL,
|
`zan` int NOT NULL DEFAULT '0',
|
||||||
`is_hidden` tinyint(1) NOT NULL,
|
`is_hidden` tinyint(1) NOT NULL,
|
||||||
`type` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'B',
|
`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;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -89,14 +93,19 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `blogs_comments` (
|
CREATE TABLE `blogs_comments` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`blog_id` int(11) NOT NULL,
|
`blog_id` int NOT NULL,
|
||||||
`content` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
`content` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`post_time` datetime NOT NULL,
|
`post_time` datetime NOT NULL,
|
||||||
`poster` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`poster` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`zan` int(11) NOT NULL,
|
`zan` int NOT NULL,
|
||||||
`reply_id` int(11) NOT NULL,
|
`reply_id` int NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
`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;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -116,8 +125,8 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `blogs_tags` (
|
CREATE TABLE `blogs_tags` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`blog_id` int(11) NOT NULL,
|
`blog_id` int NOT NULL,
|
||||||
`tag` varchar(30) NOT NULL,
|
`tag` varchar(30) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `blog_id` (`blog_id`),
|
KEY `blog_id` (`blog_id`),
|
||||||
@ -143,8 +152,8 @@ UNLOCK TABLES;
|
|||||||
CREATE TABLE `click_zans` (
|
CREATE TABLE `click_zans` (
|
||||||
`type` char(2) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`type` char(2) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`target_id` int(11) NOT NULL,
|
`target_id` int NOT NULL,
|
||||||
`val` tinyint(4) NOT NULL DEFAULT '1',
|
`val` tinyint NOT NULL DEFAULT '1',
|
||||||
PRIMARY KEY (`type`,`target_id`,`username`)
|
PRIMARY KEY (`type`,`target_id`,`username`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
@ -165,15 +174,17 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests` (
|
CREATE TABLE `contests` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`name` varchar(50) NOT NULL,
|
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`start_time` datetime NOT NULL,
|
`start_time` datetime NOT NULL,
|
||||||
`last_min` int(11) NOT NULL,
|
`end_time` datetime GENERATED ALWAYS AS ((`start_time` + interval `last_min` minute)) VIRTUAL NOT NULL,
|
||||||
`player_num` int(11) NOT NULL,
|
`last_min` int NOT NULL,
|
||||||
`status` varchar(50) NOT NULL,
|
`player_num` int NOT NULL DEFAULT '0',
|
||||||
`extra_config` varchar(200) NOT NULL,
|
`status` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`zan` int(11) NOT NULL,
|
`extra_config` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '{}',
|
||||||
PRIMARY KEY (`id`)
|
`zan` int NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `status` (`status`,`id`) USING BTREE
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -193,15 +204,17 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests_asks` (
|
CREATE TABLE `contests_asks` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`contest_id` int(11) NOT NULL,
|
`contest_id` int NOT NULL,
|
||||||
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`question` text NOT NULL,
|
`question` text NOT NULL,
|
||||||
`answer` text NOT NULL,
|
`answer` text NOT NULL,
|
||||||
`post_time` datetime NOT NULL,
|
`post_time` datetime NOT NULL,
|
||||||
`reply_time` datetime NOT NULL,
|
`reply_time` datetime NOT NULL,
|
||||||
`is_hidden` tinyint(1) DEFAULT '0',
|
`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;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -221,7 +234,7 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests_notice` (
|
CREATE TABLE `contests_notice` (
|
||||||
`contest_id` int(11) NOT NULL,
|
`contest_id` int NOT NULL,
|
||||||
`title` varchar(30) NOT NULL,
|
`title` varchar(30) NOT NULL,
|
||||||
`content` varchar(500) NOT NULL,
|
`content` varchar(500) NOT NULL,
|
||||||
`time` datetime NOT NULL,
|
`time` datetime NOT NULL,
|
||||||
@ -246,7 +259,7 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests_permissions` (
|
CREATE TABLE `contests_permissions` (
|
||||||
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`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`)
|
PRIMARY KEY (`username`,`contest_id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
@ -267,10 +280,11 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests_problems` (
|
CREATE TABLE `contests_problems` (
|
||||||
`problem_id` int(11) NOT NULL,
|
`problem_id` int NOT NULL,
|
||||||
`contest_id` int(11) NOT NULL,
|
`contest_id` int NOT NULL,
|
||||||
`dfn` int(11) NOT NULL DEFAULT 0,
|
`level` int NOT NULL DEFAULT 0,
|
||||||
PRIMARY KEY (`problem_id`,`contest_id`)
|
PRIMARY KEY (`problem_id`,`contest_id`),
|
||||||
|
KEY `contest_id` (`contest_id`,`problem_id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -291,9 +305,9 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests_registrants` (
|
CREATE TABLE `contests_registrants` (
|
||||||
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`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,
|
`has_participated` tinyint(1) NOT NULL,
|
||||||
`rank` int(11) NOT NULL,
|
`final_rank` int NOT NULL,
|
||||||
PRIMARY KEY (`contest_id`,`username`)
|
PRIMARY KEY (`contest_id`,`username`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
@ -314,12 +328,14 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests_submissions` (
|
CREATE TABLE `contests_submissions` (
|
||||||
`contest_id` int(11) NOT NULL,
|
`contest_id` int NOT NULL,
|
||||||
`submitter` varchar(20) NOT NULL,
|
`submitter` varchar(20) NOT NULL,
|
||||||
`problem_id` int(11) NOT NULL,
|
`problem_id` int NOT NULL,
|
||||||
`submission_id` int(11) NOT NULL,
|
`submission_id` int NOT NULL,
|
||||||
`score` int(11) NOT NULL,
|
`score` int NOT NULL,
|
||||||
`penalty` int(11) NOT NULL,
|
`penalty` int NOT NULL,
|
||||||
|
`cnt` int DEFAULT NULL,
|
||||||
|
`n_failures` int DEFAULT NULL,
|
||||||
PRIMARY KEY (`contest_id`,`submitter`,`problem_id`)
|
PRIMARY KEY (`contest_id`,`submitter`,`problem_id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
@ -340,11 +356,13 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `contests_reviews` (
|
CREATE TABLE `contests_reviews` (
|
||||||
`contest_id` int(11) NOT NULL,
|
`contest_id` int NOT NULL,
|
||||||
`problem_id` int(11) NOT NULL DEFAULT 0,
|
`problem_id` int NOT NULL DEFAULT 0,
|
||||||
`poster` varchar(20) NOT NULL,
|
`poster` varchar(20) NOT NULL,
|
||||||
`content` text 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;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -364,7 +382,7 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `countdowns` (
|
CREATE TABLE `countdowns` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`title` text NOT NULL,
|
`title` text NOT NULL,
|
||||||
`end_time` datetime NOT NULL,
|
`end_time` datetime NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
@ -387,8 +405,8 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `custom_test_submissions` (
|
CREATE TABLE `custom_test_submissions` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`problem_id` int(10) unsigned NOT NULL,
|
`problem_id` int UNSIGNED NOT NULL,
|
||||||
`submit_time` datetime NOT NULL,
|
`submit_time` datetime NOT NULL,
|
||||||
`submitter` varchar(20) NOT NULL,
|
`submitter` varchar(20) NOT NULL,
|
||||||
`content` text NOT NULL,
|
`content` text NOT NULL,
|
||||||
@ -396,8 +414,10 @@ CREATE TABLE `custom_test_submissions` (
|
|||||||
`result` blob NOT NULL,
|
`result` blob NOT NULL,
|
||||||
`status` varchar(20) NOT NULL,
|
`status` varchar(20) NOT NULL,
|
||||||
`status_details` varchar(100) NOT NULL,
|
`status_details` varchar(100) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`),
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -416,10 +436,10 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `friend_links` (
|
CREATE TABLE `friend_links` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`title` varchar(40) NOT NULL,
|
`title` varchar(40) NOT NULL,
|
||||||
`url` varchar(100) NOT NULL,
|
`url` varchar(100) NOT NULL,
|
||||||
`level` int(10) NOT NULL DEFAULT 10,
|
`level` int NOT NULL DEFAULT 10,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
@ -440,7 +460,7 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `groups` (
|
CREATE TABLE `groups` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`title` text NOT NULL,
|
`title` text NOT NULL,
|
||||||
`announcement` text NOT NULL DEFAULT '',
|
`announcement` text NOT NULL DEFAULT '',
|
||||||
`is_hidden` tinyint(1) NOT NULL DEFAULT 0,
|
`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 @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `groups_assignments` (
|
CREATE TABLE `groups_assignments` (
|
||||||
`group_id` int(11) NOT NULL,
|
`group_id` int NOT NULL,
|
||||||
`list_id` int(11) NOT NULL,
|
`list_id` int NOT NULL,
|
||||||
`end_time` datetime 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;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!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 @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `groups_users` (
|
CREATE TABLE `groups_users` (
|
||||||
`group_id` int(11) NOT NULL,
|
`group_id` int NOT NULL,
|
||||||
`username` varchar(20) COLLATE utf8mb4_unicode_ci 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;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!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 @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `hacks` (
|
CREATE TABLE `hacks` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`problem_id` int(10) unsigned NOT NULL,
|
`problem_id` int UNSIGNED NOT NULL,
|
||||||
`contest_id` int(10) unsigned DEFAULT NULL,
|
`contest_id` int UNSIGNED DEFAULT NULL,
|
||||||
`submission_id` int(10) unsigned NOT NULL,
|
`submission_id` int UNSIGNED NOT NULL,
|
||||||
`hacker` varchar(20) NOT NULL,
|
`hacker` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`owner` varchar(20) NOT NULL,
|
`owner` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`input` varchar(150) NOT NULL,
|
`input` varchar(150) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`input_type` char(20) NOT NULL,
|
`input_type` char(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`submit_time` datetime NOT NULL,
|
`submit_time` datetime NOT NULL,
|
||||||
`judge_time` datetime DEFAULT NULL,
|
`judge_time` datetime DEFAULT NULL,
|
||||||
`success` tinyint(1) DEFAULT NULL,
|
`success` tinyint(1) DEFAULT NULL,
|
||||||
|
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`details` blob NOT NULL,
|
`details` blob NOT NULL,
|
||||||
`is_hidden` tinyint(1) NOT NULL,
|
`is_hidden` tinyint(1) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `submission_id` (`submission_id`),
|
KEY `submission_id` (`submission_id`),
|
||||||
KEY `is_hidden` (`is_hidden`,`problem_id`)
|
KEY `is_hidden` (`is_hidden`,`problem_id`),
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -539,11 +565,14 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `judger_info` (
|
CREATE TABLE `judger_info` (
|
||||||
`judger_name` varchar(50) NOT NULL,
|
`judger_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
|
`password` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`ip` char(20) 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`)
|
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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -555,6 +584,26 @@ LOCK TABLES `judger_info` WRITE;
|
|||||||
/*!40000 ALTER TABLE `judger_info` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `judger_info` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
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`
|
-- Table structure for table `problems`
|
||||||
--
|
--
|
||||||
@ -562,18 +611,20 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `problems` (
|
CREATE TABLE `problems` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||||
`title` text NOT NULL,
|
`title` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`uploader` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`uploader` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`is_hidden` tinyint(1) NOT NULL DEFAULT '0',
|
`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',
|
`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',
|
`zan` int(11) NOT NULL DEFAULT '0',
|
||||||
`ac_num` int(11) NOT NULL DEFAULT '0',
|
`ac_num` int(11) NOT NULL DEFAULT '0',
|
||||||
`submit_num` int(11) NOT NULL DEFAULT '0',
|
`submit_num` int(11) NOT NULL DEFAULT '0',
|
||||||
PRIMARY KEY (`id`)
|
`assigned_to_judger` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'any',
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -592,11 +643,11 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `problems_contents` (
|
CREATE TABLE `problems_contents` (
|
||||||
`id` int(11) NOT NULL,
|
`id` int NOT NULL,
|
||||||
`statement` mediumtext NOT NULL,
|
`statement` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`statement_md` mediumtext NOT NULL,
|
`statement_md` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -616,9 +667,10 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `problems_permissions` (
|
CREATE TABLE `problems_permissions` (
|
||||||
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`username` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`problem_id` int(11) NOT NULL,
|
`problem_id` int NOT NULL,
|
||||||
PRIMARY KEY (`username`,`problem_id`)
|
PRIMARY KEY (`username`,`problem_id`),
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
KEY `problem_id` (`problem_id`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -637,9 +689,10 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `problems_solutions` (
|
CREATE TABLE `problems_solutions` (
|
||||||
`problem_id` int(11) NOT NULL,
|
`problem_id` int NOT NULL,
|
||||||
`blog_id` int(11) NOT NULL,
|
`blog_id` int NOT NULL,
|
||||||
PRIMARY KEY (`problem_id`, `blog_id`)
|
PRIMARY KEY (`problem_id`, `blog_id`),
|
||||||
|
KEY `problem_id` (`problem_id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -659,8 +712,8 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `problems_tags` (
|
CREATE TABLE `problems_tags` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`problem_id` int(11) NOT NULL,
|
`problem_id` int NOT NULL,
|
||||||
`tag` varchar(30) NOT NULL,
|
`tag` varchar(30) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `problem_id` (`problem_id`),
|
KEY `problem_id` (`problem_id`),
|
||||||
@ -684,7 +737,7 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `lists` (
|
CREATE TABLE `lists` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`title` text NOT NULL,
|
`title` text NOT NULL,
|
||||||
`description` text NOT NULL DEFAULT '',
|
`description` text NOT NULL DEFAULT '',
|
||||||
`is_hidden` tinyint(1) NOT NULL DEFAULT '0',
|
`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 @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `lists_problems` (
|
CREATE TABLE `lists_problems` (
|
||||||
`list_id` int(11) NOT NULL,
|
`list_id` int NOT NULL,
|
||||||
`problem_id` int(11) NOT NULL,
|
`problem_id` int NOT NULL,
|
||||||
PRIMARY KEY (`list_id`, `problem_id`)
|
PRIMARY KEY (`list_id`, `problem_id`),
|
||||||
|
KEY `list_id` (`list_id`)
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!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 @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `lists_tags` (
|
CREATE TABLE `lists_tags` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`list_id` int(11) NOT NULL,
|
`list_id` int NOT NULL,
|
||||||
`tag` varchar(30) NOT NULL,
|
`tag` varchar(30) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `list_id` (`list_id`),
|
KEY `list_id` (`list_id`),
|
||||||
@ -728,14 +782,14 @@ CREATE TABLE `lists_tags` (
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `search_requests` (
|
CREATE TABLE `search_requests` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int NOT NULL AUTO_INCREMENT,
|
||||||
`created_at` datetime NOT NULL,
|
`created_at` datetime NOT NULL,
|
||||||
`remote_addr` varchar(50) NOT NULL,
|
`remote_addr` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`type` enum('search','autocomplete') NOT NULL,
|
`type` enum('search','autocomplete') COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`cache_id` int(11) NOT NULL,
|
`cache_id` int NOT NULL,
|
||||||
`q` varchar(100) NOT NULL,
|
`q` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`content` text NOT NULL,
|
`content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`result` mediumtext NOT NULL,
|
`result` json NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `remote_addr` (`remote_addr`,`created_at`),
|
KEY `remote_addr` (`remote_addr`,`created_at`),
|
||||||
KEY `created_at` (`created_at`)
|
KEY `created_at` (`created_at`)
|
||||||
@ -758,27 +812,42 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `submissions` (
|
CREATE TABLE `submissions` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`problem_id` int(10) unsigned NOT NULL,
|
`problem_id` int UNSIGNED NOT NULL,
|
||||||
`contest_id` int(10) unsigned DEFAULT NULL,
|
`contest_id` int UNSIGNED DEFAULT NULL,
|
||||||
`submit_time` datetime NOT NULL,
|
`submit_time` datetime NOT NULL,
|
||||||
`submitter` varchar(20) NOT NULL,
|
`submitter` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`content` text NOT NULL,
|
`content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`language` varchar(15) NOT NULL,
|
`language` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`tot_size` int(11) 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,
|
`judge_time` datetime DEFAULT NULL,
|
||||||
`result` blob NOT NULL,
|
`judger` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||||
`status` varchar(20) NOT NULL,
|
`result` mediumblob NOT NULL,
|
||||||
`result_error` varchar(20) DEFAULT NULL,
|
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`score` int(11) DEFAULT NULL,
|
`result_error` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||||
`used_time` int(11) NOT NULL DEFAULT '0',
|
`score` int DEFAULT NULL,
|
||||||
`used_memory` int(11) NOT NULL DEFAULT '0',
|
`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,
|
`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`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `is_hidden` (`is_hidden`,`problem_id`),
|
KEY `status` (`status`,`id`),
|
||||||
KEY `score` (`problem_id`, `submitter`, `score`)
|
KEY `result_error` (`result_error`),
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -790,6 +859,83 @@ LOCK TABLES `submissions` WRITE;
|
|||||||
/*!40000 ALTER TABLE `submissions` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `submissions` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
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`
|
-- Table structure for table `user_info`
|
||||||
--
|
--
|
||||||
@ -797,32 +943,29 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `user_info` (
|
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,
|
`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 '',
|
`realname` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||||
`school` varchar(50) 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) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`email` varchar(50) NOT NULL,
|
`password` char(32) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`password` char(32) NOT NULL,
|
`svn_password` char(10) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`svn_password` char(10) NOT NULL,
|
`qq` bigint NOT NULL DEFAULT '0',
|
||||||
`qq` bigint(20) NOT NULL,
|
`sex` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'U',
|
||||||
`sex` char(1) NOT NULL DEFAULT 'U',
|
`ac_num` int NOT NULL DEFAULT 0,
|
||||||
`ac_num` int(11) NOT NULL,
|
|
||||||
`register_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`register_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`remote_addr` varchar(50) NOT NULL,
|
`last_login_time` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
`http_x_forwarded_for` varchar(50) NOT NULL,
|
`last_visit_time` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||||
`remember_token` char(60) NOT NULL,
|
`expiration_time` datetime DEFAULT NULL,
|
||||||
`motto` varchar(200) NOT NULL,
|
`remote_addr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||||
`last_login` timestamp NOT NULL DEFAULT 0,
|
`http_x_forwarded_for` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||||
`last_visited` timestamp NOT NULL DEFAULT 0,
|
`remember_token` char(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||||
`images_size_limit` int(11) UNSIGNED NOT NULL DEFAULT 104857600, /* 100 MiB */
|
`motto` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||||
`codeforces_handle` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
`extra` json NOT NULL,
|
||||||
`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',
|
|
||||||
PRIMARY KEY (`username`),
|
PRIMARY KEY (`username`),
|
||||||
KEY `ac_num` (`ac_num`,`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 */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -841,13 +984,13 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `users_images` (
|
CREATE TABLE `users_images` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`path` varchar(100) NOT NULL,
|
`path` varchar(100) NOT NULL,
|
||||||
`uploader` varchar(20) NOT NULL,
|
`uploader` varchar(20) NOT NULL,
|
||||||
`width` int(11) NOT NULL,
|
`width` int NOT NULL,
|
||||||
`height` int(11) NOT NULL,
|
`height` int NOT NULL,
|
||||||
`upload_time` datetime NOT NULL,
|
`upload_time` datetime NOT NULL,
|
||||||
`size` int(11) NOT NULL,
|
`size` int NOT NULL,
|
||||||
`hash` varchar(100) NOT NULL,
|
`hash` varchar(100) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `uploader` (`uploader`),
|
KEY `uploader` (`uploader`),
|
||||||
@ -874,13 +1017,16 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `user_msg` (
|
CREATE TABLE `user_msg` (
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`sender` varchar(20) NOT NULL,
|
`sender` varchar(20) NOT NULL,
|
||||||
`receiver` varchar(20) NOT NULL,
|
`receiver` varchar(20) NOT NULL,
|
||||||
`message` varchar(5000) NOT NULL,
|
`message` varchar(5000) NOT NULL,
|
||||||
`send_time` datetime NOT NULL,
|
`send_time` datetime NOT NULL,
|
||||||
`read_time` datetime DEFAULT 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;
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
@ -900,13 +1046,14 @@ UNLOCK TABLES;
|
|||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
/*!40101 SET character_set_client = utf8mb4 */;
|
/*!40101 SET character_set_client = utf8mb4 */;
|
||||||
CREATE TABLE `user_system_msg` (
|
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,
|
`title` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`content` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
`content` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`receiver` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
`receiver` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||||
`send_time` datetime NOT NULL,
|
`send_time` datetime NOT NULL,
|
||||||
`read_time` datetime DEFAULT 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;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./judger/
|
context: ./judger/
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
- USE_MIRROR=1
|
||||||
container_name: uoj-judger
|
container_name: uoj-judger
|
||||||
restart: always
|
restart: always
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
@ -44,6 +46,8 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: web/Dockerfile
|
dockerfile: web/Dockerfile
|
||||||
|
args:
|
||||||
|
- USE_MIRROR=1
|
||||||
container_name: uoj-web
|
container_name: uoj-web
|
||||||
restart: always
|
restart: always
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
FROM ubuntu:22.04
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
ARG CLONE_ADDFLAG
|
ARG CLONE_ADDFLAG
|
||||||
|
ARG USE_MIRROR
|
||||||
|
ENV USE_MIRROR $USE_MIRROR
|
||||||
|
SHELL ["/bin/bash", "-c"]
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
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
|
ADD . /opt/uoj_judger
|
||||||
WORKDIR /opt/uoj_judger
|
WORKDIR /opt/uoj_judger
|
||||||
|
|
||||||
# Install environment and set startup script
|
# Install environment and set startup script
|
||||||
RUN sh install.sh -p && echo "\
|
RUN sh install.sh -p && echo -e "\
|
||||||
#!/bin/sh\n\
|
#!/bin/sh\n\
|
||||||
if [ ! -f \"/opt/uoj_judger/.conf.json\" ]; then\n\
|
if [ ! -f \"/opt/uoj_judger/.conf.json\" ]; then\n\
|
||||||
cd /opt/uoj_judger && sh install.sh -i\n\
|
cd /opt/uoj_judger && sh install.sh -i\n\
|
||||||
|
@ -35,12 +35,15 @@ const std::vector<std::pair<const char *, const char *>> suffix_search_list = {
|
|||||||
{".code" , "" },
|
{".code" , "" },
|
||||||
{"20.cpp" , "C++20" },
|
{"20.cpp" , "C++20" },
|
||||||
{"17.cpp" , "C++17" },
|
{"17.cpp" , "C++17" },
|
||||||
{"14.cpp" , "C++14" },
|
{"14.cpp" , "C++" },
|
||||||
{"11.cpp" , "C++11" },
|
{"11.cpp" , "C++11" },
|
||||||
|
{"03.cpp" , "C++03" },
|
||||||
|
{"98.cpp" , "C++98" },
|
||||||
{".cpp" , "C++" },
|
{".cpp" , "C++" },
|
||||||
{".c" , "C" },
|
{".c" , "C" },
|
||||||
{".pas" , "Pascal" },
|
{".pas" , "Pascal" },
|
||||||
{"2.7.py" , "Python2.7"},
|
{"2.7.py" , "Python2.7"},
|
||||||
|
{"2.py" , "Python2.7"},
|
||||||
{".py" , "Python3" },
|
{".py" , "Python3" },
|
||||||
{"7.java" , "Java7" },
|
{"7.java" , "Java7" },
|
||||||
{"8.java" , "Java8" },
|
{"8.java" , "Java8" },
|
||||||
|
@ -1,18 +1,30 @@
|
|||||||
FROM ubuntu:22.04
|
FROM ubuntu:22.04
|
||||||
|
|
||||||
ARG CLONE_ADDFLAG
|
ARG CLONE_ADDFLAG
|
||||||
|
ARG USE_MIRROR
|
||||||
|
ENV USE_MIRROR $USE_MIRROR
|
||||||
|
SHELL ["/bin/bash", "-c"]
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
RUN dpkg -s gnupg 2>/dev/null || (apt-get update && apt-get install -y gnupg) &&\
|
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 &&\
|
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 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
|
(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
|
ADD . /opt/uoj
|
||||||
WORKDIR /opt/uoj
|
WORKDIR /opt/uoj
|
||||||
|
|
||||||
# Install environment and set startup script
|
# Install environment and set startup script
|
||||||
RUN sh web/install.sh -p && echo "\
|
RUN sh web/install.sh -p && echo -e "\
|
||||||
#!/bin/sh\n\
|
#!/bin/sh\n\
|
||||||
if [ ! -f \"/var/uoj_data/.UOJSetupDone\" ]; then\n\
|
if [ ! -f \"/var/uoj_data/.UOJSetupDone\" ]; then\n\
|
||||||
cd /opt/uoj/web && sh install.sh -i\n\
|
cd /opt/uoj/web && sh install.sh -i\n\
|
||||||
|
@ -21,12 +21,12 @@ return [
|
|||||||
'main' => [
|
'main' => [
|
||||||
'protocol' => 'http',
|
'protocol' => 'http',
|
||||||
'host' => '_httpHost_',
|
'host' => '_httpHost_',
|
||||||
'port' => 80
|
'port' => '80/443'
|
||||||
],
|
],
|
||||||
'blog' => [
|
'blog' => [
|
||||||
'protocol' => 'http',
|
'protocol' => 'http',
|
||||||
'host' => '_httpHost_',
|
'host' => '_httpHost_',
|
||||||
'port' => 80
|
'port' => '80/443'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'security' => [
|
'security' => [
|
||||||
@ -54,7 +54,6 @@ return [
|
|||||||
],
|
],
|
||||||
'switch' => [
|
'switch' => [
|
||||||
'blog-domain-mode' => 3,
|
'blog-domain-mode' => 3,
|
||||||
'force-login' => true,
|
|
||||||
'open-register' => false
|
'open-register' => false
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check()) {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser)) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!isSuperUser($myUser)) {
|
Auth::check() || redirectToLogin();
|
||||||
become403Page();
|
isSuperUser(Auth::user()) || UOJResponse::page403();
|
||||||
}
|
|
||||||
$time_form = new UOJForm('time');
|
$time_form = new UOJBs4Form('time');
|
||||||
$time_form->addVInput(
|
$time_form->addVInput(
|
||||||
'name', 'text', '比赛标题', 'New Contest',
|
'name',
|
||||||
|
'text',
|
||||||
|
'比赛标题',
|
||||||
|
'New Contest',
|
||||||
function ($name, &$vdata) {
|
function ($name, &$vdata) {
|
||||||
if ($name == '') {
|
if ($name == '') {
|
||||||
return '标题不能为空';
|
return '标题不能为空';
|
||||||
@ -38,7 +33,10 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$time_form->addVInput(
|
$time_form->addVInput(
|
||||||
'start_time', 'text', '开始时间', date("Y-m-d H:i:s"),
|
'start_time',
|
||||||
|
'text',
|
||||||
|
'开始时间',
|
||||||
|
date("Y-m-d H:i:s"),
|
||||||
function ($str, &$vdata) {
|
function ($str, &$vdata) {
|
||||||
try {
|
try {
|
||||||
$vdata['start_time'] = new DateTime($str);
|
$vdata['start_time'] = new DateTime($str);
|
||||||
@ -50,7 +48,10 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$time_form->addVInput(
|
$time_form->addVInput(
|
||||||
'last_min', 'text', '时长(单位:分钟)', 180,
|
'last_min',
|
||||||
|
'text',
|
||||||
|
'时长(单位:分钟)',
|
||||||
|
180,
|
||||||
function ($str, &$vdata) {
|
function ($str, &$vdata) {
|
||||||
if (!validateUInt($str)) {
|
if (!validateUInt($str)) {
|
||||||
return '必须为一个整数';
|
return '必须为一个整数';
|
||||||
@ -64,10 +65,12 @@
|
|||||||
);
|
);
|
||||||
$time_form->handle = function (&$vdata) {
|
$time_form->handle = function (&$vdata) {
|
||||||
$start_time_str = $vdata['start_time']->format('Y-m-d H:i:s');
|
$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')");
|
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->succ_href = "/contests";
|
||||||
$time_form->runAtServer();
|
$time_form->runAtServer();
|
||||||
@ -75,12 +78,12 @@
|
|||||||
<?php echoUOJPageHeader('添加比赛') ?>
|
<?php echoUOJPageHeader('添加比赛') ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
|
||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<h1 class="h2 card-title">添加比赛</h1>
|
<h1 class="card-title">添加比赛</h1>
|
||||||
|
|
||||||
<div class="w-full" style="max-width: 400px">
|
<div class="w-full" style="max-width: 400px">
|
||||||
<?php $time_form->printHTML(); ?>
|
<?php $time_form->printHTML(); ?>
|
||||||
@ -88,14 +91,13 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- end left col -->
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<?php uojIncludeView('sidebar', array()) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,73 +1,57 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
function echoBlogCell($blog) {
|
|
||||||
$level = $blog['level'];
|
|
||||||
|
|
||||||
switch ($level) {
|
|
||||||
case 0:
|
|
||||||
$level_str = '';
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
$level_str = '<span style="color:red">[三级置顶]</span> ';
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
$level_str = '<span style="color:red">[二级置顶]</span> ';
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
$level_str = '<span style="color:red">[一级置顶]</span> ';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '<tr>';
|
|
||||||
echo '<td>' . $level_str . getBlogLink($blog['id']) . '</td>';
|
|
||||||
echo '<td>' . getUserLink($blog['poster']) . '</td>';
|
|
||||||
echo '<td>' . $blog['post_time'] . '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
$header = <<<EOD
|
|
||||||
<tr>
|
|
||||||
<th width="60%">标题</th>
|
|
||||||
<th width="20%">发表者</th>
|
|
||||||
<th width="20%">发表日期</th>
|
|
||||||
</tr>
|
|
||||||
EOD;
|
|
||||||
$config = [
|
|
||||||
'page_len' => 40,
|
|
||||||
'div_classes' => ['card', 'my-3'],
|
|
||||||
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
|
||||||
];
|
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('announcements')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('announcements')) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
<h1>
|
||||||
<h1 class="h2">
|
|
||||||
<?= UOJLocale::get('announcements') ?>
|
<?= UOJLocale::get('announcements') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<?php echoLongTable(array('blogs.id', 'poster', 'title', 'post_time', 'zan', 'level'), 'important_blogs, blogs', 'is_hidden = 0 and important_blogs.blog_id = blogs.id', 'order by level desc, important_blogs.blog_id desc', $header, 'echoBlogCell', $config); ?>
|
<?php
|
||||||
|
echoLongTable(
|
||||||
|
['blogs.id', 'poster', 'title', 'post_time', 'zan', 'level'],
|
||||||
|
'important_blogs, blogs',
|
||||||
|
[
|
||||||
|
'is_hidden' => 0,
|
||||||
|
'important_blogs.blog_id' => DB::raw('blogs.id')
|
||||||
|
],
|
||||||
|
'order by level desc, important_blogs.blog_id desc',
|
||||||
|
<<<EOD
|
||||||
|
<tr>
|
||||||
|
<th width="60%">标题</th>
|
||||||
|
<th width="20%">发表者</th>
|
||||||
|
<th width="20%">发表日期</th>
|
||||||
|
</tr>
|
||||||
|
EOD,
|
||||||
|
function ($info) {
|
||||||
|
$blog = new UOJBlog($info);
|
||||||
|
|
||||||
|
echo '<tr>';
|
||||||
|
echo '<td>' . $blog->getLink(['show_level' => true, 'show_new_tag' => true]) . '</td>';
|
||||||
|
echo '<td>' . getUserLink($blog->info['poster']) . '</td>';
|
||||||
|
echo '<td>' . $blog->info['post_time'] . '</td>';
|
||||||
|
echo '</tr>';
|
||||||
|
},
|
||||||
|
[
|
||||||
|
'page_len' => 40,
|
||||||
|
'div_classes' => ['card', 'my-3'],
|
||||||
|
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<?php uojIncludeView('sidebar', array()) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
<!-- end right col -->
|
<!-- end right col -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
become403Page();
|
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($blog = queryBlog($_GET['id']))) {
|
redirectTo(HTML::blog_url(UOJBlog::info('poster'), '/post/' . UOJBlog::info('id'), ['escape' => false]));
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
redirectTo(HTML::blog_url($blog['poster'], '/post/'.$_GET['id'] . ($_GET['sub'] ?: '')));
|
|
||||||
?>
|
|
||||||
|
@ -2,28 +2,20 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('blogs')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('blogs')) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
|
||||||
<!-- title container -->
|
<!-- title container -->
|
||||||
<div class="d-flex flex-wrap justify-content-between align-items-center">
|
<div class="d-flex flex-wrap justify-content-between align-items-center">
|
||||||
|
<h1>
|
||||||
<h1 class="h2">
|
|
||||||
<?= UOJLocale::get("blogs overview") ?>
|
<?= UOJLocale::get("blogs overview") ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<?php if (Auth::check()) : ?>
|
||||||
<div class="text-end">
|
<div class="text-end">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="<?= HTML::blog_url(Auth::id(), '/') ?>" class="btn btn-secondary btn-sm">
|
<a href="<?= HTML::blog_url(Auth::id(), '/') ?>" class="btn btn-secondary btn-sm">
|
||||||
@ -35,6 +27,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
<!-- end title container -->
|
<!-- end title container -->
|
||||||
|
|
||||||
@ -46,21 +39,25 @@ echoLongTable(
|
|||||||
'order by post_time desc',
|
'order by post_time desc',
|
||||||
<<<EOD
|
<<<EOD
|
||||||
<tr>
|
<tr>
|
||||||
<th width="60%">标题</th>
|
<th>标题</th>
|
||||||
<th width="20%">发表者</th>
|
<th style="width:200px">发表者</th>
|
||||||
<th width="20%">发表日期</th>
|
<th style="width:200px">发表日期</th>
|
||||||
|
<th style="width:50px" class="text-center">评价</th>
|
||||||
</tr>
|
</tr>
|
||||||
EOD,
|
EOD,
|
||||||
function($blog) {
|
function ($info) {
|
||||||
|
$blog = new UOJBlog($info);
|
||||||
|
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
echo getBlogLink($blog['id']);
|
echo $blog->getLink();
|
||||||
if ($blog['is_hidden']) {
|
if ($blog->info['is_hidden']) {
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||||
}
|
}
|
||||||
echo '</td>';
|
echo '</td>';
|
||||||
echo '<td>' . getUserLink($blog['poster']) . '</td>';
|
echo '<td>' . getUserLink($blog->info['poster']) . '</td>';
|
||||||
echo '<td>' . $blog['post_time'] . '</td>';
|
echo '<td>' . $blog->info['post_time'] . '</td>';
|
||||||
|
echo '<td class="text-center">' . ClickZans::getCntBlock($blog->info['zan']) . '</td>';
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
@ -9,5 +9,3 @@ $_SESSION['phrase'] = $builder->getPhrase();
|
|||||||
|
|
||||||
header('Content-Type: image/jpeg');
|
header('Content-Type: image/jpeg');
|
||||||
$builder->build()->output();
|
$builder->build()->output();
|
||||||
|
|
||||||
?>
|
|
||||||
|
3
web/app/controllers/check_notice.php
Normal file
3
web/app/controllers/check_notice.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
die(json_encode(UOJNotice::fetch(UOJTime::str2time(UOJRequest::post('last_time')))));
|
@ -1,69 +1,24 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
function validateZan() {
|
function validateZan() {
|
||||||
if (!validateUInt($_POST['id'])) {
|
if (!validateUInt($_POST['id']))
|
||||||
return false;
|
return false;
|
||||||
}
|
if (!validateInt($_POST['delta']))
|
||||||
if (!validateInt($_POST['delta'])) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
if ($_POST['delta'] != 1 && $_POST['delta'] != -1)
|
||||||
if ($_POST['delta'] != 1 && $_POST['delta'] != -1) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
if (!ClickZans::getTable($_POST['type']))
|
||||||
if ($_POST['type'] != 'B' && $_POST['type'] != 'BC' && $_POST['type'] != 'P' && $_POST['type'] != 'C') {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!validateZan()) {
|
if (!validateZan()) {
|
||||||
die('<div class="text-danger">failed</div>');
|
die('<div class="text-danger">failed</div>');
|
||||||
}
|
}
|
||||||
if ($myUser == null) {
|
if (!Auth::check()) {
|
||||||
die('<div class="text-danger">please <a href="' . HTML::url('/login') . '">log in</a></div>');
|
die('<div class="text-danger">please <a href="' . HTML::url('/login') . '">log in</a></div>');
|
||||||
}
|
}
|
||||||
|
if (!ClickZans::canClickZan($_POST['id'], $_POST['type'], Auth::user())) {
|
||||||
$id = $_POST['id'];
|
die('<div class="text-danger">no permission</div>');
|
||||||
$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);
|
die(ClickZans::click($_POST['id'], $_POST['type'], Auth::user(), $_POST['delta'], $_POST['show-text']));
|
||||||
|
|
||||||
if ($cur != $delta) {
|
|
||||||
$row = DB::selectFirst("select zan from $table_name where id = $id");
|
|
||||||
if ($row == null) {
|
|
||||||
die('<div class="text-danger">failed</div>');
|
|
||||||
}
|
|
||||||
$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('<div class="text-danger">failed</div>');
|
|
||||||
}
|
|
||||||
$cnt = $row['zan'];
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<?= getClickZanBlock($type, $id, $cnt, $cur, $show_text) ?>
|
|
||||||
|
@ -2,40 +2,28 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($contest = queryContest($_GET['id']))) {
|
Auth::check() || redirectToLogin();
|
||||||
become404Page();
|
UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
UOJContest::cur()->userCanParticipateNow(Auth::user()) || UOJResponse::page403();
|
||||||
|
UOJContest::cur()->userHasMarkedParticipated(Auth::user()) && redirectTo(UOJContest::cur()->getUri());
|
||||||
|
|
||||||
genMoreContestInfo($contest);
|
$confirm_form = new UOJBs4Form('confirm');
|
||||||
|
$confirm_form->submit_button_config['class_str'] = 'btn btn-primary mt-3';
|
||||||
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 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->submit_button_config['text'] = '我已核对信息,确认参加比赛';
|
||||||
$confirm_form->handle = function() use ($myUser, $contest) {
|
$confirm_form->handle = function () {
|
||||||
DB::update("update contests_registrants set has_participated = 1 where username = '{$myUser['username']}' and contest_id = {$contest['id']}");
|
UOJContest::cur()->markUserAsParticipated(Auth::user());
|
||||||
};
|
};
|
||||||
$confirm_form->succ_href = "/contest/{$contest['id']}";
|
$confirm_form->succ_href = '/contest/' . UOJContest::info('id');
|
||||||
$confirm_form->runAtServer();
|
$confirm_form->runAtServer();
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader('确认参赛 - ' . HTML::stripTags($contest['name'])) ?>
|
<?php echoUOJPageHeader('确认参赛 - ' . UOJContest::info('name')) ?>
|
||||||
|
|
||||||
<div class="card mw-100 mx-auto" style="width:800px">
|
<div class="card mw-100 mx-auto" style="width:800px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h1 class="h2 card-title text-center mb-3">确认参赛</h1>
|
<h1 class="card-title text-center mb-3">确认参赛</h1>
|
||||||
|
|
||||||
<p class="card-text text-center">您即将参加比赛 “<b><?= $contest['name'] ?></b>”,请在正式参赛前仔细核对以下比赛信息:</p>
|
<p class="card-text text-center">您即将参加比赛 “<b><?= UOJContest::info('name') ?></b>”,请在正式参赛前仔细核对以下比赛信息:</p>
|
||||||
|
|
||||||
<div class="table-responsive mx-auto" style="width:500px">
|
<div class="table-responsive mx-auto" style="width:500px">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
@ -48,23 +36,23 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">比赛名称</td>
|
<td class="text-center">比赛名称</td>
|
||||||
<td><?= $contest['name'] ?></td>
|
<td><?= UOJContest::info('name') ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">参赛选手</td>
|
<td class="text-center">参赛选手</td>
|
||||||
<td><?= getUserLink($myUser['username']) ?></td>
|
<td><?= getUserLink(Auth::id()) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">开始时间</td>
|
<td class="text-center">开始时间</td>
|
||||||
<td><?= $contest['start_time_str'] ?></td>
|
<td><?= UOJContest::info('start_time_str') ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">结束时间</td>
|
<td class="text-center">结束时间</td>
|
||||||
<td><?= $contest['end_time_str'] ?></td>
|
<td><?= UOJContest::info('end_time_str') ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center">比赛赛制</td>
|
<td class="text-center">比赛赛制</td>
|
||||||
<td><?= $contest['extra_config']['contest_type'] ?: 'OI' ?></td>
|
<td><?= UOJContest::cur()->basicRule() ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -2,41 +2,15 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requireLib('mathjax');
|
requireLib('mathjax');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
requirePHPLib('judger');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($contest = queryContest($_GET['id']))) {
|
UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become404Page();
|
UOJContest::cur()->userCanView(Auth::user(), ['ensure' => true, 'check-register' => true]);
|
||||||
}
|
|
||||||
genMoreContestInfo($contest);
|
|
||||||
|
|
||||||
if (!hasContestPermission($myUser, $contest)) {
|
$contest = UOJContest::info();
|
||||||
if ($contest['cur_progress'] == CONTEST_NOT_STARTED) {
|
$is_manager = UOJContest::cur()->userCanManage(Auth::user());
|
||||||
redirectTo("/contest/{$contest['id']}/register");
|
|
||||||
} elseif ($contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
|
||||||
if (Auth::check()) {
|
|
||||||
if (!hasParticipated($myUser, $contest)) {
|
|
||||||
redirectTo("/contest/{$contest['id']}/confirm");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!hasRegistered($myUser, $contest) && !isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
|
||||||
if (hasRegistered($myUser, $contest)) {
|
|
||||||
if (!hasParticipated($myUser, $contest)) {
|
|
||||||
redirectTo("/contest/{$contest['id']}/confirm");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET['tab'])) {
|
if (isset($_GET['tab'])) {
|
||||||
$cur_tab = $_GET['tab'];
|
$cur_tab = $_GET['tab'];
|
||||||
@ -44,20 +18,20 @@
|
|||||||
$cur_tab = 'dashboard';
|
$cur_tab = 'dashboard';
|
||||||
}
|
}
|
||||||
|
|
||||||
$tabs_info = array(
|
$tabs_info = [
|
||||||
'dashboard' => array(
|
'dashboard' => [
|
||||||
'name' => UOJLocale::get('contests::contest dashboard'),
|
'name' => UOJLocale::get('contests::contest dashboard'),
|
||||||
'url' => "/contest/{$contest['id']}"
|
'url' => "/contest/{$contest['id']}"
|
||||||
),
|
],
|
||||||
'submissions' => array(
|
'submissions' => [
|
||||||
'name' => UOJLocale::get('contests::contest submissions'),
|
'name' => UOJLocale::get('contests::contest submissions'),
|
||||||
'url' => "/contest/{$contest['id']}/submissions"
|
'url' => "/contest/{$contest['id']}/submissions"
|
||||||
),
|
],
|
||||||
'standings' => array(
|
'standings' => [
|
||||||
'name' => UOJLocale::get('contests::contest standings'),
|
'name' => UOJLocale::get('contests::contest standings'),
|
||||||
'url' => "/contest/{$contest['id']}/standings"
|
'url' => "/contest/{$contest['id']}/standings"
|
||||||
),
|
],
|
||||||
);
|
];
|
||||||
|
|
||||||
if ($contest['cur_progress'] > CONTEST_TESTING) {
|
if ($contest['cur_progress'] > CONTEST_TESTING) {
|
||||||
$tabs_info['after_contest_standings'] = array(
|
$tabs_info['after_contest_standings'] = array(
|
||||||
@ -70,103 +44,30 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasContestPermission(Auth::user(), $contest)) {
|
if ($is_manager) {
|
||||||
$tabs_info['backstage'] = array(
|
$tabs_info['backstage'] = array(
|
||||||
'name' => UOJLocale::get('contests::contest backstage'),
|
'name' => UOJLocale::get('contests::contest backstage'),
|
||||||
'url' => "/contest/{$contest['id']}/backstage"
|
'url' => "/contest/{$contest['id']}/backstage"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($tabs_info[$cur_tab])) {
|
isset($tabs_info[$cur_tab]) || UOJResponse::page404();
|
||||||
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 (isSuperUser($myUser) || isContestJudger($myUser)) {
|
||||||
if (CONTEST_PENDING_FINAL_TEST <= $contest['cur_progress']) {
|
if (CONTEST_PENDING_FINAL_TEST <= $contest['cur_progress']) {
|
||||||
$start_test_form = new UOJForm('start_test');
|
$start_test_form = new UOJBs4Form('start_test');
|
||||||
$start_test_form->handle = function () {
|
$start_test_form->handle = function () {
|
||||||
global $contest;
|
UOJContest::finalTest();
|
||||||
$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['class_str'] = 'btn btn-danger d-block w-100';
|
||||||
$start_test_form->submit_button_config['smart_confirm'] = '';
|
$start_test_form->submit_button_config['smart_confirm'] = '';
|
||||||
if ($contest['cur_progress'] < CONTEST_TESTING) {
|
$start_test_form->submit_button_config['text'] = UOJContest::cur()->labelForFinalTest();
|
||||||
$start_test_form->submit_button_config['text'] = '开始最终测试';
|
|
||||||
} else {
|
|
||||||
$start_test_form->submit_button_config['text'] = '重新开始最终测试';
|
|
||||||
}
|
|
||||||
|
|
||||||
$start_test_form->runAtServer();
|
$start_test_form->runAtServer();
|
||||||
}
|
}
|
||||||
if ($contest['cur_progress'] >= CONTEST_TESTING) {
|
if ($contest['cur_progress'] >= CONTEST_TESTING) {
|
||||||
$publish_result_form = new UOJForm('publish_result');
|
$publish_result_form = new UOJBs4Form('publish_result');
|
||||||
$publish_result_form->handle = function () {
|
$publish_result_form->handle = function () {
|
||||||
// time config
|
UOJContest::announceOfficialResults();
|
||||||
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 = <<<EOD
|
|
||||||
<p>{$user_link} 您好:</p>
|
|
||||||
<p>您参与的比赛 <a href="/contest/{$contest['id']}">{$contest['name']}</a> 现已结束,您的成绩为 <a class="uoj-score" data-max="{$total_score}">{$standings[$i][0]}</a>{$tail}</p>
|
|
||||||
EOD;
|
|
||||||
sendSystemMsg($standings[$i][2][0], '比赛成绩公布', $content);
|
|
||||||
}
|
|
||||||
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['class_str'] = 'btn btn-danger d-block w-100';
|
||||||
$publish_result_form->submit_button_config['smart_confirm'] = '';
|
$publish_result_form->submit_button_config['smart_confirm'] = '';
|
||||||
@ -178,9 +79,12 @@ EOD;
|
|||||||
|
|
||||||
if ($cur_tab == 'dashboard') {
|
if ($cur_tab == 'dashboard') {
|
||||||
if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) {
|
if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) {
|
||||||
$post_question = new UOJForm('post_question');
|
$post_question = new UOJBs4Form('post_question');
|
||||||
$post_question->addVTextArea('qcontent', '问题', '',
|
$post_question->addVTextArea(
|
||||||
function($content) {
|
'qcontent',
|
||||||
|
'问题',
|
||||||
|
'',
|
||||||
|
function ($content, &$vdata) {
|
||||||
if (!Auth::check()) {
|
if (!Auth::check()) {
|
||||||
return '您尚未登录';
|
return '您尚未登录';
|
||||||
}
|
}
|
||||||
@ -190,15 +94,19 @@ EOD;
|
|||||||
if (strlen($content) > 140 * 4) {
|
if (strlen($content) > 140 * 4) {
|
||||||
return '问题太长';
|
return '问题太长';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['content'] = HTML::escape($content);
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$post_question->handle = function() {
|
$post_question->handle = function (&$vdata) use ($contest) {
|
||||||
global $contest;
|
DB::insert([
|
||||||
$content = DB::escape($_POST['qcontent']);
|
"insert into contests_asks",
|
||||||
$username = Auth::id();
|
"(contest_id, question, answer, username, post_time, is_hidden)",
|
||||||
DB::query("insert into contests_asks (contest_id, question, username, post_time, is_hidden) values ('{$contest['id']}', '$content', '$username', now(), 1)");
|
"values", DB::tuple([$contest['id'], $vdata['content'], '', Auth::id(), DB::now(), 1])
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$post_question->runAtServer();
|
$post_question->runAtServer();
|
||||||
} else {
|
} else {
|
||||||
@ -206,62 +114,87 @@ EOD;
|
|||||||
}
|
}
|
||||||
} elseif ($cur_tab == 'backstage') {
|
} elseif ($cur_tab == 'backstage') {
|
||||||
if (isSuperUser(Auth::user())) {
|
if (isSuperUser(Auth::user())) {
|
||||||
$post_notice = new UOJForm('post_notice');
|
$post_notice = new UOJBs4Form('post_notice');
|
||||||
$post_notice->addVInput('title', 'text', '标题', '',
|
$post_notice->addInput(
|
||||||
function($title) {
|
'title',
|
||||||
|
'text',
|
||||||
|
'标题',
|
||||||
|
'',
|
||||||
|
function ($title, &$vdata) {
|
||||||
if (!$title) {
|
if (!$title) {
|
||||||
return '标题不能为空';
|
return '标题不能为空';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['title'] = HTML::escape($title);
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$post_notice->addVTextArea('content', '正文', '',
|
$post_notice->addTextArea(
|
||||||
function($content) {
|
'content',
|
||||||
|
'正文',
|
||||||
|
'',
|
||||||
|
function ($content, &$vdata) {
|
||||||
if (!$content) {
|
if (!$content) {
|
||||||
return '公告不能为空';
|
return '公告不能为空';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['content'] = HTML::escape($content);
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$post_notice->handle = function() {
|
$post_notice->handle = function (&$vdata) use ($contest) {
|
||||||
global $contest;
|
DB::insert([
|
||||||
$title = DB::escape($_POST['title']);
|
"insert into contests_notice",
|
||||||
$content = DB::escape($_POST['content']);
|
"(contest_id, title, content, time)",
|
||||||
DB::insert("insert into contests_notice (contest_id, title, content, time) values ('{$contest['id']}', '$title', '$content', now())");
|
"values", DB::tuple([$contest['id'], $vdata['title'], $vdata['content'], DB::now()])
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$post_notice->runAtServer();
|
$post_notice->runAtServer();
|
||||||
} else {
|
} else {
|
||||||
$post_notice = null;
|
$post_notice = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasContestPermission(Auth::user(), $contest)) {
|
|
||||||
$reply_question = new UOJForm('reply_question');
|
|
||||||
$reply_question->addHidden('rid', '0',
|
|
||||||
function($id) {
|
|
||||||
global $contest;
|
|
||||||
|
|
||||||
|
if ($is_manager) {
|
||||||
|
$reply_question = new UOJBs4Form('reply_question');
|
||||||
|
$reply_question->addHidden(
|
||||||
|
'rid',
|
||||||
|
'0',
|
||||||
|
function ($id, &$vdata) use ($contest) {
|
||||||
if (!validateUInt($id)) {
|
if (!validateUInt($id)) {
|
||||||
return '无效ID';
|
return '无效ID';
|
||||||
}
|
}
|
||||||
$q = DB::selectFirst("select * from contests_asks where id = $id");
|
$q = DB::selectFirst([
|
||||||
if ($q['contest_id'] != $contest['id']) {
|
"select * from contests_asks",
|
||||||
|
"where", [
|
||||||
|
"id" => $id,
|
||||||
|
"contest_id" => $contest['id']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if (!$q) {
|
||||||
return '无效ID';
|
return '无效ID';
|
||||||
}
|
}
|
||||||
|
$vdata['id'] = $id;
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$reply_question->addVSelect('rtype', [
|
$reply_question->addVSelect('rtype', [
|
||||||
'public' => '公开',
|
'public' => '公开(如果该问题反复被不同人提出,或指出了题目中的错误,请选择该项)',
|
||||||
'private' => '非公开',
|
'private' => '非公开',
|
||||||
'statement' => '请仔细阅读题面(非公开)',
|
'statement' => '请仔细阅读题面(非公开)',
|
||||||
'no_comment' => '无可奉告(非公开)',
|
'no_comment' => '无可奉告(非公开)',
|
||||||
'no_play' => '请认真比赛(非公开)',
|
'no_play' => '请认真比赛(非公开)',
|
||||||
], '回复类型', 'private');
|
], '回复类型', 'private');
|
||||||
$reply_question->addVTextArea('rcontent', '回复', '',
|
$reply_question->addVTextArea(
|
||||||
function($content) {
|
'rcontent',
|
||||||
|
'回复',
|
||||||
|
'',
|
||||||
|
function ($content, &$vdata) {
|
||||||
if (!Auth::check()) {
|
if (!Auth::check()) {
|
||||||
return '您尚未登录';
|
return '您尚未登录';
|
||||||
}
|
}
|
||||||
@ -273,13 +206,13 @@ EOD;
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
$vdata['content'] = HTML::escape($content);
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$reply_question->handle = function() {
|
$reply_question->handle = function (&$vdata) use ($contest) {
|
||||||
global $contest;
|
$content = $vdata['content'];
|
||||||
$content = DB::escape($_POST['rcontent']);
|
|
||||||
$is_hidden = 1;
|
$is_hidden = 1;
|
||||||
switch ($_POST['rtype']) {
|
switch ($_POST['rtype']) {
|
||||||
case 'statement':
|
case 'statement':
|
||||||
@ -297,25 +230,48 @@ EOD;
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DB::update("update contests_asks set answer = '$content', reply_time = now(), is_hidden = {$is_hidden} where id = {$_POST['rid']}");
|
DB::update([
|
||||||
|
"update contests_asks",
|
||||||
|
"set", [
|
||||||
|
"answer" => $content,
|
||||||
|
"reply_time" => DB::now(),
|
||||||
|
"is_hidden" => $is_hidden
|
||||||
|
], "where", ["id" => $vdata['id']]
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$reply_question->runAtServer();
|
$reply_question->runAtServer();
|
||||||
} else {
|
} else {
|
||||||
$reply_question = null;
|
$reply_question = null;
|
||||||
}
|
}
|
||||||
} elseif ($cur_tab == 'self_reviews') {
|
} elseif ($cur_tab == 'self_reviews') {
|
||||||
if (hasParticipated(Auth::user(), $contest)) {
|
if (UOJContest::cur()->userHasMarkedParticipated(Auth::user())) {
|
||||||
$self_reviews_update_form = new UOJForm('self_review_update');
|
$self_reviews_update_form = new UOJBs4Form('self_review_update');
|
||||||
$self_reviews_update_form->ctrl_enter_submit = true;
|
$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");
|
$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++) {
|
for ($i = 0; $i < count($contest_problems); $i++) {
|
||||||
$contest_problems[$i]['problem'] = queryProblemBrief($contest_problems[$i]['problem_id']);
|
$contest_problems[$i]['problem'] = UOJContestProblem::query($contest_problems[$i]['problem_id']);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($i = 0; $i < count($contest_problems); $i++) {
|
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'];
|
$content = DB::selectFirst([
|
||||||
$self_reviews_update_form->addVTextArea('self_review_update__problem_' . chr(ord('A') + $i), '<b>' . chr(ord('A') + $i) . '</b>: ' . $contest_problems[$i]['problem']['title'], $content,
|
"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(),
|
||||||
|
'<b>' . $contest_problems[$i]['problem']->getLetter() . '</b>: ' . $contest_problems[$i]['problem']->info['title'],
|
||||||
|
$content['content'],
|
||||||
function ($content) {
|
function ($content) {
|
||||||
if (strlen($content) > 200) {
|
if (strlen($content) > 200) {
|
||||||
return '总结不能超过200字';
|
return '总结不能超过200字';
|
||||||
@ -328,8 +284,19 @@ EOD;
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = DB::selectFirst("select content from contests_reviews where contest_id = {$contest['id']} and problem_id = -1 and poster = '{$myUser['username']}'")['content'];
|
$content = DB::selectFirst([
|
||||||
$self_reviews_update_form->addVTextArea('self_review_update__overall', '比赛总结', $content,
|
"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) {
|
function ($content) {
|
||||||
if (strlen($content) > 200) {
|
if (strlen($content) > 200) {
|
||||||
return '总结不能超过200字';
|
return '总结不能超过200字';
|
||||||
@ -341,21 +308,29 @@ EOD;
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
$self_reviews_update_form->handle = function() {
|
$self_reviews_update_form->handle = function () use ($contest, $contest_problems) {
|
||||||
global $contest, $contest_problems, $myUser;
|
global $contest, $contest_problems, $myUser;
|
||||||
|
|
||||||
for ($i = 0; $i < count($contest_problems); $i++) {
|
for ($i = 0; $i < count($contest_problems); $i++) {
|
||||||
if (isset($_POST['self_review_update__problem_' . chr(ord('A') + $i)])) {
|
if (isset($_POST['self_review_update__problem_' . $contest_problems[$i]['problem']->getLetter()])) {
|
||||||
$esc_content = DB::escape($_POST['self_review_update__problem_' . chr(ord('A') + $i)]);
|
$esc_content = DB::escape($_POST['self_review_update__problem_' . $contest_problems[$i]['problem']->getLetter()]);
|
||||||
$problem_id = $contest_problems[$i]['problem_id'];
|
$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')");
|
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'])) {
|
if (isset($_POST['self_review_update__overall'])) {
|
||||||
$esc_content = DB::escape($_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')");
|
DB::query([
|
||||||
|
"replace into contests_reviews",
|
||||||
|
"(contest_id, problem_id, poster, content)",
|
||||||
|
"values", DB::tuple([$contest['id'], -1, Auth::id(), $esc_content]),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -364,19 +339,37 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
function echoDashboard() {
|
function echoDashboard() {
|
||||||
global $contest, $post_notice, $post_question, $reply_question;
|
global $contest, $post_question;
|
||||||
|
|
||||||
$myname = Auth::id();
|
$contest_problems = DB::selectAll([
|
||||||
$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");
|
"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++) {
|
for ($i = 0; $i < count($contest_problems); $i++) {
|
||||||
$contest_problems[$i]['problem'] = queryProblemBrief($contest_problems[$i]['problem_id']);
|
$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");
|
$contest_notice = DB::selectAll([
|
||||||
|
"select * from contests_notice",
|
||||||
|
"where", ["contest_id" => $contest['id']],
|
||||||
|
"order by time desc"
|
||||||
|
]);
|
||||||
|
|
||||||
if (Auth::check()) {
|
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 = DB::selectAll([
|
||||||
|
"select * from contests_asks",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
"username" => Auth::id()
|
||||||
|
], "order by post_time desc"
|
||||||
|
]);
|
||||||
$my_questions_pag = new Paginator([
|
$my_questions_pag = new Paginator([
|
||||||
'data' => $my_questions
|
'data' => $my_questions
|
||||||
]);
|
]);
|
||||||
@ -385,9 +378,13 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
$others_questions_pag = new Paginator([
|
$others_questions_pag = new Paginator([
|
||||||
'col_names' => array('*'),
|
'col_names' => ['*'],
|
||||||
'table_name' => 'contests_asks',
|
'table_name' => 'contests_asks',
|
||||||
'cond' => "contest_id = {$contest['id']} and username != '{$myname}' and is_hidden = 0",
|
'cond' => [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
["username", "!=", Auth::id()],
|
||||||
|
"is_hidden" => 0
|
||||||
|
],
|
||||||
'tail' => 'order by reply_time desc',
|
'tail' => 'order by reply_time desc',
|
||||||
'page_len' => 10
|
'page_len' => 10
|
||||||
]);
|
]);
|
||||||
@ -398,7 +395,7 @@ EOD;
|
|||||||
'contest_problems' => $contest_problems,
|
'contest_problems' => $contest_problems,
|
||||||
'post_question' => $post_question,
|
'post_question' => $post_question,
|
||||||
'my_questions_pag' => $my_questions_pag,
|
'my_questions_pag' => $my_questions_pag,
|
||||||
'others_questions_pag' => $others_questions_pag,
|
'others_questions_pag' => $others_questions_pag
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,14 +403,14 @@ EOD;
|
|||||||
global $contest, $post_notice, $reply_question;
|
global $contest, $post_notice, $reply_question;
|
||||||
|
|
||||||
$questions_pag = new Paginator([
|
$questions_pag = new Paginator([
|
||||||
'col_names' => array('*'),
|
'col_names' => ['*'],
|
||||||
'table_name' => 'contests_asks',
|
'table_name' => 'contests_asks',
|
||||||
'cond' => "contest_id = {$contest['id']}",
|
'cond' => ["contest_id" => $contest['id']],
|
||||||
'tail' => 'order by post_time desc',
|
'tail' => 'order by post_time desc',
|
||||||
'page_len' => 50
|
'page_len' => 50
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($contest['cur_progress'] < CONTEST_TESTING) {
|
if (UOJContest::cur()->managerCanSeeFinalStandingsTab(Auth::user())) {
|
||||||
$contest_data = queryContestData($contest, ['pre_final' => true]);
|
$contest_data = queryContestData($contest, ['pre_final' => true]);
|
||||||
calcStandings($contest, $contest_data, $score, $standings);
|
calcStandings($contest, $contest_data, $score, $standings);
|
||||||
|
|
||||||
@ -437,73 +434,53 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
function echoMySubmissions() {
|
function echoMySubmissions() {
|
||||||
global $contest, $myUser;
|
$problems = UOJContest::cur()->getProblemIDs();
|
||||||
|
|
||||||
$show_all_submissions_status = Cookie::get('show_all_submissions') !== null ? 'checked="checked" ' : '';
|
$options = [];
|
||||||
$show_all_submissions = UOJLocale::get('contests::show all submissions');
|
$options[] = ['value' => 'all', 'text' => '所有题目'];
|
||||||
echo <<<EOD
|
for ($i = 0; $i < count($problems); $i++) {
|
||||||
<div class="text-end">
|
$letter = chr(ord('A') + $i);
|
||||||
<div class="form-check d-inline-block">
|
$options[] = ['value' => $letter, 'text' => "{$letter} 题"];
|
||||||
<input type="checkbox" class="form-check-input" id="input-show_all_submissions" $show_all_submissions_status />
|
|
||||||
<label class="form-check-label" for="input-show_all_submissions">
|
|
||||||
$show_all_submissions
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#input-show_all_submissions').click(function() {
|
|
||||||
if (this.checked) {
|
|
||||||
$.cookie('show_all_submissions', '');
|
|
||||||
} else {
|
|
||||||
$.removeCookie('show_all_submissions');
|
|
||||||
}
|
}
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
EOD;
|
|
||||||
|
|
||||||
$config = array(
|
$chosen = UOJRequest::get('p');
|
||||||
'judge_time_hidden' => '',
|
$problem_id = null;
|
||||||
'table_config' => array(
|
if (strlen($chosen) == 1) {
|
||||||
'div_classes' => array('card', 'mb-3', 'table-responsive'),
|
$num = ord($chosen) - ord('A');
|
||||||
'table_classes' => array('table', 'mb-0', 'uoj-table', 'text-center')
|
if (0 <= $num && $num < count($problems)) {
|
||||||
),
|
$problem_id = $problems[$num];
|
||||||
);
|
|
||||||
|
|
||||||
if (Cookie::get('show_all_submissions') !== null) {
|
|
||||||
echoSubmissionsList("contest_id = {$contest['id']}", 'order by id desc', $config, $myUser);
|
|
||||||
} else {
|
} else {
|
||||||
echoSubmissionsList("submitter = '{$myUser['username']}' and contest_id = {$contest['id']}", 'order by id desc', $config, $myUser);
|
$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) {
|
function echoStandings($is_after_contest_query = false) {
|
||||||
global $contest;
|
global $contest;
|
||||||
|
uojIncludeView('contest-standings', ['contest' => $contest] + UOJContest::cur()->queryResult(['after_contest' => $is_after_contest_query]));
|
||||||
$contest_data = queryContestData($contest, array(), $is_after_contest_query);
|
|
||||||
calcStandings($contest, $contest_data, $score, $standings);
|
|
||||||
|
|
||||||
uojIncludeView('contest-standings', [
|
|
||||||
'contest' => $contest,
|
|
||||||
'standings' => $standings,
|
|
||||||
'score' => $score,
|
|
||||||
'contest_data' => $contest_data
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function echoReviews() {
|
function echoSelfReviews() {
|
||||||
global $contest;
|
global $contest;
|
||||||
|
|
||||||
$contest_data = queryContestData($contest, array());
|
uojIncludeView('contest-reviews', ['contest' => $contest] + UOJContest::cur()->queryResult());
|
||||||
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
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$page_header = HTML::stripTags($contest['name']) . ' - ';
|
$page_header = HTML::stripTags($contest['name']) . ' - ';
|
||||||
@ -511,7 +488,7 @@ EOD;
|
|||||||
<?php echoUOJPageHeader(HTML::stripTags($contest['name']) . ' - ' . $tabs_info[$cur_tab]['name'] . ' - ' . UOJLocale::get('contests::contest')) ?>
|
<?php echoUOJPageHeader(HTML::stripTags($contest['name']) . ' - ' . $tabs_info[$cur_tab]['name'] . ' - ' . UOJLocale::get('contests::contest')) ?>
|
||||||
|
|
||||||
<div class="text-center d-md-none mb-3">
|
<div class="text-center d-md-none mb-3">
|
||||||
<h1 class="h2"><?= $contest['name'] ?></h1>
|
<h1><?= $contest['name'] ?></h1>
|
||||||
<div class="small text-muted">
|
<div class="small text-muted">
|
||||||
<?php if ($contest['cur_progress'] <= CONTEST_NOT_STARTED) : ?>
|
<?php if ($contest['cur_progress'] <= CONTEST_NOT_STARTED) : ?>
|
||||||
<?= UOJLocale::get('contests::not started') ?>
|
<?= UOJLocale::get('contests::not started') ?>
|
||||||
@ -537,7 +514,7 @@ EOD;
|
|||||||
<?= HTML::tablist($tabs_info, $cur_tab, 'nav-pills') ?>
|
<?= HTML::tablist($tabs_info, $cur_tab, 'nav-pills') ?>
|
||||||
<?php if ($cur_tab == 'standings' || $cur_tab == 'after_contest_standings' || $cur_tab == 'self_reviews') : ?>
|
<?php if ($cur_tab == 'standings' || $cur_tab == 'after_contest_standings' || $cur_tab == 'self_reviews') : ?>
|
||||||
<div class="d-none d-md-block text-center">
|
<div class="d-none d-md-block text-center">
|
||||||
<h1 class="h2 mt-2 mb-3"><?= $contest['name'] ?></h1>
|
<h1 class="mt-2 mb-3"><?= $contest['name'] ?></h1>
|
||||||
<div class="small text-muted">
|
<div class="small text-muted">
|
||||||
<?php if ($contest['cur_progress'] <= CONTEST_NOT_STARTED) : ?>
|
<?php if ($contest['cur_progress'] <= CONTEST_NOT_STARTED) : ?>
|
||||||
<?= UOJLocale::get('contests::not started') ?>
|
<?= UOJLocale::get('contests::not started') ?>
|
||||||
@ -566,7 +543,7 @@ EOD;
|
|||||||
} elseif ($cur_tab == 'backstage') {
|
} elseif ($cur_tab == 'backstage') {
|
||||||
echoBackstage();
|
echoBackstage();
|
||||||
} elseif ($cur_tab == 'self_reviews') {
|
} elseif ($cur_tab == 'self_reviews') {
|
||||||
echoReviews();
|
echoSelfReviews();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
@ -590,7 +567,7 @@ EOD;
|
|||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h3 class="h5 card-title text-center">
|
<h3 class="h4 card-title text-center">
|
||||||
<a class="text-decoration-none text-body" href="/contest/<?= $contest['id'] ?>">
|
<a class="text-decoration-none text-body" href="/contest/<?= $contest['id'] ?>">
|
||||||
<?= $contest['name'] ?>
|
<?= $contest['name'] ?>
|
||||||
</a>
|
</a>
|
||||||
@ -600,7 +577,6 @@ EOD;
|
|||||||
<span id="contest-countdown"></span>
|
<span id="contest-countdown"></span>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function() {}, '1.75rem', false);
|
$('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function() {}, '1.75rem', false);
|
||||||
checkContestNotice(<?= $contest['id'] ?>, '<?= UOJTime::$time_now_str ?>');
|
|
||||||
</script>
|
</script>
|
||||||
<?php elseif ($contest['cur_progress'] <= CONTEST_TESTING) : ?>
|
<?php elseif ($contest['cur_progress'] <= CONTEST_TESTING) : ?>
|
||||||
<?php if ($contest['cur_progress'] < CONTEST_TESTING) : ?>
|
<?php if ($contest['cur_progress'] < CONTEST_TESTING) : ?>
|
||||||
@ -611,7 +587,7 @@ EOD;
|
|||||||
$n_judged = DB::selectCount("select count(*) from submissions where contest_id = {$contest['id']} and status = 'Judged'");
|
$n_judged = DB::selectCount("select count(*) from submissions where contest_id = {$contest['id']} and status = 'Judged'");
|
||||||
$rop = $total == 0 ? 100 : (int)($n_judged / $total * 100);
|
$rop = $total == 0 ? 100 : (int)($n_judged / $total * 100);
|
||||||
?>
|
?>
|
||||||
<?= UOJLocale::get('contests::contest final testing') ?>
|
<?= UOJLocale::get('contests::final testing') ?>
|
||||||
(<?= $rop ?>%)
|
(<?= $rop ?>%)
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
@ -620,16 +596,19 @@ EOD;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
比赛评价:<?= getClickZanBlock('C', $contest['id'], $contest['zan']) ?>
|
比赛评价:<?= ClickZans::getBlock('C', $contest['id'], $contest['zan']) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if (!isset($contest['extra_config']['contest_type']) || $contest['extra_config']['contest_type'] == 'OI'): ?>
|
<?php if (UOJContest::cur()->basicRule() === 'OI') : ?>
|
||||||
<p>此次比赛为 OI 赛制。</p>
|
<p>此次比赛为 OI 赛制。</p>
|
||||||
<p><strong>注意:比赛时只显示测样例的结果。</strong></p>
|
<p><strong>注意:比赛时只显示测样例的结果。</strong></p>
|
||||||
<?php elseif ($contest['extra_config']['contest_type'] == 'IOI'): ?>
|
<?php elseif (UOJContest::cur()->basicRule() === 'ACM') : ?>
|
||||||
|
<p>此次比赛为 ACM 赛制。</p>
|
||||||
|
<p><strong>封榜时间:<?= $contest['frozen_time']->format('Y-m-d H:i:s') ?></strong></p>
|
||||||
|
<?php elseif (UOJContest::cur()->basicRule() === 'IOI') : ?>
|
||||||
<p>此次比赛为 IOI 赛制。</p>
|
<p>此次比赛为 IOI 赛制。</p>
|
||||||
<p><strong>注意:比赛时显示测试所有数据的结果,但无法看到详细信息。</strong></p>
|
<p>比赛时显示的得分即最终得分。</p>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<a href="/contest/<?= $contest['id'] ?>/registrants" class="btn btn-secondary d-block mt-2">
|
<a href="/contest/<?= $contest['id'] ?>/registrants" class="btn btn-secondary d-block mt-2">
|
||||||
@ -653,7 +632,7 @@ EOD;
|
|||||||
<?php if ($contest['extra_config']['links']) : ?>
|
<?php if ($contest['extra_config']['links']) : ?>
|
||||||
<div class="card card-default border-info mt-3">
|
<div class="card card-default border-info mt-3">
|
||||||
<div class="card-header bg-info">
|
<div class="card-header bg-info">
|
||||||
<h3 class="h4 card-title">比赛资料</h3>
|
<h3 class="card-title">比赛资料</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<?php foreach ($contest['extra_config']['links'] as $link) : ?>
|
<?php foreach ($contest['extra_config']['links'] as $link) : ?>
|
||||||
|
@ -1,19 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check()) {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($contest = queryContest($_GET['id']))) {
|
Auth::check() || redirectToLogin();
|
||||||
become404Page();
|
UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
isSuperUser(Auth::user()) || UOJResponse::page403();
|
||||||
genMoreContestInfo($contest);
|
$contest = UOJContest::info();
|
||||||
|
|
||||||
if (!hasContestPermission($myUser, $contest)) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET['tab'])) {
|
if (isset($_GET['tab'])) {
|
||||||
$cur_tab = $_GET['tab'];
|
$cur_tab = $_GET['tab'];
|
||||||
@ -45,9 +37,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($cur_tab == 'profile') {
|
if ($cur_tab == 'profile') {
|
||||||
$profile_form = new UOJForm('time');
|
$profile_form = new UOJBs4Form('time');
|
||||||
$profile_form->addVInput(
|
$profile_form->addVInput(
|
||||||
'name', 'text', '比赛标题', $contest['name'],
|
'name',
|
||||||
|
'text',
|
||||||
|
'比赛标题',
|
||||||
|
$contest['name'],
|
||||||
function ($name, &$vdata) {
|
function ($name, &$vdata) {
|
||||||
if ($name == '') {
|
if ($name == '') {
|
||||||
return '标题不能为空';
|
return '标题不能为空';
|
||||||
@ -70,7 +65,10 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$profile_form->addVInput(
|
$profile_form->addVInput(
|
||||||
'start_time', 'text', '开始时间', $contest['start_time_str'],
|
'start_time',
|
||||||
|
'text',
|
||||||
|
'开始时间',
|
||||||
|
$contest['start_time_str'],
|
||||||
function ($str, &$vdata) {
|
function ($str, &$vdata) {
|
||||||
try {
|
try {
|
||||||
$vdata['start_time'] = new DateTime($str);
|
$vdata['start_time'] = new DateTime($str);
|
||||||
@ -82,7 +80,10 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$profile_form->addVInput(
|
$profile_form->addVInput(
|
||||||
'last_min', 'text', '时长(单位:分钟)', $contest['last_min'],
|
'last_min',
|
||||||
|
'text',
|
||||||
|
'时长(单位:分钟)',
|
||||||
|
$contest['last_min'],
|
||||||
function ($str, &$vdata) {
|
function ($str, &$vdata) {
|
||||||
if (!validateUInt($str)) {
|
if (!validateUInt($str)) {
|
||||||
return '必须为一个整数';
|
return '必须为一个整数';
|
||||||
@ -95,11 +96,14 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$profile_form->handle = function (&$vdata) use ($contest) {
|
$profile_form->handle = function (&$vdata) use ($contest) {
|
||||||
$start_time_str = $vdata['start_time']->format('Y-m-d H:i:s');
|
DB::update([
|
||||||
$esc_name = DB::escape($vdata['name']);
|
"update contests",
|
||||||
$esc_last_min = DB::escape($vdata['last_min']);
|
"set", [
|
||||||
|
"name" => $vdata['name'],
|
||||||
DB::update("update contests set start_time = '$start_time_str', last_min = {$_POST['last_min']}, name = '$esc_name' where id = {$contest['id']}");
|
"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' => '修改成功']);
|
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
||||||
};
|
};
|
||||||
@ -126,42 +130,56 @@ EOD);
|
|||||||
} elseif ($cur_tab == 'problems') {
|
} elseif ($cur_tab == 'problems') {
|
||||||
if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') {
|
if (isset($_POST['submit-remove_problem']) && $_POST['submit-remove_problem'] == 'remove_problem') {
|
||||||
$problem_id = $_POST['problem_id'];
|
$problem_id = $_POST['problem_id'];
|
||||||
|
$problem = UOJProblem::query($problem_id);
|
||||||
|
|
||||||
if (!validateUInt($problem_id)) {
|
if (!$problem) {
|
||||||
dieWithAlert('无效的题目 ID。');
|
dieWithAlert('题目不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!queryProblemBrief($problem_id)) {
|
if (!UOJContest::cur()->hasProblem($problem)) {
|
||||||
dieWithAlert('题目不存在。');
|
dieWithAlert('题目不在本场比赛中');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DB::selectFirst("SELECT * FROM contests_problems WHERE contest_id = {$contest['id']} AND problem_id = $problem_id")) {
|
DB::delete([
|
||||||
dieWithAlert('题目不在比赛中。');
|
"delete from contests_problems",
|
||||||
}
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
DB::delete("DELETE FROM contests_problems WHERE contest_id = {$contest['id']} AND problem_id = $problem_id");
|
"problem_id" => $problem_id,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
unset($contest['extra_config']["problem_$problem_id"]);
|
unset($contest['extra_config']["problem_$problem_id"]);
|
||||||
$esc_extra_config = DB::escape(json_encode($contest['extra_config']));
|
unset($contest['extra_config']['bonus']["problem_$problem_id"]);
|
||||||
DB::update("UPDATE `contests` SET extra_config = '$esc_extra_config' WHERE id = {$contest['id']}");
|
unset($contest['extra_config']['submit_time_limit']["problem_$problem_id"]);
|
||||||
|
|
||||||
|
$esc_extra_config = json_encode($contest['extra_config']);
|
||||||
|
DB::update([
|
||||||
|
"update contests",
|
||||||
|
"set", ["extra_config" => $esc_extra_config],
|
||||||
|
"where", ["id" => $contest['id']]
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithAlert('移除成功!');
|
dieWithAlert('移除成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$add_problem_form = new UOJForm('add_problem');
|
$add_problem_form = new UOJBs4Form('add_problem');
|
||||||
$add_problem_form->addVInput('problem_id', 'text', '题目 ID', '',
|
$add_problem_form->addVInput(
|
||||||
|
'problem_id',
|
||||||
|
'text',
|
||||||
|
'题目 ID',
|
||||||
|
'',
|
||||||
function ($problem_id, &$vdata) {
|
function ($problem_id, &$vdata) {
|
||||||
if (!validateUInt($problem_id)) {
|
$problem = UOJProblem::query($problem_id);
|
||||||
return '无效的题目 ID。';
|
|
||||||
}
|
|
||||||
|
|
||||||
$problem = queryProblemBrief($problem_id);
|
|
||||||
if (!$problem) {
|
if (!$problem) {
|
||||||
return '题目不存在。';
|
return '题目不存在。';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasProblemPermission(Auth::user(), $problem)) {
|
if (!$problem->userCanManage(Auth::user())) {
|
||||||
return "无权添加题目 #$problem_id。";
|
return "无权添加此题目。";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UOJContest::cur()->hasProblem($problem)) {
|
||||||
|
return "题目已经在本场比赛中。";
|
||||||
}
|
}
|
||||||
|
|
||||||
$vdata['problem_id'] = $problem_id;
|
$vdata['problem_id'] = $problem_id;
|
||||||
@ -171,24 +189,44 @@ EOD);
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_problem_form->addVSelect('judge_config', [
|
$add_problem_form->addVSelect('judge_config', [
|
||||||
|
'default' => '默认',
|
||||||
'sample' => '只测样例',
|
'sample' => '只测样例',
|
||||||
'no-details' => '测试全部数据,但不显示测试点详情',
|
'no-details' => '测试全部数据,对于每个测试点显示得分但不显示详情',
|
||||||
'full' => '测试全部数据',
|
'full' => '测试全部数据',
|
||||||
], '评测设置', 'sample');
|
], '评测设置', 'default');
|
||||||
|
$add_problem_form->addVCheckboxes('bonus', ['0' => '否', '1' => '是'], '是否为 bonus 题(ACM 赛制)', '0');
|
||||||
$add_problem_form->handle = function (&$vdata) use ($contest) {
|
$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;
|
$level = DB::selectFirst([
|
||||||
DB::insert("INSERT INTO `contests_problems` (contest_id, problem_id, dfn) VALUES ({$contest['id']}, '{$vdata['problem_id']}', $dfn)");
|
"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])
|
||||||
|
]);
|
||||||
|
|
||||||
if ($_POST['judge_config'] != 'sample') {
|
$judge_type = $_POST['judge_config'];
|
||||||
$contest['extra_config']["problem_$problem_id"] = $_POST['judge_config'];
|
if ($judge_type === 'default') {
|
||||||
$esc_extra_config = DB::escape(json_encode($contest['extra_config']));
|
unset($contest['extra_config']["problem_{$vdata['problem_id']}"]);
|
||||||
DB::update("UPDATE `contests` SET extra_config = '$esc_extra_config' WHERE id = {$contest['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']} 添加成功!"]);
|
dieWithJsonData(['status' => 'success', 'message' => "题目 #{$vdata['problem_id']} 添加成功!"]);
|
||||||
};
|
};
|
||||||
$add_problem_form->submit_button_config['text'] = '添加';
|
$add_problem_form->submit_button_config['text'] = '添加';
|
||||||
$add_problem_form->submit_button_config['margin_class'] = 'mt-3';
|
$add_problem_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
$add_problem_form->setAjaxSubmit(<<<EOD
|
$add_problem_form->setAjaxSubmit(<<<EOD
|
||||||
function(res) {
|
function(res) {
|
||||||
if (res.status === 'success') {
|
if (res.status === 'success') {
|
||||||
@ -212,35 +250,41 @@ EOD);
|
|||||||
} elseif ($cur_tab == 'managers') {
|
} elseif ($cur_tab == 'managers') {
|
||||||
if (isset($_POST['submit-remove_manager']) && $_POST['submit-remove_manager'] == 'remove_manager') {
|
if (isset($_POST['submit-remove_manager']) && $_POST['submit-remove_manager'] == 'remove_manager') {
|
||||||
$username = $_POST['username'];
|
$username = $_POST['username'];
|
||||||
|
$user = UOJUser::query($username);
|
||||||
|
|
||||||
if (!validateUsername($username)) {
|
if (!$user) {
|
||||||
dieWithAlert('用户名不合法。');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!queryUser($username)) {
|
|
||||||
dieWithAlert('用户不存在。');
|
dieWithAlert('用户不存在。');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DB::selectFirst("SELECT * FROM contests_permissions WHERE contest_id = {$contest['id']} AND username = '$username'")) {
|
if (!UOJContest::cur()->userCanManage($user)) {
|
||||||
dieWithAlert('用户不是这场比赛的管理员。');
|
dieWithAlert('用户不是这场比赛的管理员。');
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::delete("DELETE FROM `contests_permissions` WHERE contest_id = ${contest['id']} AND username = '$username'");
|
|
||||||
|
DB::delete([
|
||||||
|
"delete from contests_permissions",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
"username" => $user['username'],
|
||||||
|
]
|
||||||
|
]);
|
||||||
dieWithAlert('移除成功!');
|
dieWithAlert('移除成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$add_manager_form = new UOJForm('add_manager');
|
$add_manager_form = new UOJBs4Form('add_manager');
|
||||||
$add_manager_form->addVInput('username', 'text', '用户名', '',
|
$add_manager_form->addVInput(
|
||||||
function($username, &$vdata) {
|
'username',
|
||||||
if (!validateUsername($username)) {
|
'text',
|
||||||
return '用户名不合法';
|
'用户名',
|
||||||
}
|
'',
|
||||||
|
function ($username, &$vdata) use ($contest) {
|
||||||
|
$user = UOJUser::query($username);
|
||||||
|
|
||||||
if (!queryUser($username)) {
|
if (!$user) {
|
||||||
return '用户不存在';
|
return '用户不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DB::selectFirst("SELECT * FROM contests_permissions WHERE contest_id = {$contest['id']} AND username = '$username'")) {
|
if (UOJContest::cur()->userCanManage($user)) {
|
||||||
return '用户已经是这场比赛的管理员';
|
return '用户已经是这场比赛的管理员';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,12 +295,16 @@ EOD);
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_manager_form->handle = function (&$vdata) use ($contest) {
|
$add_manager_form->handle = function (&$vdata) use ($contest) {
|
||||||
DB::query("INSERT INTO `contests_permissions` (contest_id, username) VALUES (${contest['id']}, '{$vdata['username']}')");
|
DB::insert([
|
||||||
|
"insert into contests_permissions",
|
||||||
|
"(contest_id, username)",
|
||||||
|
"values", DB::tuple([$contest['id'], $vdata['username']])
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户设置为本场比赛的管理者。']);
|
dieWithJsonData(['status' => 'success', 'message' => '已将用户名为 ' . $vdata['username'] . ' 的用户设置为本场比赛的管理者。']);
|
||||||
};
|
};
|
||||||
$add_manager_form->submit_button_config['text'] = '添加';
|
$add_manager_form->submit_button_config['text'] = '添加';
|
||||||
$add_manager_form->submit_button_config['margin_class'] = 'mt-3';
|
$add_manager_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
$add_manager_form->setAjaxSubmit(<<<EOD
|
$add_manager_form->setAjaxSubmit(<<<EOD
|
||||||
function(res) {
|
function(res) {
|
||||||
if (res.status === 'success') {
|
if (res.status === 'success') {
|
||||||
@ -278,7 +326,7 @@ function(res) {
|
|||||||
EOD);
|
EOD);
|
||||||
$add_manager_form->runAtServer();
|
$add_manager_form->runAtServer();
|
||||||
} elseif ($cur_tab == 'others') {
|
} elseif ($cur_tab == 'others') {
|
||||||
$version_form = new UOJForm('version');
|
$version_form = new UOJBs4Form('version');
|
||||||
$version_form->addVSelect('standings_version', [
|
$version_form->addVSelect('standings_version', [
|
||||||
'1' => '1',
|
'1' => '1',
|
||||||
'2' => '2',
|
'2' => '2',
|
||||||
@ -286,8 +334,11 @@ EOD);
|
|||||||
$version_form->handle = function () use ($contest) {
|
$version_form->handle = function () use ($contest) {
|
||||||
$contest['extra_config']['standings_version'] = $_POST['standings_version'];
|
$contest['extra_config']['standings_version'] = $_POST['standings_version'];
|
||||||
$esc_extra_config = json_encode($contest['extra_config']);
|
$esc_extra_config = json_encode($contest['extra_config']);
|
||||||
$esc_extra_config = DB::escape($esc_extra_config);
|
DB::update([
|
||||||
DB::update("UPDATE contests SET extra_config = '$esc_extra_config' WHERE id = {$contest['id']}");
|
"update contests",
|
||||||
|
"set", ["extra_config" => $esc_extra_config],
|
||||||
|
"where", ["id" => $contest['id']],
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
||||||
};
|
};
|
||||||
@ -312,20 +363,46 @@ function(res) {
|
|||||||
EOD);
|
EOD);
|
||||||
$version_form->runAtServer();
|
$version_form->runAtServer();
|
||||||
|
|
||||||
$contest_type_form = new UOJForm('contest_type');
|
$rule_form = new UOJBs4Form('basic_rule');
|
||||||
$contest_type_form->addVSelect('contest_type', [
|
$rule_form->addVSelect('basic_rule', [
|
||||||
'OI' => 'OI',
|
'OI' => 'OI',
|
||||||
'IOI' => 'IOI'
|
'IOI' => 'IOI',
|
||||||
], '比赛类型', $contest['extra_config']['contest_type']);
|
'ACM' => 'ACM',
|
||||||
$contest_type_form->handle = function() use ($contest) {
|
], '比赛类型', $contest['extra_config']['basic_rule']);
|
||||||
$contest['extra_config']['contest_type'] = $_POST['contest_type'];
|
$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'];
|
||||||
|
|
||||||
$esc_extra_config = json_encode($contest['extra_config']);
|
$esc_extra_config = json_encode($contest['extra_config']);
|
||||||
$esc_extra_config = DB::escape($esc_extra_config);
|
DB::update([
|
||||||
DB::update("UPDATE contests set extra_config = '$esc_extra_config' where id = {$contest['id']}");
|
"update contests",
|
||||||
|
"set", ["extra_config" => $esc_extra_config],
|
||||||
|
"where", ["id" => $contest['id']]
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
dieWithJsonData(['status' => 'success', 'message' => '修改成功']);
|
||||||
};
|
};
|
||||||
$contest_type_form->setAjaxSubmit(<<<EOD
|
$rule_form->setAjaxSubmit(<<<EOD
|
||||||
function(res) {
|
function(res) {
|
||||||
if (res.status === 'success') {
|
if (res.status === 'success') {
|
||||||
$('#type-result-alert')
|
$('#type-result-alert')
|
||||||
@ -344,10 +421,14 @@ function(res) {
|
|||||||
$(window).scrollTop(0);
|
$(window).scrollTop(0);
|
||||||
}
|
}
|
||||||
EOD);
|
EOD);
|
||||||
$contest_type_form->runAtServer();
|
$rule_form->runAtServer();
|
||||||
|
|
||||||
$blog_link_contests = new UOJForm('blog_link_contests');
|
$blog_link_contests = new UOJBs4Form('blog_link_contests');
|
||||||
$blog_link_contests->addVInput('blog_id', 'text', '博客 ID', '',
|
$blog_link_contests->addVInput(
|
||||||
|
'blog_id',
|
||||||
|
'text',
|
||||||
|
'博客 ID',
|
||||||
|
'',
|
||||||
function ($blog_id, &$vdata) {
|
function ($blog_id, &$vdata) {
|
||||||
if (!validateUInt($blog_id)) {
|
if (!validateUInt($blog_id)) {
|
||||||
return 'ID 不合法';
|
return 'ID 不合法';
|
||||||
@ -363,7 +444,11 @@ EOD);
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$blog_link_contests->addVInput('title', 'text', '名称', '',
|
$blog_link_contests->addVInput(
|
||||||
|
'title',
|
||||||
|
'text',
|
||||||
|
'名称',
|
||||||
|
'',
|
||||||
function ($title, &$vdata) {
|
function ($title, &$vdata) {
|
||||||
if ($title == '') {
|
if ($title == '') {
|
||||||
return '名称不能为空';
|
return '名称不能为空';
|
||||||
@ -440,7 +525,7 @@ EOD);
|
|||||||
|
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(HTML::stripTags('比赛管理 - ' . $contest['name'])) ?>
|
<?php echoUOJPageHeader(HTML::stripTags('比赛管理 - ' . $contest['name'])) ?>
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= $contest['name'] ?>
|
<?= $contest['name'] ?>
|
||||||
<small class="fs-5">(ID: <?= $contest['id'] ?>)</small>
|
<small class="fs-5">(ID: <?= $contest['id'] ?>)</small>
|
||||||
管理
|
管理
|
||||||
@ -452,10 +537,7 @@ EOD);
|
|||||||
|
|
||||||
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
||||||
|
|
||||||
<a
|
<a class="btn btn-light d-block mt-2 w-100 text-start text-primary" style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;" href="<?= HTML::url("/contest/{$contest['id']}") ?>">
|
||||||
class="btn btn-light d-block mt-2 w-100 text-start text-primary"
|
|
||||||
style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;"
|
|
||||||
href="<?= HTML::url("/contest/{$contest['id']}") ?>">
|
|
||||||
<i class="bi bi-arrow-left"></i> 返回
|
<i class="bi bi-arrow-left"></i> 返回
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@ -501,7 +583,7 @@ EOD);
|
|||||||
['*'],
|
['*'],
|
||||||
'contests_problems',
|
'contests_problems',
|
||||||
"contest_id = '{$contest['id']}'",
|
"contest_id = '{$contest['id']}'",
|
||||||
'ORDER BY dfn, problem_id',
|
'ORDER BY level, problem_id',
|
||||||
<<<EOD
|
<<<EOD
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:3em">ID</th>
|
<th style="width:3em">ID</th>
|
||||||
@ -511,15 +593,15 @@ EOD);
|
|||||||
</tr>
|
</tr>
|
||||||
EOD,
|
EOD,
|
||||||
function ($row) {
|
function ($row) {
|
||||||
$problem = queryProblemBrief($row['problem_id']);
|
$problem = UOJProblem::query($row['problem_id']);
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>', $row['problem_id'], '</td>';
|
echo '<td>', $row['problem_id'], '</td>';
|
||||||
echo '<td>', getProblemLink($problem), '</td>';
|
echo '<td>', $problem->getLink(['with' => 'none']), '</td>';
|
||||||
echo '<td>', isset($contest['extra_config']["problem_{$problem['id']}"]) ? $contest['extra_config']["problem_{$problem['id']}"] : 'sample', '</td>';
|
echo '<td>', isset($contest['extra_config']["problem_{$problem->info['id']}"]) ? $contest['extra_config']["problem_{$problem->info['id']}"] : 'default', '</td>';
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
echo '<form class="d-inline-block" method="POST" target="_self" onsubmit=\'return confirm("你确定要将题目 #', $problem['id'], ' 从比赛中移除吗?")\'>';
|
echo '<form class="d-inline-block" method="POST" target="_self" onsubmit=\'return confirm("你确定要将题目 #', $problem->info['id'], ' 从比赛中移除吗?")\'>';
|
||||||
echo '<input type="hidden" name="_token" value="', crsf_token(), '">';
|
echo '<input type="hidden" name="_token" value="', crsf_token(), '">';
|
||||||
echo '<input type="hidden" name="problem_id" value="', $problem['id'], '">';
|
echo '<input type="hidden" name="problem_id" value="', $problem->info['id'], '">';
|
||||||
echo '<button type="submit" class="btn btn-link text-danger text-decoration-none p-0" name="submit-remove_problem" value="remove_problem">移除</button>';
|
echo '<button type="submit" class="btn btn-link text-danger text-decoration-none p-0" name="submit-remove_problem" value="remove_problem">移除</button>';
|
||||||
echo '</form>';
|
echo '</form>';
|
||||||
echo '</td>';
|
echo '</td>';
|
||||||
@ -544,6 +626,7 @@ EOD,
|
|||||||
<ul class="mt-0">
|
<ul class="mt-0">
|
||||||
<li>推荐在比赛结束前将题目设置为隐藏。</li>
|
<li>推荐在比赛结束前将题目设置为隐藏。</li>
|
||||||
<li>对于「评测设置」选项,一般情况下保持默认(即只测样例)即可。</li>
|
<li>对于「评测设置」选项,一般情况下保持默认(即只测样例)即可。</li>
|
||||||
|
<li>在 ACM 赛制中,如果设置一道题目为 bonus 题,那么获得 100 分后会总罚时会减少 20 分钟,但排名时不会将此题记入该选手通过的题目总数中。</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -618,7 +701,7 @@ EOD,
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
<ul class="nav nav-tabs card-header-tabs" role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="#type" data-bs-toggle="tab" data-bs-target="#type">赛制管理</a>
|
<a class="nav-link active" href="#type" data-bs-toggle="tab" data-bs-target="#type">规则</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="#standings-version" data-bs-toggle="tab" data-bs-target="#standings-version">排名版本</a>
|
<a class="nav-link" href="#standings-version" data-bs-toggle="tab" data-bs-target="#standings-version">排名版本</a>
|
||||||
@ -633,12 +716,18 @@ EOD,
|
|||||||
<div id="type-result-alert" class="alert" role="alert" style="display: none"></div>
|
<div id="type-result-alert" class="alert" role="alert" style="display: none"></div>
|
||||||
<div class="row row-cols-1 row-cols-md-2">
|
<div class="row row-cols-1 row-cols-md-2">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<?php $contest_type_form->printHTML(); ?>
|
<?php $rule_form->printHTML(); ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="col mt-3 mt-md-0">
|
<div class="col mt-3 mt-md-0">
|
||||||
<h5>注意事项</h5>
|
<h5>赛制解释</h5>
|
||||||
|
<ul>
|
||||||
|
<li><strong>OI 赛制:</strong> 比赛期间可设置题目只测样例,结束后会进行重测。按最后一次有效提交算分和算罚时。</li>
|
||||||
|
<li><strong>ACM 赛制:</strong> 比赛期间所有题目显示最终测评结果。比赛结束前一小时封榜,比赛时间不足 5 小时则比赛过去五分之四后封榜。一道题的罚时为得分最高的提交的时间,加上在此之前没有使得该题分数增加的提交的次数乘以 20 分钟。</li>
|
||||||
|
<li><strong>IOI 赛制:</strong> 比赛期间所有题目显示最终测评结果。按得分最高的有效提交算分和算罚时。</li>
|
||||||
|
</ul>
|
||||||
|
<h5>常见问题</h5>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
<li>目前 S2OJ 支持 OI 和 IOI 赛制。</li>
|
<li></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,104 +2,96 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
$contest = UOJContest::info();
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($contest = queryContest($_GET['id']))) {
|
$is_manager = UOJContest::cur()->userCanManage(Auth::user());
|
||||||
become404Page();
|
$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) {
|
if (!$user) {
|
||||||
return '用户不存在';
|
return '用户不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasRegistered($user, $contest)) {
|
if (UOJContest::cur()->userHasRegistered($user)) {
|
||||||
return '该用户已经报名';
|
return '该用户已经报名';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['user'] = $user;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_new_contestant_form->submit_button_config['align'] = 'compressed';
|
$add_new_contestant_form->submit_button_config['align'] = 'compressed';
|
||||||
$add_new_contestant_form->submit_button_config['text'] = '注册该用户';
|
$add_new_contestant_form->submit_button_config['text'] = '注册该用户';
|
||||||
$add_new_contestant_form->handle = function() {
|
$add_new_contestant_form->handle = function (&$vdata) {
|
||||||
global $contest;
|
UOJContest::cur()->userRegister($vdata['user']);
|
||||||
|
|
||||||
$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_new_contestant_form->runAtServer();
|
||||||
|
|
||||||
$add_group_to_contest_form = new UOJForm('add_group_to_contest');
|
$add_group_to_contest_form = new UOJBs4Form('add_group_to_contest');
|
||||||
$add_group_to_contest_form->addInput('group_id', 'text', '小组 ID', '',
|
$add_group_to_contest_form->addInput(
|
||||||
function ($x) {
|
'group_id',
|
||||||
global $contest;
|
'text',
|
||||||
|
'小组 ID',
|
||||||
if (!validateUInt($x)) {
|
'',
|
||||||
|
function ($group_id, &$vdata) {
|
||||||
|
if (!validateUInt($group_id)) {
|
||||||
return '小组 ID 不合法';
|
return '小组 ID 不合法';
|
||||||
}
|
}
|
||||||
$group = queryGroup($x);
|
$group = queryGroup($group_id);
|
||||||
if (!$group) {
|
if (!$group) {
|
||||||
return '小组不存在';
|
return '小组不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['group_id'] = $group_id;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_group_to_contest_form->submit_button_config['align'] = 'compressed';
|
$add_group_to_contest_form->submit_button_config['align'] = 'compressed';
|
||||||
$add_group_to_contest_form->submit_button_config['text'] = '注册该小组中的用户';
|
$add_group_to_contest_form->submit_button_config['text'] = '注册该小组中的用户';
|
||||||
$add_group_to_contest_form->handle = function() {
|
$add_group_to_contest_form->handle = function (&$vdata) {
|
||||||
global $contest;
|
$users = queryGroupUsers($vdata['group_id']);
|
||||||
$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) {
|
foreach ($users as $user) {
|
||||||
DB::query("replace into contests_registrants (username, contest_id, has_participated) values ('{$user['username']}', {$contest['id']}, 0)");
|
UOJContest::cur()->userRegister($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContestPlayerNum($contest);
|
|
||||||
};
|
};
|
||||||
$add_group_to_contest_form->runAtServer();
|
$add_group_to_contest_form->runAtServer();
|
||||||
|
|
||||||
$remove_user_from_contest_form = new UOJForm('remove_user_from_contest');
|
$remove_user_from_contest_form = new UOJBs4Form('remove_user_from_contest');
|
||||||
$remove_user_from_contest_form->addInput('remove_username', 'text', '用户名', '',
|
$remove_user_from_contest_form->addInput(
|
||||||
function ($x) {
|
'remove_username',
|
||||||
global $contest;
|
'text',
|
||||||
if (!validateUsername($x)) {
|
'用户名',
|
||||||
return '用户名不合法';
|
'',
|
||||||
}
|
function ($username, &$vdata) {
|
||||||
|
$user = UOJUser::query($username);
|
||||||
|
|
||||||
$user = queryUser($x);
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return '用户不存在';
|
return '用户不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasRegistered($user, $contest)) {
|
if (!UOJContest::cur()->userHasRegistered($user)) {
|
||||||
return '该用户未报名';
|
return '该用户未报名';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['user'] = $user;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
@ -107,33 +99,30 @@
|
|||||||
$remove_user_from_contest_form->submit_button_config['align'] = 'compressed';
|
$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['text'] = '移除该用户';
|
||||||
$remove_user_from_contest_form->submit_button_config['class_str'] = 'mt-2 btn btn-danger';
|
$remove_user_from_contest_form->submit_button_config['class_str'] = 'mt-2 btn btn-danger';
|
||||||
$remove_user_from_contest_form->handle = function() {
|
$remove_user_from_contest_form->handle = function (&$vdata) {
|
||||||
global $contest;
|
UOJContest::cur()->userUnregister($vdata['user']);
|
||||||
$username = $_POST['remove_username'];
|
|
||||||
|
|
||||||
DB::query("delete from contests_registrants where username = '{$username}' and contest_id = {$contest['id']}");
|
|
||||||
updateContestPlayerNum($contest);
|
|
||||||
};
|
};
|
||||||
$remove_user_from_contest_form->runAtServer();
|
$remove_user_from_contest_form->runAtServer();
|
||||||
|
|
||||||
$force_set_user_participated_form = new UOJForm('force_set_user_participated');
|
$force_set_user_participated_form = new UOJBs4Form('force_set_user_participated');
|
||||||
$force_set_user_participated_form->addInput('force_set_username', 'text', '用户名', '',
|
$force_set_user_participated_form->addInput(
|
||||||
function ($x) {
|
'force_set_username',
|
||||||
global $contest;
|
'text',
|
||||||
|
'用户名',
|
||||||
|
'',
|
||||||
|
function ($username, &$vdata) {
|
||||||
|
$user = UOJUser::query($username);
|
||||||
|
|
||||||
if (!validateUsername($x)) {
|
|
||||||
return '用户名不合法';
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = queryUser($x);
|
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
return '用户不存在';
|
return '用户不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasRegistered($user, $contest)) {
|
if (!UOJContest::cur()->userHasRegistered($user)) {
|
||||||
return '该用户未报名';
|
return '该用户未报名';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['user'] = $user;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
@ -141,30 +130,21 @@
|
|||||||
$force_set_user_participated_form->submit_button_config['align'] = 'compressed';
|
$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['text'] = '强制参赛';
|
||||||
$force_set_user_participated_form->submit_button_config['class_str'] = 'mt-2 btn btn-warning';
|
$force_set_user_participated_form->submit_button_config['class_str'] = 'mt-2 btn btn-warning';
|
||||||
$force_set_user_participated_form->handle = function() {
|
$force_set_user_participated_form->handle = function (&$vdata) {
|
||||||
global $contest;
|
UOJContest::cur()->markUserAsParticipated($vdata['user']);
|
||||||
$username = $_POST['force_set_username'];
|
|
||||||
|
|
||||||
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();
|
$force_set_user_participated_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
$has_contest_permission = hasContestPermission($myUser, $contest);
|
|
||||||
$show_ip = $has_contest_permission;
|
|
||||||
|
|
||||||
if ($contest['cur_progress'] == CONTEST_NOT_STARTED) {
|
if ($contest['cur_progress'] == CONTEST_NOT_STARTED) {
|
||||||
$iHasRegistered = $myUser != null && hasRegistered($myUser, $contest);
|
$iHasRegistered = UOJContest::cur()->userHasRegistered(Auth::user());
|
||||||
|
|
||||||
if ($iHasRegistered) {
|
if ($iHasRegistered) {
|
||||||
$unregister_form = new UOJForm('unregister');
|
if ($iHasRegistered && UOJContest::cur()->freeRegistration()) {
|
||||||
|
$unregister_form = new UOJBs4Form('unregister');
|
||||||
$unregister_form->handle = function () {
|
$unregister_form->handle = function () {
|
||||||
global $myUser, $contest;
|
UOJContest::cur()->userUnregister(Auth::user());
|
||||||
DB::query("delete from contests_registrants where username = '{$myUser['username']}' and contest_id = {$contest['id']}");
|
|
||||||
updateContestPlayerNum($contest);
|
|
||||||
};
|
};
|
||||||
$unregister_form->submit_button_config['align'] = 'right';
|
|
||||||
$unregister_form->submit_button_config['class_str'] = 'btn btn-danger btn-xs';
|
$unregister_form->submit_button_config['class_str'] = 'btn btn-danger btn-xs';
|
||||||
$unregister_form->submit_button_config['text'] = '取消报名';
|
$unregister_form->submit_button_config['text'] = '取消报名';
|
||||||
$unregister_form->succ_href = "/contests";
|
$unregister_form->succ_href = "/contests";
|
||||||
@ -172,10 +152,11 @@
|
|||||||
$unregister_form->runAtServer();
|
$unregister_form->runAtServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(HTML::stripTags($contest['name']) . ' - ' . UOJLocale::get('contests::contest registrants')) ?>
|
<?php echoUOJPageHeader(HTML::stripTags($contest['name']) . ' - ' . UOJLocale::get('contests::contest registrants')) ?>
|
||||||
|
|
||||||
<h1 class="h2 text-center">
|
<h1 class="text-center">
|
||||||
<?= $contest['name'] ?>
|
<?= $contest['name'] ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -200,7 +181,7 @@
|
|||||||
if ($show_ip) {
|
if ($show_ip) {
|
||||||
$header_row .= '<th>remote_addr</th><th>http_x_forwarded_for</th>';
|
$header_row .= '<th>remote_addr</th><th>http_x_forwarded_for</th>';
|
||||||
}
|
}
|
||||||
if ($has_contest_permission) {
|
if ($is_manager) {
|
||||||
$header_row .= '<th>是否参赛</th>';
|
$header_row .= '<th>是否参赛</th>';
|
||||||
}
|
}
|
||||||
$header_row .= '</tr>';
|
$header_row .= '</tr>';
|
||||||
@ -208,20 +189,20 @@
|
|||||||
echoLongTable(
|
echoLongTable(
|
||||||
['*'],
|
['*'],
|
||||||
'contests_registrants',
|
'contests_registrants',
|
||||||
"contest_id = {$contest['id']}",
|
['contest_id' => $contest['id']],
|
||||||
'order by username desc',
|
'order by username desc',
|
||||||
$header_row,
|
$header_row,
|
||||||
function($contestant, $num) use ($myUser, $has_contest_permission, $show_ip, $has_participated) {
|
function ($contestant, $num) use ($is_manager, $show_ip) {
|
||||||
$user = queryUser($contestant['username']);
|
$user = UOJUser::query($contestant['username']);
|
||||||
|
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>' . $num . '</td>';
|
echo '<td>' . $num . '</td>';
|
||||||
echo '<td>'.getUserLink($contestant['username']).'</td>';
|
echo '<td>' . getUserLink($user['username']) . '</td>';
|
||||||
if ($show_ip) {
|
if ($show_ip) {
|
||||||
echo '<td>' . $user['remote_addr'] . '</td>';
|
echo '<td>' . $user['remote_addr'] . '</td>';
|
||||||
echo '<td>' . $user['http_x_forwarded_for'] . '</td>';
|
echo '<td>' . $user['http_x_forwarded_for'] . '</td>';
|
||||||
}
|
}
|
||||||
if ($has_contest_permission) {
|
if ($is_manager) {
|
||||||
echo '<td>' . ($contestant['has_participated'] ? 'Yes' : 'No') . '</td>';
|
echo '<td>' . ($contestant['has_participated'] ? 'Yes' : 'No') . '</td>';
|
||||||
}
|
}
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
|
@ -2,63 +2,47 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($contest = queryContest($_GET['id']))) {
|
Auth::check() || redirectToLogin();
|
||||||
become404Page();
|
UOJContest::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
UOJContest::cur()->userCanRegister(Auth::user(), ['ensure' => true]);
|
||||||
genMoreContestInfo($contest);
|
|
||||||
|
|
||||||
if (!Auth::check()) {
|
$register_form = new UOJBs4Form('register');
|
||||||
redirectToLogin();
|
$register_form->handle = function () {
|
||||||
} elseif (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
UOJContest::cur()->userRegister(Auth::user());
|
||||||
become403Page();
|
|
||||||
} elseif (hasRegistered($myUser, $contest)) {
|
|
||||||
if ($contest['cur_progress'] < CONTEST_IN_PROGRESS) {
|
|
||||||
redirectTo('/contests');
|
|
||||||
} elseif ($contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
|
||||||
redirectTo("/contest/{$contest['id']}/confirm");
|
|
||||||
} else {
|
|
||||||
redirectTo("/contest/{$contest['id']}");
|
|
||||||
}
|
|
||||||
} elseif ($contest['cur_progress'] > 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)");
|
|
||||||
|
|
||||||
updateContestPlayerNum($contest);
|
|
||||||
};
|
};
|
||||||
$register_form->submit_button_config['class_str'] = 'btn btn-primary';
|
$register_form->submit_button_config['class_str'] = 'btn btn-primary';
|
||||||
$register_form->submit_button_config['text'] = '我已阅读规则,确认报名比赛';
|
$register_form->submit_button_config['text'] = '我已阅读规则,确认报名比赛';
|
||||||
|
|
||||||
if ($contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
if (UOJContest::cur()->progress() == CONTEST_IN_PROGRESS) {
|
||||||
$register_form->succ_href = "/contest/{$contest['id']}/confirm";
|
$register_form->succ_href = '/contest/' . UOJContest::info('id') . '/confirm';
|
||||||
} else {
|
} else {
|
||||||
$register_form->succ_href = "/contests";
|
$register_form->succ_href = '/contests';
|
||||||
}
|
}
|
||||||
|
|
||||||
$register_form->runAtServer();
|
$register_form->runAtServer();
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader('报名 - ' . HTML::stripTags($contest['name'])) ?>
|
|
||||||
|
<?php echoUOJPageHeader('报名 - ' . UOJContest::info('name')) ?>
|
||||||
|
|
||||||
<div class="card mw-100 mx-auto" style="width:800px">
|
<div class="card mw-100 mx-auto" style="width:800px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h1 class="h2 card-title text-center mb-3">比赛规则</h1>
|
<h1 class="card-title text-center mb-3">比赛规则</h1>
|
||||||
|
|
||||||
<p class="card-text">您即将报名比赛 “<b><?= $contest['name'] ?></b>”,请在报名前仔细阅读以下比赛规则:</p>
|
<p class="card-text">您即将报名比赛 “<b><?= UOJContest::info('name') ?></b>”,请在报名前仔细阅读以下比赛规则:</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<?php if ($contest['cur_progress'] == CONTEST_IN_PROGRESS): ?>
|
<?php if (UOJContest::cur()->progress() == CONTEST_IN_PROGRESS) : ?>
|
||||||
<li class="text-danger">本场比赛正在进行中,将于 <b><?= $contest['end_time_str'] ?></b> 结束。</li>
|
<li class="text-danger">本场比赛正在进行中,将于 <b><?= UOJContest::info('end_time_str') ?></b> 结束。</li>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<li>本场比赛将于 <b><?= $contest['start_time_str'] ?></b> 开始,并于 <b><?= $contest['end_time_str'] ?></b> 结束。</li>
|
<li>本场比赛将于 <b><?= UOJContest::info('start_time_str') ?></b> 开始,并于 <b><?= UOJContest::info('end_time_str') ?></b> 结束。</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<li>比赛开始后点击 “<b>确认参赛</b>” 按钮才会被视为正式参赛,未正式参赛的选手不会显示在排行榜上。</li>
|
<li>比赛开始后点击 “<b>确认参赛</b>” 按钮才会被视为正式参赛,未正式参赛的选手不会显示在排行榜上。</li>
|
||||||
<?php if (!isset($contest['extra_config']['contest_type']) || $contest['extra_config']['contest_type'] == 'OI'): ?>
|
<?php if (UOJContest::cur()->basicRule() == 'OI') : ?>
|
||||||
<li>本场比赛为 OI 赛制。比赛中途可以提交代码,但 <b>只显示测样例的结果</b>。</li>
|
<li>本场比赛为 OI 赛制。比赛中途可以提交代码,但 <b>只显示测样例的结果</b>。</li>
|
||||||
<?php elseif ($contest['extra_config']['contest_type'] == 'IOI'): ?>
|
<?php elseif (UOJContest::cur()->basicRule() == 'IOI') : ?>
|
||||||
<li>本场比赛为 IOI 赛制。比赛时的提交会测试题目的全部数据,但无法查看数据点详情。</li>
|
<li>本场比赛为 IOI 赛制。比赛时的提交会测试题目的全部数据,但无法查看数据点详情。</li>
|
||||||
|
<?php elseif (UOJContest::cur()->basicRule() == 'ACM') : ?>
|
||||||
|
<li>本场比赛为 ACM 赛制。</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<li>若选手在比赛中多次提交了同一题,则最后按照 <b>最后一次不是 Compile Error 的提交</b> 计算排行。</li>
|
<li>若选手在比赛中多次提交了同一题,则最后按照 <b>最后一次不是 Compile Error 的提交</b> 计算排行。</li>
|
||||||
<li>比赛结束后会进行最终测试,最终测试后的排名为最终排名。</li>
|
<li>比赛结束后会进行最终测试,最终测试后的排名为最终排名。</li>
|
||||||
|
@ -2,55 +2,57 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
$upcoming_contest_name = null;
|
$upcoming_contest_name = null;
|
||||||
$upcoming_contest_href = null;
|
$upcoming_contest_href = null;
|
||||||
$rest_second = 1000000;
|
$rest_second = 1000000;
|
||||||
function echoContest($contest) {
|
function echoContest($info) {
|
||||||
global $myUser, $upcoming_contest_name, $upcoming_contest_href, $rest_second;
|
global $upcoming_contest_name, $upcoming_contest_href, $rest_second;
|
||||||
|
|
||||||
$contest_name_link = <<<EOD
|
$contest = new UOJContest($info);
|
||||||
<a class="text-decoration-none" href="/contest/{$contest['id']}">{$contest['name']}</a>
|
|
||||||
EOD;
|
$contest_name_link = '<a class="text-decoration-none" href="/contest/' . $contest->info['id'] . '">' . $contest->info['name'] . '</a>';
|
||||||
genMoreContestInfo($contest);
|
|
||||||
if ($contest['cur_progress'] == CONTEST_NOT_STARTED) {
|
if ($contest->progress() == CONTEST_NOT_STARTED) {
|
||||||
$cur_rest_second = $contest['start_time']->getTimestamp() - UOJTime::$time_now->getTimestamp();
|
$cur_rest_second = $contest->info['start_time']->getTimestamp() - UOJTime::$time_now->getTimestamp();
|
||||||
if ($cur_rest_second < $rest_second) {
|
if ($cur_rest_second < $rest_second) {
|
||||||
$upcoming_contest_name = $contest['name'];
|
$upcoming_contest_name = $contest->info['name'];
|
||||||
$upcoming_contest_href = "/contest/{$contest['id']}";
|
$upcoming_contest_href = '/contest/' . $contest->info['id'];
|
||||||
$rest_second = $cur_rest_second;
|
$rest_second = $cur_rest_second;
|
||||||
}
|
}
|
||||||
if ($myUser != null && hasRegistered($myUser, $contest)) {
|
if ($contest->userHasRegistered(Auth::user())) {
|
||||||
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:green">' . UOJLocale::get('contests::registered') . '</a></sup>';
|
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:green">' . UOJLocale::get('contests::registered') . '</a></sup>';
|
||||||
} else {
|
} else {
|
||||||
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:red" href="/contest/'.$contest['id'].'/register">'.UOJLocale::get('contests::register').'</a></sup>';
|
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:red" href="/contest/' . $contest->info['id'] . '/register">' . UOJLocale::get('contests::register') . '</a></sup>';
|
||||||
}
|
}
|
||||||
} elseif ($contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
} elseif ($contest->progress() == CONTEST_IN_PROGRESS) {
|
||||||
if (hasRegistered($myUser, $contest)) {
|
if ($contest->allowExtraRegistration() && !$contest->userHasRegistered(Auth::user())) {
|
||||||
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:blue" href="/contest/'.$contest['id'].'">'.UOJLocale::get('contests::in progress').'</a></sup>';
|
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:red" href="/contest/' . $contest->info['id'] . '/register">' . UOJLocale::get('contests::register') . ' (' . UOJLocale::get('contests::in progress') . ')' . '</a></sup>';
|
||||||
} else {
|
} else {
|
||||||
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:blue" href="/contest/'.$contest['id'].'/register">'.UOJLocale::get('contests::in progress').'</a></sup>';
|
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:blue" href="/contest/' . $contest->info['id'] . '">' . UOJLocale::get('contests::in progress') . '</a></sup>';
|
||||||
|
}
|
||||||
|
} elseif ($contest->progress() == CONTEST_FINISHED) {
|
||||||
|
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:grey" href="/contest/' . $contest->info['id'] . '/standings">' . UOJLocale::get('contests::ended') . '</a></sup>';
|
||||||
|
} else {
|
||||||
|
if ($contest->basicRule() == 'OI') {
|
||||||
|
if ($contest->progress() == CONTEST_PENDING_FINAL_TEST) {
|
||||||
|
$contest_name_link .= '<sup><a style="color:blue" href="/contest/' . $contest->info['id'] . '">' . UOJLocale::get('contests::pending final test') . '</a></sup>';
|
||||||
|
} elseif ($contest->progress() == CONTEST_TESTING) {
|
||||||
|
$contest_name_link .= '<sup><a style="color:blue" href="/contest/' . $contest->info['id'] . '">' . UOJLocale::get('contests::final testing') . '</a></sup>';
|
||||||
|
}
|
||||||
|
} elseif ($contest->basicRule() == 'ACM' || $contest->basicRule() == 'IOI') {
|
||||||
|
$contest_name_link .= '<sup><a style="color:blue" href="/contest/' . $contest->info['id'] . '">' . UOJLocale::get('contests::official results to be announced') . '</a></sup>';
|
||||||
}
|
}
|
||||||
} elseif ($contest['cur_progress'] == CONTEST_PENDING_FINAL_TEST) {
|
|
||||||
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:blue" href="/contest/'.$contest['id'].'">'.UOJLocale::get('contests::pending final test').'</a></sup>';
|
|
||||||
} elseif ($contest['cur_progress'] == CONTEST_TESTING) {
|
|
||||||
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:blue" href="/contest/'.$contest['id'].'">'.UOJLocale::get('contests::final testing').'</a></sup>';
|
|
||||||
} elseif ($contest['cur_progress'] == CONTEST_FINISHED) {
|
|
||||||
$contest_name_link .= '<sup><a class="text-decoration-none" style="color:grey" href="/contest/'.$contest['id'].'/standings">'.UOJLocale::get('contests::ended').'</a></sup>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$last_hour = round($contest['last_min'] / 60, 2);
|
$last_hour = round($contest->info['last_min'] / 60, 2);
|
||||||
|
|
||||||
$click_zan_block = getClickZanBlock('C', $contest['id'], $contest['zan']);
|
|
||||||
echo '<tr>';
|
echo '<tr>';
|
||||||
echo '<td>', $contest_name_link, '</td>';
|
echo '<td>', $contest_name_link, '</td>';
|
||||||
echo '<td>', '<a class="text-decoration-none" href="'.HTML::timeanddate_url($contest['start_time'], array('duration' => $contest['last_min'])).'">'.$contest['start_time_str'].'</a>', '</td>';
|
echo '<td>', '<a class="text-decoration-none" href="' . HTML::timeanddate_url($contest->info['start_time'], ['duration' => $contest->info['last_min']]) . '">' . $contest->info['start_time_str'] . '</a>', '</td>';
|
||||||
echo '<td>', UOJLocale::get('hours', $last_hour), '</td>';
|
echo '<td>', UOJLocale::get('hours', $last_hour), '</td>';
|
||||||
echo '<td>', '<a class="text-decoration-none" href="/contest/'.$contest['id'].'/registrants">', '<i class="bi bi-person-fill"></i>', ' ×'.$contest['player_num'].'</a>', '</td>';
|
echo '<td>', '<a class="text-decoration-none" href="/contest/' . $contest->info['id'] . '/registrants">', '<i class="bi bi-person-fill"></i>', ' ×' . $contest->info['player_num'] . '</a>', '</td>';
|
||||||
echo '<td>', '<div class="text-left">'.$click_zan_block.'</div>', '</td>';
|
echo '<td>', '<div class="text-left">' . ClickZans::getBlock('C', $contest->info['id'], $contest->info['zan']) . '</div>', '</td>';
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@ -58,7 +60,7 @@ EOD;
|
|||||||
|
|
||||||
<!-- title container -->
|
<!-- title container -->
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('contests') ?>
|
<?= UOJLocale::get('contests') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -71,7 +73,7 @@ EOD;
|
|||||||
</div>
|
</div>
|
||||||
<!-- end title container -->
|
<!-- end title container -->
|
||||||
|
|
||||||
<h2 class="h4">
|
<h2>
|
||||||
<?= UOJLocale::get('contests::current or upcoming contests') ?>
|
<?= UOJLocale::get('contests::current or upcoming contests') ?>
|
||||||
</h2>
|
</h2>
|
||||||
<?php
|
<?php
|
||||||
@ -93,10 +95,10 @@ EOD;
|
|||||||
echoLongTable(
|
echoLongTable(
|
||||||
['*'],
|
['*'],
|
||||||
'contests',
|
'contests',
|
||||||
"status != 'finished'",
|
[["status", "!=", 'finished']],
|
||||||
'order by start_time asc, id asc',
|
'order by start_time asc, id asc',
|
||||||
$table_header,
|
$table_header,
|
||||||
echoContest,
|
'echoContest',
|
||||||
$table_config
|
$table_config
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -118,18 +120,20 @@ EOD;
|
|||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<h2 class="h4">
|
<h2>
|
||||||
<?= UOJLocale::get('contests::ended contests') ?>
|
<?= UOJLocale::get('contests::ended contests') ?>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
echoLongTable(
|
echoLongTable(
|
||||||
['*'],
|
['*'],
|
||||||
'contests',
|
'contests',
|
||||||
"status = 'finished'",
|
['status' => 'finished'],
|
||||||
'order by start_time desc, id desc',
|
'order by start_time desc, id desc',
|
||||||
$table_header,
|
$table_header,
|
||||||
echoContest,
|
'echoContest',
|
||||||
$table_config
|
$table_config
|
||||||
);
|
);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,140 +1,61 @@
|
|||||||
<?php
|
<?php
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
$auth = false;
|
||||||
redirectToLogin();
|
if (UOJRequest::get('auth') === 'judger') {
|
||||||
|
authenticateJudger() || UOJResponse::page403();
|
||||||
|
$auth = true;
|
||||||
|
} else {
|
||||||
|
Auth::check() || redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login'] && $_GET['type'] != 'attachment') {
|
switch (UOJRequest::get('type')) {
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($_GET['type']) {
|
|
||||||
case 'attachment':
|
case 'attachment':
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become404Page();
|
if (!$auth) {
|
||||||
|
UOJProblem::cur()->userCanDownloadAttachments(Auth::user()) || UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
|
||||||
$visible = isProblemVisibleToUser($problem, $myUser);
|
$file_name = UOJProblem::cur()->getDataFolderPath() . '/download.zip';
|
||||||
if (!$visible && $myUser != null) {
|
$download_name = 'problem_' . UOJProblem::info('id') . '_attachment.zip';
|
||||||
$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();
|
|
||||||
}
|
|
||||||
|
|
||||||
$id = $_GET['id'];
|
|
||||||
|
|
||||||
$file_name = "/var/uoj_data/$id/download.zip";
|
|
||||||
$download_name = "problem_{$id}_attachment.zip";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'problem':
|
case 'problem':
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become404Page();
|
|
||||||
|
if (!$auth) {
|
||||||
|
UOJProblem::cur()->userCanDownloadTestData(Auth::user()) || UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isProblemVisibleToUser($problem, $myUser)) {
|
$file_name = UOJProblem::cur()->getDataZipPath();
|
||||||
become404Page();
|
$download_name = 'problem_' . UOJProblem::info('id') . '.zip';
|
||||||
}
|
|
||||||
|
|
||||||
$id = $_GET['id'];
|
|
||||||
$file_name = "/var/uoj_data/$id.zip";
|
|
||||||
$download_name = "problem_$id.zip";
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'testcase':
|
case 'submission':
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
if (!$auth) {
|
||||||
become404Page();
|
isSuperUser(Auth::user()) || UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
$file_name = UOJContext::storagePath() . "/submission/{$_GET['id']}/{$_GET['rand_str_id']}";
|
||||||
if (!isProblemVisibleToUser($problem, $myUser)) {
|
$download_name = "submission.zip";
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$id = $_GET['id'];
|
|
||||||
$problem_conf = getUOJConf("/var/uoj_data/$id/problem.conf");
|
|
||||||
|
|
||||||
if ($problem_conf == -1 || $problem_conf == -2) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
break;
|
||||||
|
|
||||||
case 'output':
|
case 'tmp':
|
||||||
$file_name = "/var/uoj_data/$id/" . getUOJProblemExtraOutputFileName($problem_conf, $testcase_id);
|
if (!$auth) {
|
||||||
$download_name = getUOJProblemExtraOutputFileName($problem_conf, $testcase_id);
|
isSuperUser(Auth::user()) || UOJResponse::page404();
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
become404Page();
|
|
||||||
}
|
}
|
||||||
} else {
|
$file_name = UOJContext::storagePath() . "/tmp/{$_GET['rand_str_id']}";
|
||||||
$n_tests = getUOJConfVal($problem_conf, 'n_tests', 10);
|
$download_name = "tmp";
|
||||||
|
|
||||||
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;
|
break;
|
||||||
|
|
||||||
case 'testlib.h':
|
case 'testlib.h':
|
||||||
$file_name = "/opt/uoj/judger/uoj_judger/include/testlib.h";
|
$file_name = UOJLocalRun::$judger_include_path . '/testlib.h';
|
||||||
$download_name = "testlib.h";
|
$download_name = 'testlib.h';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
become404Page();
|
UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
|
||||||
$finfo = finfo_open(FILEINFO_MIME);
|
UOJResponse::xsendfile($file_name, ['attachment' => $download_name]);
|
||||||
$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");
|
|
||||||
?>
|
|
||||||
|
@ -9,10 +9,9 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
|
||||||
<div class="card card-default">
|
<div class="card card-default">
|
||||||
<article class="card-body">
|
<article class="card-body">
|
||||||
<h1 class="h3 card-title mb-3">常见问题及其解答 (FAQ)</h1>
|
<h1 class="h2 card-title mb-3">常见问题及其解答 (FAQ)</h1>
|
||||||
|
|
||||||
<h5 class="mt-4"><?= UOJConfig::$data['profile']['oj-name-short'] ?> 是什么</h5>
|
<h5 class="mt-4"><?= UOJConfig::$data['profile']['oj-name-short'] ?> 是什么</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
@ -109,13 +108,12 @@
|
|||||||
</p>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<?php uojIncludeView('sidebar', array()) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
$forgot_form = new UOJForm('forgot');
|
$forgot_form = new UOJBs4Form('forgot');
|
||||||
$forgot_form->addInput('username', 'text', '用户名', '',
|
$forgot_form->addInput('username', 'text', '用户名', '',
|
||||||
function($username, &$vdata) {
|
function($username, &$vdata) {
|
||||||
if (!validateUsername($username)) {
|
if (!validateUsername($username)) {
|
||||||
|
@ -4,14 +4,10 @@
|
|||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$group_id = $_GET['id'];
|
$group_id = $_GET['id'];
|
||||||
if (!validateUInt($group_id) || !($group = queryGroup($group_id))) {
|
if (!validateUInt($group_id) || !($group = queryGroup($group_id))) {
|
||||||
become404Page();
|
become404Page();
|
||||||
@ -30,7 +26,7 @@
|
|||||||
|
|
||||||
<!-- title -->
|
<!-- title -->
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?php if ($group['is_hidden']): ?>
|
<?php if ($group['is_hidden']): ?>
|
||||||
<span class="fs-5 text-danger">[隐藏]</span>
|
<span class="fs-5 text-danger">[隐藏]</span>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -51,7 +47,7 @@
|
|||||||
<!-- main content -->
|
<!-- main content -->
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="h4">
|
<h2 class="h3">
|
||||||
<?= UOJLocale::get('group announcement') ?>
|
<?= UOJLocale::get('group announcement') ?>
|
||||||
</h2>
|
</h2>
|
||||||
<?php if ($group['announcement']): ?>
|
<?php if ($group['announcement']): ?>
|
||||||
@ -68,7 +64,7 @@
|
|||||||
|
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title h4">
|
<h2 class="card-title h3">
|
||||||
<?= UOJLocale::get('news') ?>
|
<?= UOJLocale::get('news') ?>
|
||||||
</h5>
|
</h5>
|
||||||
<ul class="mb-0">
|
<ul class="mb-0">
|
||||||
@ -92,7 +88,7 @@
|
|||||||
|
|
||||||
<div class="card card-default mb-3">
|
<div class="card card-default mb-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title h4">
|
<h2 class="card-title h3">
|
||||||
<?= UOJLocale::get('assignments') ?>
|
<?= UOJLocale::get('assignments') ?>
|
||||||
</h5>
|
</h5>
|
||||||
<?php
|
<?php
|
||||||
@ -139,7 +135,7 @@ EOD,
|
|||||||
|
|
||||||
<div class="card card-default mb-3">
|
<div class="card card-default mb-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title h4">
|
<h2 class="card-title h3">
|
||||||
<?= UOJLocale::get('top solver') ?>
|
<?= UOJLocale::get('top solver') ?>
|
||||||
</h5>
|
</h5>
|
||||||
<?php echoRanklist([
|
<?php echoRanklist([
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
|
|
||||||
@ -40,7 +36,7 @@
|
|||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<small class="fs-4">作业:</small><?= $list['title'] ?>
|
<small class="fs-4">作业:</small><?= $list['title'] ?>
|
||||||
</h1>
|
</h1>
|
||||||
<ul class="mt-3">
|
<ul class="mt-3">
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($cur_tab == 'profile') {
|
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'],
|
$update_profile_form->addVInput('name', 'text', '名称', $group['title'],
|
||||||
function($title, &$vdata) {
|
function($title, &$vdata) {
|
||||||
if ($title == '') {
|
if ($title == '') {
|
||||||
@ -107,7 +107,7 @@ function(res) {
|
|||||||
$(window).scrollTop(0);
|
$(window).scrollTop(0);
|
||||||
}
|
}
|
||||||
EOD);
|
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->submit_button_config['text'] = '更新';
|
||||||
$update_profile_form->runAtServer();
|
$update_profile_form->runAtServer();
|
||||||
} elseif ($cur_tab == 'assignments') {
|
} elseif ($cur_tab == 'assignments') {
|
||||||
@ -127,7 +127,7 @@ EOD);
|
|||||||
dieWithAlert('移除成功!');
|
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', '',
|
$add_new_assignment_form->addVInput('new_assignment_list_id', 'text', '题单 ID', '',
|
||||||
function ($list_id, &$vdata) use ($group) {
|
function ($list_id, &$vdata) use ($group) {
|
||||||
if (!validateUInt($list_id)) {
|
if (!validateUInt($list_id)) {
|
||||||
@ -177,7 +177,7 @@ EOD);
|
|||||||
'message' => '题单 #' . $vdata['list_id'] . ' 已经被添加到作业列表中,结束时间为 ' . $vdata['end_time']->format('Y-m-d H:i:s') . '。'
|
'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->submit_button_config['text'] = '添加';
|
||||||
$add_new_assignment_form->setAjaxSubmit(<<<EOD
|
$add_new_assignment_form->setAjaxSubmit(<<<EOD
|
||||||
function(res) {
|
function(res) {
|
||||||
@ -223,7 +223,7 @@ EOD);
|
|||||||
dieWithAlert('移除成功!');
|
dieWithAlert('移除成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$add_new_user_form = new UOJForm('add_new_user');
|
$add_new_user_form = new UOJBs4Form('add_new_user');
|
||||||
$add_new_user_form->addVInput('new_username', 'text', '用户名', '',
|
$add_new_user_form->addVInput('new_username', 'text', '用户名', '',
|
||||||
function ($username, &$vdata) {
|
function ($username, &$vdata) {
|
||||||
global $group_id;
|
global $group_id;
|
||||||
@ -246,7 +246,7 @@ EOD);
|
|||||||
},
|
},
|
||||||
null
|
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->submit_button_config['text'] = '添加';
|
||||||
$add_new_user_form->handle = function(&$vdata) use ($group) {
|
$add_new_user_form->handle = function(&$vdata) use ($group) {
|
||||||
DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')");
|
DB::insert("insert into groups_users (group_id, username) values ({$group['id']}, '{$vdata['username']}')");
|
||||||
@ -277,7 +277,7 @@ EOD);
|
|||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader('管理 - ' . $group['title']); ?>
|
<?php echoUOJPageHeader('管理 - ' . $group['title']); ?>
|
||||||
|
|
||||||
<h1 class="h2 d-block d-md-inline-block">
|
<h1 class="d-block d-md-inline-block">
|
||||||
<?= $group['title'] ?>
|
<?= $group['title'] ?>
|
||||||
<small class="fs-5">(ID: #<?= $group['id'] ?>)</small>
|
<small class="fs-5">(ID: #<?= $group['id'] ?>)</small>
|
||||||
管理
|
管理
|
||||||
|
@ -4,16 +4,12 @@
|
|||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
if (isSuperUser($myUser)) {
|
||||||
$new_group_form = new UOJForm('new_group');
|
$new_group_form = new UOJBs4Form('new_group');
|
||||||
$new_group_form->handle = function () {
|
$new_group_form->handle = function () {
|
||||||
DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)");
|
DB::query("insert into `groups` (title, is_hidden) values ('新小组', 1)");
|
||||||
};
|
};
|
||||||
@ -28,14 +24,11 @@
|
|||||||
<?php echoUOJPageHeader(UOJLocale::get('groups')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('groups')) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
|
||||||
<!-- title container -->
|
<!-- title container -->
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
|
<h1>
|
||||||
<h1 class="h2">
|
|
||||||
<?= UOJLocale::get('groups') ?>
|
<?= UOJLocale::get('groups') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -59,31 +52,39 @@
|
|||||||
</tr>
|
</tr>
|
||||||
EOD;
|
EOD;
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
if (isSuperUser(Auth::user())) {
|
||||||
$cond = "1";
|
$cond = "1";
|
||||||
} else {
|
} else {
|
||||||
$cond = 'is_hidden = 0';
|
$cond = ["is_hidden" => false];
|
||||||
}
|
}
|
||||||
|
|
||||||
echoLongTable(
|
echoLongTable(
|
||||||
['a.id as group_id', 'a.title as title', 'a.is_hidden as is_hidden', 'count(b.username) as user_count'],
|
['id', 'title', 'is_hidden'],
|
||||||
"`groups` a left join groups_users b on a.id = b.group_id",
|
"`groups`",
|
||||||
$cond,
|
$cond,
|
||||||
'group by a.id order by a.id asc',
|
'order by id asc',
|
||||||
$header,
|
$header,
|
||||||
function ($group) use ($myUser) {
|
function ($group) {
|
||||||
|
$users_count = DB::selectCount([
|
||||||
|
"select count(*)",
|
||||||
|
"from", "groups_users",
|
||||||
|
"where", [
|
||||||
|
"group_id" => $group['id'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
echo '<tr class="text-center">';
|
echo '<tr class="text-center">';
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
echo '#', $group['group_id'], '</td>';
|
echo '#', $group['id'], '</td>';
|
||||||
|
|
||||||
echo '<td class="text-start">';
|
echo '<td class="text-start">';
|
||||||
echo '<a class="text-decoration-none" href="/group/', $group['group_id'], '">', $group['title'], '</a>';
|
echo '<a class="text-decoration-none" href="/group/', $group['id'], '">', $group['title'], '</a>';
|
||||||
if ($group['is_hidden']) {
|
if ($group['is_hidden']) {
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
||||||
}
|
}
|
||||||
echo '</td>';
|
echo '</td>';
|
||||||
|
|
||||||
echo "<td>{$group['user_count']}</td>";
|
echo "<td>{$users_count}</td>";
|
||||||
|
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
},
|
},
|
||||||
@ -92,19 +93,17 @@ EOD;
|
|||||||
'div_classes' => ['card', 'my-3'],
|
'div_classes' => ['card', 'my-3'],
|
||||||
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
||||||
'head_pagination' => true,
|
'head_pagination' => true,
|
||||||
'pagination_table' => "`groups`",
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<?php uojIncludeView('sidebar', array()); ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
|
<!-- end right col -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,101 +1,117 @@
|
|||||||
<?php
|
<?php
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
requirePHPLib('judger');
|
||||||
|
requirePHPLib('data');
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requireLib('hljs');
|
requireLib('hljs');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJHack::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
|
UOJHack::cur()->setProblem() || UOJResponse::page404();
|
||||||
|
UOJHack::cur()->userCanView(Auth::user(), ['ensure' => true]);
|
||||||
|
|
||||||
|
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 (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
if (UOJHack::cur()->userCanDelete(Auth::user())) {
|
||||||
become403Page();
|
$delete_form = new UOJBs4Form('delete');
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($hack = queryHack($_GET['id']))) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$submission = querySubmission($hack['submission_id']);
|
|
||||||
$problem = queryProblemBrief($submission['problem_id']);
|
|
||||||
$problem_extra_config = getProblemExtraConfig($problem);
|
|
||||||
|
|
||||||
if ($submission['contest_id']) {
|
|
||||||
$contest = queryContest($submission['contest_id']);
|
|
||||||
genMoreContestInfo($contest);
|
|
||||||
} else {
|
|
||||||
$contest = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isHackVisibleToUser($hack, $problem, $myUser)) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
|
||||||
$delete_form = new UOJForm('delete');
|
|
||||||
$delete_form->handle = function () {
|
$delete_form->handle = function () {
|
||||||
global $hack;
|
DB::delete([
|
||||||
DB::query("delete from hacks where id = {$hack['id']}");
|
"delete from hacks",
|
||||||
|
"where", ["id" => UOJHack::info('id')]
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$delete_form->submit_button_config['class_str'] = 'btn btn-danger';
|
$delete_form->submit_button_config['class_str'] = 'btn btn-danger';
|
||||||
$delete_form->submit_button_config['text'] = '删除此 Hack';
|
$delete_form->submit_button_config['text'] = '删除此 Hack';
|
||||||
$delete_form->submit_button_config['align'] = 'right';
|
$delete_form->submit_button_config['align'] = 'end';
|
||||||
$delete_form->submit_button_config['smart_confirm'] = '';
|
$delete_form->submit_button_config['smart_confirm'] = '';
|
||||||
$delete_form->succ_href = "/hacks";
|
$delete_form->succ_href = "/hacks";
|
||||||
$delete_form->runAtServer();
|
$delete_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
$should_show_content = hasViewPermission($problem_extra_config['view_content_type'], $myUser, $problem, $submission);
|
if (UOJHack::cur()->userCanReview(Auth::user())) {
|
||||||
$should_show_all_details = hasViewPermission($problem_extra_config['view_all_details_type'], $myUser, $problem, $submission);
|
$addex_form = new UOJBs4Form('addex');
|
||||||
$should_show_details = hasViewPermission($problem_extra_config['view_details_type'], $myUser, $problem, $submission);
|
$addex_form->handle = function () {
|
||||||
$should_show_details_to_me = isSuperUser($myUser);
|
$input = UOJContext::storagePath() . UOJHack::info('input');
|
||||||
if ($hack['success'] === null) {
|
$new_in = "{$input}_in";
|
||||||
$should_show_all_details = false;
|
$new_out = "{$input}_out";
|
||||||
}
|
$reason = null;
|
||||||
if (!isSubmissionFullVisibleToUser($submission, $contest, $problem, $myUser)
|
$err = dataAddHackPoint(UOJHack::cur()->problem->info, $new_in, $new_out, $reason, Auth::user());
|
||||||
|| !isHackFullVisibleToUser($hack, $contest, $problem, $myUser)) {
|
$err === '' || UOJResponse::message($err);
|
||||||
$should_show_content = $should_show_all_details = false;
|
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 ($should_show_all_details) {
|
$perm = UOJHack::cur()->viewerCanSeeComponents(Auth::user());
|
||||||
|
?>
|
||||||
|
<?php echoUOJPageHeader(UOJLocale::get('problems::hack') . ' #' . UOJHack::info('id')) ?>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
<?= UOJLocale::get('problems::hack') . ' #' . UOJHack::info('id') ?>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<?php echoHackListOnlyOne(UOJHack::info(), [], Auth::user()) ?>
|
||||||
|
|
||||||
|
<?php if (UOJHack::cur()->hasJudged()) : ?>
|
||||||
|
<?php if ($perm['high_level_details']) : ?>
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header fw-bold">
|
||||||
|
<?= UOJLocale::get('details') ?>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<?php
|
||||||
$styler = new HackDetailsStyler();
|
$styler = new HackDetailsStyler();
|
||||||
if (!$should_show_details) {
|
if (!$perm['low_level_details']) {
|
||||||
$styler->fade_all_details = true;
|
$styler->fade_all_details = true;
|
||||||
$styler->show_small_tip = false;
|
$styler->show_small_tip = false;
|
||||||
}
|
}
|
||||||
}
|
echoJudgmentDetails(UOJHack::info('details'), $styler, 'details');
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('problems::hack').' #'.$hack['id']) ?>
|
<?php if ($perm['manager_view'] && !$perm['low_level_details']) : ?>
|
||||||
|
|
||||||
<h1 class="h3">
|
|
||||||
<?= UOJLocale::get('problems::hack').' #'.$hack['id'] ?>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<?php echoHackListOnlyOne($hack, array('id_hidden' => ''), $myUser) ?>
|
|
||||||
<?php if ($should_show_all_details): ?>
|
|
||||||
<div class="card border-info mb-3">
|
|
||||||
<div class="card-header bg-info">
|
|
||||||
<h4 class="card-title"><?= UOJLocale::get('details') ?></h4>
|
|
||||||
</div>
|
|
||||||
<?php echoJudgementDetails($hack['details'], $styler, 'details') ?>
|
|
||||||
<?php if ($should_show_details_to_me): ?>
|
|
||||||
<?php if ($styler->fade_all_details): ?>
|
|
||||||
<hr />
|
<hr />
|
||||||
<?php echoHackDetails($hack['details'], 'final_details') ?>
|
<h4 class="text-info">全部详细信息(仅管理员可见)</h4>
|
||||||
<?php endif ?>
|
<?php echoHackDetails(UOJHack::info('details'), 'all_details') ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<h2 class="h3">
|
<h2 class="mt-3">
|
||||||
<?= UOJLocale::get('problems::submission').' #'.$submission['id'] ?>
|
<?= UOJLocale::get('problems::submission') . ' #' . UOJSubmission::info('id') ?>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<?php echoSubmissionsListOnlyOne($submission, array(), $myUser) ?>
|
<?php if (UOJSubmission::cur()) : ?>
|
||||||
<?php if ($should_show_content): ?>
|
<?php UOJSubmission::cur()->echoStatusTable(['show_actual_score' => $perm['score']], Auth::user()) ?>
|
||||||
<?php echoSubmissionContent($submission, getProblemSubmissionRequirement($problem)) ?>
|
<?php if ($perm['content'] || $perm['manager_view']) : ?>
|
||||||
|
<?php UOJSubmission::cur()->echoContent() ?>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<h3 class="text-danger">提交记录信息损坏</h3>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php if (isset($delete_form)) : ?>
|
<?php if (isset($delete_form)) : ?>
|
||||||
<?php $delete_form->printHTML() ?>
|
<?php $delete_form->printHTML() ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php if (isset($addex_form)) : ?>
|
||||||
|
<?php $addex_form->printHTML() ?>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,31 +1,25 @@
|
|||||||
<?php
|
<?php
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$conds = array();
|
|
||||||
|
|
||||||
$q_problem_id = isset($_GET['problem_id']) && validateUInt($_GET['problem_id']) ? $_GET['problem_id'] : null;
|
$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_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_hacker = isset($_GET['hacker']) && validateUsername($_GET['hacker']) ? $_GET['hacker'] : null;
|
||||||
$q_owner = isset($_GET['owner']) && validateUsername($_GET['owner']) ? $_GET['owner'] : null;
|
$q_owner = isset($_GET['owner']) && validateUsername($_GET['owner']) ? $_GET['owner'] : null;
|
||||||
|
|
||||||
|
$conds = [];
|
||||||
if ($q_problem_id != null) {
|
if ($q_problem_id != null) {
|
||||||
$conds[] = "problem_id = $q_problem_id";
|
$conds[] = ["problem_id" => $q_problem_id];
|
||||||
}
|
}
|
||||||
if ($q_submission_id != null) {
|
if ($q_submission_id != null) {
|
||||||
$conds[] = "submission_id = $q_submission_id";
|
$conds[] = ["submission_id" => $q_submission_id];
|
||||||
}
|
}
|
||||||
if ($q_hacker != null) {
|
if ($q_hacker != null) {
|
||||||
$conds[] = "hacker = '$q_hacker'";
|
$conds[] = ["hacker" => $q_hacker];
|
||||||
}
|
}
|
||||||
if ($q_owner != null) {
|
if ($q_owner != null) {
|
||||||
$conds[] = "owner = '$q_owner'";
|
$conds[] = ["owner" => $q_owner];
|
||||||
}
|
}
|
||||||
|
|
||||||
$selected_all = ' selected="selected"';
|
$selected_all = ' selected="selected"';
|
||||||
@ -45,7 +39,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($conds) {
|
if ($conds) {
|
||||||
$cond = join($conds, ' and ');
|
$cond = $conds;
|
||||||
} else {
|
} else {
|
||||||
$cond = '1';
|
$cond = '1';
|
||||||
}
|
}
|
||||||
@ -53,7 +47,7 @@
|
|||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('hacks')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('hacks')) ?>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('hacks') ?>
|
<?= UOJLocale::get('hacks') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -129,7 +123,9 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoHacksList($cond,
|
<?php
|
||||||
|
echoHacksList(
|
||||||
|
$cond,
|
||||||
'order by id desc',
|
'order by id desc',
|
||||||
[
|
[
|
||||||
'judge_time_hidden' => '',
|
'judge_time_hidden' => '',
|
||||||
@ -138,7 +134,8 @@
|
|||||||
'table_classes' => ['table', 'mb-0', 'uoj-table', 'text-center'],
|
'table_classes' => ['table', 'mb-0', 'uoj-table', 'text-center'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
$myUser);
|
Auth::user()
|
||||||
|
);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
<?php
|
<?php requireLib('bootstrap5') ?>
|
||||||
requireLib('bootstrap5');
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('html to markdown')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('html to markdown')) ?>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('html to markdown') ?>
|
<?= UOJLocale::get('html to markdown') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#html, #markdown {
|
#html,
|
||||||
|
#markdown {
|
||||||
font-family: Cascadia Mono, Ubuntu Mono, Roboto Mono, Jetbrains Mono, Fira Code, Consolas, '思源黑体 Regular', '思源宋体 Light', '宋体', 'Courier New', monospace;
|
font-family: Cascadia Mono, Ubuntu Mono, Roboto Mono, Jetbrains Mono, Fira Code, Consolas, '思源黑体 Regular', '思源宋体 Light', '宋体', 'Courier New', monospace;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
@ -37,7 +36,9 @@
|
|||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#html').on('input', function() {
|
$('#html').on('input', function() {
|
||||||
$('#markdown').val(h2m($('#html').val(), { converter: 'Gfm' }));
|
$('#markdown').val(h2m($('#html').val(), {
|
||||||
|
converter: 'Gfm'
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
requirePHPLib('form');
|
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
become403Page(UOJLocale::get('need login'));
|
become403Page(UOJLocale::get('need login'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,28 +1,34 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Gregwar\Captcha\PhraseBuilder;
|
use Gregwar\Captcha\PhraseBuilder;
|
||||||
use Gregwar\Captcha\CaptchaBuilder;
|
|
||||||
|
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
|
|
||||||
if (!Auth::check()) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser)) {
|
$extra = UOJUser::getExtra($user);
|
||||||
become403Page();
|
$limit = $extra['image_hosting']['total_size_limit'];
|
||||||
}
|
$used = DB::selectSingle([
|
||||||
|
"select sum(size)",
|
||||||
$limit = $myUser['images_size_limit'];
|
"from users_images",
|
||||||
$_result = DB::selectFirst("SELECT SUM(size), count(*) FROM `users_images` WHERE uploader = '{$myUser['username']}'");
|
"where", [
|
||||||
$used = $_result["SUM(size)"];
|
"uploader" => Auth::id(),
|
||||||
$count = $_result["count(*)"];
|
],
|
||||||
|
]);
|
||||||
|
$count = DB::selectCount([
|
||||||
|
"select count(*)",
|
||||||
|
"from users_images",
|
||||||
|
"where", [
|
||||||
|
"uploader" => Auth::id(),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
function throwError($msg) {
|
function throwError($msg) {
|
||||||
dieWithJsonData(['status' => 'error', 'message' => $msg]);
|
dieWithJsonData(['status' => 'error', 'message' => $msg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG];
|
$allowedTypes = [IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_WEBP];
|
||||||
if ($_POST['image_upload_file_submit'] == 'submit') {
|
if ($_POST['image_upload_file_submit'] == 'submit') {
|
||||||
if (!crsf_check()) {
|
if (!crsf_check()) {
|
||||||
throwError('expired');
|
throwError('expired');
|
||||||
@ -140,7 +146,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('image hosting') ?>
|
<?= UOJLocale::get('image hosting') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -185,7 +191,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 col-lg-2 order-2 mt-3 mt-md-0 ms-md-2">
|
<div class="col-12 col-md-4 col-lg-2 order-2 mt-3 mt-md-0 ms-md-2">
|
||||||
<h2 class="h4">水印</h2>
|
<h2 class="h3">水印</h2>
|
||||||
<?php if (isSuperUser($myUser)) : ?>
|
<?php if (isSuperUser($myUser)) : ?>
|
||||||
<div class="form-check d-inline-block d-md-block me-2">
|
<div class="form-check d-inline-block d-md-block me-2">
|
||||||
<input class="form-check-input" type="radio" name="watermark" id="watermark-no_watermark" data-value="no_watermark">
|
<input class="form-check-input" type="radio" name="watermark" id="watermark-no_watermark" data-value="no_watermark">
|
||||||
@ -208,7 +214,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col order-3 order-md-4 order-lg-3 mt-3 mt-lg-0 ms-lg-2">
|
<div class="col order-3 order-md-4 order-lg-3 mt-3 mt-lg-0 ms-lg-2">
|
||||||
<h2 class="h4">上传须知</h2>
|
<h2 class="h3">上传须知</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>上传的图片必须符合法律与社会道德;</li>
|
<li>上传的图片必须符合法律与社会道德;</li>
|
||||||
<li>图床仅供 S2OJ 站内使用,校外用户无法查看;</li>
|
<li>图床仅供 S2OJ 站内使用,校外用户无法查看;</li>
|
||||||
@ -218,7 +224,7 @@
|
|||||||
<p class="small">更多信息可以查看 <a href="https://s2oj.github.io/#/user/apps/image_hosting" target="_blank">使用文档</a>。</p>
|
<p class="small">更多信息可以查看 <a href="https://s2oj.github.io/#/user/apps/image_hosting" target="_blank">使用文档</a>。</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-5 col-lg-3 order-4 order-md-3 order-lg-4 mt-3 mt-md-0 ms-md-2">
|
<div class="col-12 col-md-5 col-lg-3 order-4 order-md-3 order-lg-4 mt-3 mt-md-0 ms-md-2">
|
||||||
<h2 class="h4">使用统计</h2>
|
<h2 class="h3">使用统计</h2>
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<span class="small">已用空间</span>
|
<span class="small">已用空间</span>
|
||||||
<span><?= round($used * 1.0 / 1024 / 1024, 2) ?> MB / <?= round($limit * 1.0 / 1024 / 1024, 2) ?> MB</span>
|
<span><?= round($used * 1.0 / 1024 / 1024, 2) ?> MB / <?= round($limit * 1.0 / 1024 / 1024, 2) ?> MB</span>
|
||||||
@ -243,7 +249,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var image_upload_modal = new bootstrap.Modal('#image-upload-modal');
|
var image_upload_modal = new bootstrap.Modal('#image-upload-modal');
|
||||||
var image_upload_toast = new bootstrap.Toast('#image-upload-toast', { delay: 2000 });
|
var image_upload_toast = new bootstrap.Toast('#image-upload-toast', {
|
||||||
|
delay: 2000
|
||||||
|
});
|
||||||
var droppedFiles = false;
|
var droppedFiles = false;
|
||||||
|
|
||||||
function refreshCaptcha() {
|
function refreshCaptcha() {
|
||||||
@ -379,7 +387,7 @@ $pag_config = [
|
|||||||
$pag = new Paginator($pag_config);
|
$pag = new Paginator($pag_config);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<h2 class="h3 mt-4 mb-3">
|
<h2 class="mt-4 mb-3">
|
||||||
我的图片
|
我的图片
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
@ -449,7 +457,9 @@ $(document).ready(function() {
|
|||||||
[...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
[...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
|
||||||
});
|
});
|
||||||
|
|
||||||
var copy_url_toast = new bootstrap.Toast('#copy-url-toast', { delay: 2000 });
|
var copy_url_toast = new bootstrap.Toast('#copy-url-toast', {
|
||||||
|
delay: 2000
|
||||||
|
});
|
||||||
|
|
||||||
$('.image-copy-url-button').click(function() {
|
$('.image-copy-url-button').click(function() {
|
||||||
var url = new URL($(this).data('image-path'), location.origin);
|
var url = new URL($(this).data('image-path'), location.origin);
|
||||||
|
@ -1,9 +1,20 @@
|
|||||||
|
<?php requireLib('bootstrap5'); ?>
|
||||||
<?php
|
<?php
|
||||||
$blogs = DB::selectAll("select blogs.id, title, poster, post_time from important_blogs, blogs where is_hidden = 0 and important_blogs.blog_id = blogs.id order by level desc, important_blogs.blog_id desc limit 5");
|
$blogs = DB::selectAll([
|
||||||
$countdowns = DB::selectAll("select * from countdowns order by end_time asc");
|
"select blogs.id, title, poster, post_time from important_blogs inner join blogs on important_blogs.blog_id = blogs.id",
|
||||||
$friend_links = DB::selectAll("select * from friend_links order by level desc, id asc");
|
"where", [
|
||||||
|
"is_hidden" => 0,
|
||||||
requireLib('bootstrap5');
|
], "order by level desc, important_blogs.blog_id desc",
|
||||||
|
DB::limit(5)
|
||||||
|
]);
|
||||||
|
$countdowns = DB::selectAll([
|
||||||
|
"select title, end_time from countdowns",
|
||||||
|
"order by end_time asc",
|
||||||
|
]);
|
||||||
|
$friend_links = DB::selectAll([
|
||||||
|
"select title, url from friend_links",
|
||||||
|
"order by level desc, id asc",
|
||||||
|
]);
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJConfig::$data['profile']['oj-name-short']) ?>
|
<?php echoUOJPageHeader(UOJConfig::$data['profile']['oj-name-short']) ?>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -23,25 +34,21 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php $now_cnt = 0; ?>
|
<?php $now_cnt = 0; ?>
|
||||||
<?php foreach ($blogs as $blog): ?>
|
<?php foreach ($blogs as $blog_info) : ?>
|
||||||
<?php
|
<?php
|
||||||
|
$blog = new UOJBlog($blog_info);
|
||||||
$now_cnt++;
|
$now_cnt++;
|
||||||
$new_tag = '';
|
|
||||||
if ((time() - strtotime($blog['post_time'])) / 3600 / 24 <= 7) {
|
|
||||||
$new_tag = '<sup style="color:red"> new</sup>';
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td><?= $blog->getLink(['show_new_tag' => true]) ?></td>
|
||||||
<a href="/blogs/<?= $blog['id'] ?>" class="text-decoration-none"><?= $blog['title'] ?></a>
|
<td>by <?= getUserLink($blog->info['poster']) ?></td>
|
||||||
<?= $new_tag ?>
|
<td><small><?= $blog->info['post_time'] ?></small></td>
|
||||||
</td>
|
|
||||||
<td>by <?= getUserLink($blog['poster']) ?></td>
|
|
||||||
<td><small><?= $blog['post_time'] ?></small></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<?php for ($i = $now_cnt + 1; $i <= 5; $i++) : ?>
|
<?php for ($i = $now_cnt + 1; $i <= 5; $i++) : ?>
|
||||||
<tr><td colspan="233"> </td></tr>
|
<tr>
|
||||||
|
<td colspan="233"> </td>
|
||||||
|
</tr>
|
||||||
<?php endfor ?>
|
<?php endfor ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -52,26 +59,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php if (!UOJConfig::$data['switch']['force-login'] || Auth::check()): ?>
|
<?php if (Auth::check()) : ?>
|
||||||
<?php if (!UOJConfig::$data['switch']['force-login'] || isNormalUser($myUser)): ?>
|
|
||||||
|
|
||||||
<div class="mt-4 card">
|
<div class="mt-4 card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h4 class="card-title"><?= UOJLocale::get('top solver') ?></h4>
|
<h4 class="card-title mb-2"><?= UOJLocale::get('top solver') ?></h4>
|
||||||
<?php echoRanklist([
|
<?php UOJRanklist::printHTML(['top10' => true]) ?>
|
||||||
'echo_full' => true,
|
<div class="text-center mt-2">
|
||||||
'top10' => true,
|
|
||||||
'by_accepted' => true,
|
|
||||||
'table_classes' => ['table', 'text-center'],
|
|
||||||
]) ?>
|
|
||||||
<div class="text-center">
|
|
||||||
<a href="/solverlist" class="text-decoration-none">
|
<a href="/solverlist" class="text-decoration-none">
|
||||||
<?= UOJLocale::get('view all') ?>
|
<?= UOJLocale::get('view all') ?>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<div class="mt-4 card card-default">
|
<div class="mt-4 card card-default">
|
||||||
<div class="card-body text-center">
|
<div class="card-body text-center">
|
||||||
@ -94,7 +93,7 @@
|
|||||||
<?php
|
<?php
|
||||||
$enddate = strtotime($countdown['end_time']);
|
$enddate = strtotime($countdown['end_time']);
|
||||||
$nowdate = time();
|
$nowdate = time();
|
||||||
$diff = floor(($enddate - $nowdate) / (24 * 60 * 60));
|
$diff = ceil(($enddate - $nowdate) / (24 * 60 * 60));
|
||||||
?>
|
?>
|
||||||
<li>
|
<li>
|
||||||
<?php if ($diff > 0) : ?>
|
<?php if ($diff > 0) : ?>
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
requirePHPLib('judger');
|
|
||||||
|
|
||||||
if (!authenticateJudger()) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($_GET['type']) {
|
|
||||||
case 'submission':
|
|
||||||
$file_name = UOJContext::storagePath()."/submission/{$_GET['id']}/{$_GET['rand_str_id']}";
|
|
||||||
$download_name = "submission.zip";
|
|
||||||
break;
|
|
||||||
case 'tmp':
|
|
||||||
$file_name = UOJContext::storagePath()."/tmp/{$_GET['rand_str_id']}";
|
|
||||||
$download_name = "tmp";
|
|
||||||
break;
|
|
||||||
case 'problem':
|
|
||||||
$id = $_GET['id'];
|
|
||||||
if (!validateUInt($id) || !($problem = queryProblemBrief($id))) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
$file_name = "/var/uoj_data/$id.zip";
|
|
||||||
$download_name = "$id.zip";
|
|
||||||
break;
|
|
||||||
case 'judger':
|
|
||||||
$file_name = UOJContext::storagePath()."/judge_client.zip";
|
|
||||||
$download_name = "judge_client.zip";
|
|
||||||
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");
|
|
||||||
?>
|
|
@ -3,92 +3,97 @@
|
|||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (!authenticateJudger()) {
|
if (!authenticateJudger()) {
|
||||||
become404Page();
|
UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
|
||||||
function submissionJudged() {
|
function submissionJudged() {
|
||||||
$submission = DB::selectFirst("select submitter, status, content, result, problem_id from submissions where id = {$_POST['id']}");
|
UOJSubmission::onJudged(UOJRequest::post('id'), UOJRequest::post('result'), UOJRequest::post('judge_time'));
|
||||||
if ($submission == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ($submission['status'] != 'Judging' && $submission['status'] != 'Judged, Judging') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$content = json_decode($submission['content'], true);
|
|
||||||
|
|
||||||
if (isset($content['first_test_config'])) {
|
|
||||||
$result = json_decode($submission['result'], true);
|
|
||||||
$result['final_result'] = json_decode($_POST['result'], true);
|
|
||||||
$result['final_result']['details'] = uojTextEncode($result['final_result']['details']);
|
|
||||||
$esc_result = DB::escape(json_encode($result, JSON_UNESCAPED_UNICODE));
|
|
||||||
|
|
||||||
$content['final_test_config'] = $content['config'];
|
|
||||||
$content['config'] = $content['first_test_config'];
|
|
||||||
unset($content['first_test_config']);
|
|
||||||
$esc_content = DB::escape(json_encode($content));
|
|
||||||
|
|
||||||
DB::update("update submissions set status = 'Judged', result = '$esc_result', content = '$esc_content' where id = {$_POST['id']}");
|
|
||||||
} else {
|
|
||||||
$result = json_decode($_POST['result'], true);
|
|
||||||
$result['details'] = uojTextEncode($result['details']);
|
|
||||||
$esc_result = DB::escape(json_encode($result, JSON_UNESCAPED_UNICODE));
|
|
||||||
if (isset($result["error"])) {
|
|
||||||
DB::update("update submissions set status = '{$result['status']}', result_error = '{$result['error']}', result = '$esc_result', score = null, used_time = null, used_memory = null where id = {$_POST['id']}");
|
|
||||||
} else {
|
|
||||||
DB::update("update submissions set status = '{$result['status']}', result_error = null, result = '$esc_result', score = {$result['score']}, used_time = {$result['time']}, used_memory = {$result['memory']} where id = {$_POST['id']}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($content['final_test_config'])) {
|
|
||||||
$content['first_test_config'] = $content['config'];
|
|
||||||
$content['config'] = $content['final_test_config'];
|
|
||||||
unset($content['final_test_config']);
|
|
||||||
$esc_content = DB::escape(json_encode($content));
|
|
||||||
|
|
||||||
DB::update("update submissions set status = 'Judged, Waiting', content = '$esc_content' where id = ${_POST['id']}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DB::update("update submissions set status_details = '' where id = {$_POST['id']}");
|
|
||||||
updateBestACSubmissions($submission['submitter'], $submission['problem_id']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function customTestSubmissionJudged() {
|
function customTestSubmissionJudged() {
|
||||||
$submission = DB::selectFirst("select submitter, status, content, result, problem_id from custom_test_submissions where id = {$_POST['id']}");
|
$submission = DB::selectFirst([
|
||||||
|
"select submitter, status, content, result, problem_id from custom_test_submissions",
|
||||||
|
"where", ['id' => $_POST['id']]
|
||||||
|
]);
|
||||||
if ($submission == null) {
|
if ($submission == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($submission['status'] != 'Judging') {
|
if ($submission['status'] != 'Judging') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$content = json_decode($submission['content'], true);
|
|
||||||
$result = json_decode($_POST['result'], true);
|
$result = json_decode($_POST['result'], true);
|
||||||
$result['details'] = uojTextEncode($result['details']);
|
$result['details'] = uojTextEncode($result['details']);
|
||||||
$esc_result = DB::escape(json_encode($result, JSON_UNESCAPED_UNICODE));
|
DB::update([
|
||||||
if (isset($result["error"])) {
|
"update custom_test_submissions",
|
||||||
DB::update("update custom_test_submissions set status = '{$result['status']}', result = '$esc_result' where id = {$_POST['id']}");
|
"set", [
|
||||||
} else {
|
'status' => $result['status'],
|
||||||
DB::update("update custom_test_submissions set status = '{$result['status']}', result = '$esc_result' where id = {$_POST['id']}");
|
'status_details' => '',
|
||||||
}
|
'result' => json_encode($result, JSON_UNESCAPED_UNICODE)
|
||||||
DB::update("update custom_test_submissions set status_details = '' where id = {$_POST['id']}");
|
], "where", ['id' => $_POST['id']]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hackJudged() {
|
function hackJudged() {
|
||||||
$result = json_decode($_POST['result'], true);
|
$result = json_decode($_POST['result'], true);
|
||||||
$esc_details = DB::escape(uojTextEncode($result['details']));
|
|
||||||
$ok = DB::update("update hacks set success = {$result['score']}, details = '$esc_details' where id = {$_POST['id']}");
|
|
||||||
|
|
||||||
if ($ok) {
|
UOJHack::init($_POST['id']);
|
||||||
list($hack_input) = DB::fetch(DB::query("select input from hacks where id = {$_POST['id']}"), MYSQLI_NUM);
|
UOJHack::cur()->setProblem();
|
||||||
unlink(UOJContext::storagePath().$hack_input);
|
UOJHack::cur()->setSubmission();
|
||||||
|
|
||||||
if ($result['score']) {
|
if ($result['score']) {
|
||||||
list($problem_id) = DB::selectFirst("select problem_id from hacks where id = ${_POST['id']}", MYSQLI_NUM);
|
$status = 'Judged, Waiting';
|
||||||
if (validateUploadedFile('hack_input') && validateUploadedFile('std_output')) {
|
|
||||||
dataAddExtraTest(queryProblemBrief($problem_id), $_FILES["hack_input"]["tmp_name"], $_FILES["std_output"]["tmp_name"]);
|
|
||||||
} else {
|
} else {
|
||||||
error_log("hack successfully but received no data. id: ${_POST['id']}");
|
$status = 'Judged';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$ok = DB::update([
|
||||||
|
"update hacks",
|
||||||
|
"set", [
|
||||||
|
'success' => $result['score'],
|
||||||
|
'status' => $status,
|
||||||
|
'details' => uojTextEncode($result['details'])
|
||||||
|
], "where", ['id' => $_POST['id']]
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$result['score']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!$ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(validateUploadedFile('hack_input') && validateUploadedFile('std_output'))) {
|
||||||
|
UOJLog::error("hack successfully but received no data. id: {$_POST['id']}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$input = UOJContext::storagePath() . UOJHack::info('input');
|
||||||
|
$up_in = $_FILES["hack_input"]['tmp_name'];
|
||||||
|
$up_out = $_FILES["std_output"]['tmp_name'];
|
||||||
|
|
||||||
|
if (!UOJHack::cur()->problem->needToReviewHack()) {
|
||||||
|
$err = dataAddHackPoint(UOJHack::cur()->problem->info, $up_in, $up_out);
|
||||||
|
if ($err === '') {
|
||||||
|
unlink($input);
|
||||||
|
DB::update([
|
||||||
|
"update hacks",
|
||||||
|
"set", [
|
||||||
|
'status' => 'Judged'
|
||||||
|
], "where", ['id' => $_POST['id']]
|
||||||
|
]);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
UOJLog::error("hack successfully but failed to add an extra test: {$err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
move_uploaded_file($up_in, "{$input}_in");
|
||||||
|
move_uploaded_file($up_out, "{$input}_out");
|
||||||
|
DB::update([
|
||||||
|
"update hacks",
|
||||||
|
"set", [
|
||||||
|
'status' => 'Judged, WaitingM'
|
||||||
|
], "where", ['id' => $_POST['id']]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_POST['submit'])) {
|
if (isset($_POST['submit'])) {
|
||||||
@ -107,79 +112,261 @@
|
|||||||
if (!validateUInt($_POST['id'])) {
|
if (!validateUInt($_POST['id'])) {
|
||||||
die("Wow! hacker! T_T....");
|
die("Wow! hacker! T_T....");
|
||||||
}
|
}
|
||||||
$esc_status_details = DB::escape($_POST['status']);
|
|
||||||
|
$status_details = $_POST['status'];
|
||||||
if (isset($_POST['is_custom_test'])) {
|
if (isset($_POST['is_custom_test'])) {
|
||||||
DB::update("update custom_test_submissions set status_details = '$esc_status_details' where id = {$_POST['id']}");
|
DB::update([
|
||||||
|
"update custom_test_submissions",
|
||||||
|
"set", ["status_details" => $status_details],
|
||||||
|
"where", ["id" => $_POST['id']]
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
DB::update("update submissions set status_details = '$esc_status_details' where id = {$_POST['id']}");
|
DB::update([
|
||||||
|
"update submissions",
|
||||||
|
"set", ["status_details" => $status_details],
|
||||||
|
"where", ["id" => $_POST['id']]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$problem_ban_list = DB::selectAll([
|
||||||
|
"select id from problems",
|
||||||
|
"where", [
|
||||||
|
["assigned_to_judger", "!=", "any"],
|
||||||
|
["assigned_to_judger", "!=", $_POST['judger_name']]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
foreach ($problem_ban_list as &$val) {
|
||||||
|
$val = $val['id'];
|
||||||
|
}
|
||||||
|
$assignCond = $problem_ban_list ? [["problem_id", "not in", DB::rawtuple($problem_ban_list)]] : [];
|
||||||
|
|
||||||
$submission = null;
|
$submission = null;
|
||||||
$hack = null;
|
$hack = null;
|
||||||
function querySubmissionToJudge($status, $set_q) {
|
function querySubmissionToJudge($status, $set_q) {
|
||||||
global $submission;
|
global $assignCond;
|
||||||
$submission = DB::selectFirst("select id, problem_id, content from submissions where status = '$status' order by id limit 1");
|
|
||||||
if ($submission) {
|
for ($times = 0; $times < 10; $times++) {
|
||||||
DB::update("update submissions set $set_q where id = {$submission['id']} and status = '$status'");
|
$submission = DB::selectFirst([
|
||||||
if (DB::affected_rows() != 1) {
|
"select id from submissions",
|
||||||
|
"where", array_merge(["status" => $status], $assignCond),
|
||||||
|
"order by id limit 1"
|
||||||
|
]);
|
||||||
|
if (!$submission) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ok = DB::transaction(function () use (&$submission, $set_q, $status) {
|
||||||
|
DB::update([
|
||||||
|
"update submissions",
|
||||||
|
"set", $set_q,
|
||||||
|
"where", [
|
||||||
|
"id" => $submission['id'],
|
||||||
|
"status" => $status
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if (DB::affected_rows() == 1) {
|
||||||
|
$submission = DB::selectFirst([
|
||||||
|
"select id, problem_id, content, status, judge_time from submissions",
|
||||||
|
"where", ["id" => $submission['id']]
|
||||||
|
]);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ($ok) {
|
||||||
|
return $submission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function queryMinorSubmissionToJudge($status, $set_q) {
|
||||||
|
global $assignCond;
|
||||||
|
|
||||||
|
for ($times = 0; $times < 10; $times++) {
|
||||||
$submission = null;
|
$submission = null;
|
||||||
|
$his = DB::selectFirst([
|
||||||
|
"select id, submission_id from submissions_history",
|
||||||
|
"where", ["status" => $status, "major" => 0], // $assignCond is removed!!! fix this bug in the future!
|
||||||
|
"order by id limit 1"
|
||||||
|
]);
|
||||||
|
if (!$his) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ok = DB::transaction(function () use (&$submission, &$his, $set_q, $status) {
|
||||||
|
$submission = DB::selectFirst([
|
||||||
|
"select id, problem_id, content from submissions",
|
||||||
|
"where", ["id" => $his['submission_id']], DB::for_share()
|
||||||
|
]);
|
||||||
|
if (!$submission) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DB::update([
|
||||||
|
"update submissions_history",
|
||||||
|
"set", $set_q,
|
||||||
|
"where", [
|
||||||
|
"id" => $his['id'],
|
||||||
|
"status" => $status
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if (DB::affected_rows() == 1) {
|
||||||
|
$ret = DB::selectFirst([
|
||||||
|
"select status, judge_time from submissions_history",
|
||||||
|
"where", ["id" => $his['id']]
|
||||||
|
]);
|
||||||
|
if ($ret === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$submission += $ret;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ($ok) {
|
||||||
|
return $submission;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function queryCustomTestSubmissionToJudge() {
|
function queryCustomTestSubmissionToJudge() {
|
||||||
global $submission;
|
global $assignCond;
|
||||||
$submission = DB::selectFirst("select id, problem_id, content from custom_test_submissions where judge_time is null order by id limit 1");
|
|
||||||
if ($submission) {
|
while (true) {
|
||||||
DB::update("update custom_test_submissions set judge_time = now(), status = 'Judging' where id = {$submission['id']} and judge_time is null");
|
$submission = DB::selectFirst([
|
||||||
if (DB::affected_rows() != 1) {
|
"select id, problem_id, content from custom_test_submissions",
|
||||||
$submission = null;
|
"where", array_merge(["judge_time" => null], $assignCond),
|
||||||
|
"order by id limit 1"
|
||||||
|
]);
|
||||||
|
if (!$submission) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if ($submission) {
|
|
||||||
$submission['is_custom_test'] = '';
|
$submission['is_custom_test'] = '';
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update custom_test_submissions",
|
||||||
|
"set", [
|
||||||
|
"judge_time" => DB::now(),
|
||||||
|
"status" => 'Judging'
|
||||||
|
], "where", [
|
||||||
|
"id" => $submission['id'],
|
||||||
|
"judge_time" => null
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if (DB::affected_rows() == 1) {
|
||||||
|
$submission['status'] = 'Judging';
|
||||||
|
return $submission;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function queryHackToJudge() {
|
function queryHackToJudge() {
|
||||||
global $hack;
|
global $assignCond;
|
||||||
$hack = DB::selectFirst("select id, submission_id, input, input_type from hacks where judge_time is null order by id limit 1");
|
|
||||||
if ($hack) {
|
while (true) {
|
||||||
DB::update("update hacks set judge_time = now() where id = {$hack['id']} and judge_time is null");
|
if (DB::selectFirst([
|
||||||
if (DB::affected_rows() != 1) {
|
"select 1 from hacks",
|
||||||
$hack = null;
|
"where", [
|
||||||
|
["status", "!=", "Waiting"],
|
||||||
|
["status", "!=", "Judged"],
|
||||||
|
], "order by id limit 1"
|
||||||
|
])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hack = DB::selectFirst([
|
||||||
|
"select id, submission_id, input, input_type from hacks",
|
||||||
|
"where", array_merge(["judge_time" => null], $assignCond),
|
||||||
|
"order by id limit 1"
|
||||||
|
]);
|
||||||
|
if (!$hack) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update hacks",
|
||||||
|
"set", [
|
||||||
|
"judge_time" => DB::now(),
|
||||||
|
"status" => 'Judging'
|
||||||
|
],
|
||||||
|
"where", [
|
||||||
|
"id" => $hack['id'],
|
||||||
|
"judge_time" => null
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if (DB::affected_rows() == 1) {
|
||||||
|
$hack['status'] = 'Judging';
|
||||||
|
return $hack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function findSubmissionToJudge() {
|
function findSubmissionToJudge() {
|
||||||
global $submission, $hack;
|
global $submission, $hack;
|
||||||
querySubmissionToJudge('Waiting', "judge_time = now(), status = 'Judging'");
|
$submission = querySubmissionToJudge('Waiting', [
|
||||||
|
"judge_time" => DB::now(),
|
||||||
|
"judger" => $_POST['judger_name'],
|
||||||
|
"status" => 'Judging'
|
||||||
|
]);
|
||||||
if ($submission) {
|
if ($submission) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
queryCustomTestSubmissionToJudge();
|
$submission = queryCustomTestSubmissionToJudge();
|
||||||
if ($submission) {
|
if ($submission) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
querySubmissionToJudge('Waiting Rejudge', "judge_time = now(), status = 'Judging'");
|
$submission = querySubmissionToJudge('Waiting Rejudge', [
|
||||||
|
"judge_time" => DB::now(),
|
||||||
|
"judger" => $_POST['judger_name'],
|
||||||
|
"status" => 'Judging'
|
||||||
|
]);
|
||||||
if ($submission) {
|
if ($submission) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
querySubmissionToJudge('Judged, Waiting', "status = 'Judged, Judging'");
|
$submission = querySubmissionToJudge('Judged, Waiting', [
|
||||||
|
"status" => 'Judged, Judging'
|
||||||
|
]);
|
||||||
if ($submission) {
|
if ($submission) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
queryHackToJudge();
|
$submission = queryMinorSubmissionToJudge('Waiting Rejudge', [
|
||||||
|
"judge_time" => DB::now(),
|
||||||
|
"judger" => $_POST['judger_name'],
|
||||||
|
"status" => 'Judging'
|
||||||
|
]);
|
||||||
|
if ($submission) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$submission = queryMinorSubmissionToJudge('Judged, Waiting', [
|
||||||
|
"status" => 'Judged, Judging'
|
||||||
|
]);
|
||||||
|
if ($submission) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hack = queryHackToJudge();
|
||||||
if ($hack) {
|
if ($hack) {
|
||||||
$submission = DB::selectFirst("select id, problem_id, content from submissions where id = {$hack['submission_id']} and score = 100");
|
$submission = DB::selectFirst([
|
||||||
|
"select id, problem_id, content from submissions",
|
||||||
|
"where", [
|
||||||
|
"id" => $hack['submission_id'],
|
||||||
|
"score" => 100
|
||||||
|
]
|
||||||
|
]);
|
||||||
if (!$submission) {
|
if (!$submission) {
|
||||||
$details = "<error>the score gained by the hacked submission is not 100.\n</error>";
|
$details = "<error>the score gained by the hacked submission is not 100.</error>";
|
||||||
$esc_details = DB::escape(uojTextEncode($details));
|
DB::update([
|
||||||
DB::update("update hacks set success = 0, details = '$esc_details' where id = {$hack['id']}");
|
"update hacks",
|
||||||
|
"set", [
|
||||||
|
'success' => 0,
|
||||||
|
'status' => 'Judged',
|
||||||
|
'details' => uojTextEncode($details)
|
||||||
|
], "where", ["id" => $hack['id']]
|
||||||
|
]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -187,8 +374,6 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (isset($_POST['fetch_new']) && !$_POST['fetch_new']) {
|
if (isset($_POST['fetch_new']) && !$_POST['fetch_new']) {
|
||||||
die("Nothing to judge");
|
die("Nothing to judge");
|
||||||
}
|
}
|
||||||
@ -199,7 +384,11 @@
|
|||||||
$submission['id'] = (int)$submission['id'];
|
$submission['id'] = (int)$submission['id'];
|
||||||
$submission['problem_id'] = (int)$submission['problem_id'];
|
$submission['problem_id'] = (int)$submission['problem_id'];
|
||||||
$submission['problem_mtime'] = filemtime("/var/uoj_data/{$submission['problem_id']}");
|
$submission['problem_mtime'] = filemtime("/var/uoj_data/{$submission['problem_id']}");
|
||||||
$submission['content'] = json_decode($submission['content']);
|
$submission['content'] = json_decode($submission['content'], true);
|
||||||
|
if (isset($submission['status']) && $submission['status'] == 'Judged, Judging' && isset($submission['content']['final_test_config'])) {
|
||||||
|
$submission['content']['config'] = $submission['content']['final_test_config'];
|
||||||
|
unset($submission['content']['final_test_config']);
|
||||||
|
}
|
||||||
|
|
||||||
if ($hack) {
|
if ($hack) {
|
||||||
$submission['is_hack'] = "";
|
$submission['is_hack'] = "";
|
||||||
@ -209,4 +398,3 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode($submission);
|
echo json_encode($submission);
|
||||||
?>
|
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (!authenticateJudger()) {
|
if (!authenticateJudger()) {
|
||||||
become404Page();
|
UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (DB::selectAll("select * from judger_info where ip != ''") as $judger) {
|
$res = DB::selectAll([
|
||||||
|
"select * from judger_info",
|
||||||
|
"where", [
|
||||||
|
["ip", "!=", ""],
|
||||||
|
"enabled" => true
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
foreach ($res as $judger) {
|
||||||
$socket = fsockopen($judger['ip'], UOJConfig::$data['judger']['socket']['port']);
|
$socket = fsockopen($judger['ip'], UOJConfig::$data['judger']['socket']['port']);
|
||||||
if ($socket === false) {
|
if ($socket === false) {
|
||||||
die("judge client {$judger['ip']} lost.");
|
die("judge client {$judger['ip']} lost.");
|
||||||
@ -18,4 +26,3 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
die("ok");
|
die("ok");
|
||||||
?>
|
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requireLib('mathjax');
|
requireLib('mathjax');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
@ -73,7 +69,7 @@ EOD;
|
|||||||
echo "<td>{$extra_config['difficulty']}</td>";
|
echo "<td>{$extra_config['difficulty']}</td>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo '<td class="text-start">', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
echo '<td class="text-start">', ClickZans::getBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
||||||
echo '</tr>';
|
echo '</tr>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +117,7 @@ EOD;
|
|||||||
<!-- title container -->
|
<!-- title container -->
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= $list['title'] ?>
|
<?= $list['title'] ?>
|
||||||
<span class="fs-5">(ID: #<?= $list['id'] ?>)</span>
|
<span class="fs-5">(ID: #<?= $list['id'] ?>)</span>
|
||||||
<?php if ($list['is_hidden']): ?>
|
<?php if ($list['is_hidden']): ?>
|
||||||
@ -146,7 +142,7 @@ EOD;
|
|||||||
<!-- description -->
|
<!-- description -->
|
||||||
<div class="card my-2">
|
<div class="card my-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="h5 mb-3">题单简介</h2>
|
<h2 class="h4 mb-3">题单简介</h2>
|
||||||
<?php $description = HTML::purifier()->purify(HTML::parsedown()->text($list['description'])) ?>
|
<?php $description = HTML::purifier()->purify(HTML::parsedown()->text($list['description'])) ?>
|
||||||
<?php if ($description): ?>
|
<?php if ($description): ?>
|
||||||
<?= $description ?>
|
<?= $description ?>
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
if ($cur_tab == 'profile') {
|
if ($cur_tab == 'profile') {
|
||||||
$list_tags = queryProblemListTags($list_id);
|
$list_tags = queryProblemListTags($list_id);
|
||||||
|
|
||||||
$update_profile_form = new UOJForm('update_profile');
|
$update_profile_form = new UOJBs4Form('update_profile');
|
||||||
$update_profile_form->addVInput('name', 'text', '标题', $list['title'],
|
$update_profile_form->addVInput('name', 'text', '标题', $list['title'],
|
||||||
function($title, &$vdata) {
|
function($title, &$vdata) {
|
||||||
if ($title == '') {
|
if ($title == '') {
|
||||||
@ -151,7 +151,7 @@ function(res) {
|
|||||||
$(window).scrollTop(0);
|
$(window).scrollTop(0);
|
||||||
}
|
}
|
||||||
EOD);
|
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->submit_button_config['text'] = '更新';
|
||||||
$update_profile_form->runAtServer();
|
$update_profile_form->runAtServer();
|
||||||
} elseif ($cur_tab == 'problems') {
|
} elseif ($cur_tab == 'problems') {
|
||||||
@ -179,7 +179,7 @@ EOD);
|
|||||||
|
|
||||||
$n_problems = DB::selectCount("SELECT count(*) FROM `lists_problems` WHERE `list_id` = {$list['id']}");
|
$n_problems = DB::selectCount("SELECT count(*) FROM `lists_problems` WHERE `list_id` = {$list['id']}");
|
||||||
|
|
||||||
$add_new_problem_form = new UOJForm('add_new_problem');
|
$add_new_problem_form = new UOJBs4Form('add_new_problem');
|
||||||
$add_new_problem_form->addVInput('problem_id', 'text', '题目 ID', '',
|
$add_new_problem_form->addVInput('problem_id', 'text', '题目 ID', '',
|
||||||
function ($problem_id, &$vdata) use ($list) {
|
function ($problem_id, &$vdata) use ($list) {
|
||||||
if (!validateUInt($problem_id)) {
|
if (!validateUInt($problem_id)) {
|
||||||
@ -200,7 +200,7 @@ EOD);
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_new_problem_form->submit_button_config['margin_class'] = 'mt-3';
|
$add_new_problem_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
$add_new_problem_form->submit_button_config['text'] = '添加';
|
$add_new_problem_form->submit_button_config['text'] = '添加';
|
||||||
$add_new_problem_form->handle = function($vdata) use ($list) {
|
$add_new_problem_form->handle = function($vdata) use ($list) {
|
||||||
DB::insert("INSERT INTO `lists_problems` (`list_id`, `problem_id`) values ({$list['id']}, {$vdata['problem_id']})");
|
DB::insert("INSERT INTO `lists_problems` (`list_id`, `problem_id`) values ({$list['id']}, {$vdata['problem_id']})");
|
||||||
@ -250,7 +250,7 @@ EOD);
|
|||||||
dieWithAlert('移除成功!');
|
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_group_id', 'text', '小组 ID', '',
|
$add_new_assignment_form->addVInput('new_assignment_group_id', 'text', '小组 ID', '',
|
||||||
function ($group_id, &$vdata) use ($list) {
|
function ($group_id, &$vdata) use ($list) {
|
||||||
if (!validateUInt($group_id)) {
|
if (!validateUInt($group_id)) {
|
||||||
@ -300,7 +300,7 @@ EOD);
|
|||||||
'message' => '题单 #' . $list['id'] . ' 已经被添加到小组 #' . $vdata['group_id'] . ' 的作业列表中,结束时间为 ' . $vdata['end_time']->format('Y-m-d H:i:s') . '。'
|
'message' => '题单 #' . $list['id'] . ' 已经被添加到小组 #' . $vdata['group_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->submit_button_config['text'] = '添加';
|
||||||
$add_new_assignment_form->setAjaxSubmit(<<<EOD
|
$add_new_assignment_form->setAjaxSubmit(<<<EOD
|
||||||
function(res) {
|
function(res) {
|
||||||
@ -330,7 +330,7 @@ EOD);
|
|||||||
|
|
||||||
<?php echoUOJPageHeader('管理 - ' . $list['title']) ?>
|
<?php echoUOJPageHeader('管理 - ' . $list['title']) ?>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= $list['title'] ?>
|
<?= $list['title'] ?>
|
||||||
<small class="fs-5">(ID: #<?= $list['id'] ?>)</small>
|
<small class="fs-5">(ID: #<?= $list['id'] ?>)</small>
|
||||||
管理
|
管理
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
if (isSuperUser($myUser)) {
|
||||||
$new_list_form = new UOJForm('new_list');
|
$new_list_form = new UOJBs4Form('new_list');
|
||||||
$new_list_form->handle = function() {
|
$new_list_form->handle = function() {
|
||||||
DB::query("insert into lists (title, is_hidden) values ('未命名题单', 1)");
|
DB::query("insert into lists (title, is_hidden) values ('未命名题单', 1)");
|
||||||
};
|
};
|
||||||
@ -66,7 +62,7 @@
|
|||||||
<!-- title container -->
|
<!-- title container -->
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('problems lists') ?>
|
<?= UOJLocale::get('problems lists') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -147,7 +143,6 @@ EOD;
|
|||||||
'page_len' => 40,
|
'page_len' => 40,
|
||||||
'table_classes' => ['table', 'table-bordered', 'table-hover', 'table-striped'],
|
'table_classes' => ['table', 'table-bordered', 'table-hover', 'table-striped'],
|
||||||
'head_pagination' => true,
|
'head_pagination' => true,
|
||||||
'pagination_table' => 'lists',
|
|
||||||
'div_classes' => ['card', 'my-3'],
|
'div_classes' => ['card', 'my-3'],
|
||||||
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
'table_classes' => ['table', 'uoj-table', 'mb-0'],
|
||||||
]
|
]
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Gregwar\Captcha\PhraseBuilder;
|
use Gregwar\Captcha\PhraseBuilder;
|
||||||
use Gregwar\Captcha\CaptchaBuilder;
|
|
||||||
|
|
||||||
requireLib('md5');
|
requireLib('md5');
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
|
|
||||||
if (Auth::check()) {
|
Auth::check() && redirectTo('/');
|
||||||
redirectTo('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleLoginPost() {
|
function handleLoginPost() {
|
||||||
if (!crsf_check()) {
|
if (!crsf_check()) {
|
||||||
@ -34,13 +32,14 @@
|
|||||||
return "failed";
|
return "failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = queryUser($username);
|
$user = UOJUser::query($username);
|
||||||
if (!$user || !checkPassword($user, $password)) {
|
if (!$user || !checkPassword($user, $password)) {
|
||||||
return "failed";
|
return "failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($user['usergroup'] == 'B') {
|
$account_status = UOJUser::getAccountStatus($user);
|
||||||
return "banned";
|
if ($account_status != 'ok') {
|
||||||
|
return 'account:' . $account_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth::login($user['username']);
|
Auth::login($user['username']);
|
||||||
@ -179,7 +178,6 @@ $(document).ready(function() {
|
|||||||
refreshCaptcha();
|
refreshCaptcha();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -5,105 +5,171 @@
|
|||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
|
|
||||||
|
$problem = UOJProblem::cur()->info;
|
||||||
|
$problem_content = UOJProblem::cur()->queryContent();
|
||||||
|
|
||||||
|
if (UOJRequest::get('contest_id')) {
|
||||||
|
UOJContest::init(UOJRequest::get('contest_id')) || UOJResponse::page404();
|
||||||
|
UOJProblem::upgradeToContestProblem() || UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
UOJProblem::cur()->userCanView(Auth::user(), ['ensure' => true]);
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
$pre_submit_check_ret = UOJProblem::cur()->preSubmitCheck();
|
||||||
become404Page();
|
|
||||||
|
$is_participating = false;
|
||||||
|
$no_more_submission = false;
|
||||||
|
$submission_warning = null;
|
||||||
|
if (UOJContest::cur()) {
|
||||||
|
if (UOJContest::cur()->userCanParticipateNow(Auth::user())) {
|
||||||
|
if (!UOJContest::cur()->userHasMarkedParticipated(Auth::user())) {
|
||||||
|
redirectTo(UOJContest::cur()->getUri("/confirm"));
|
||||||
}
|
}
|
||||||
|
$is_participating = true;
|
||||||
$problem_content = queryProblemContent($problem['id']);
|
$submit_time_limit = UOJContestProblem::cur()->submitTimeLimit();
|
||||||
|
$max_cnt = UOJContest::cur()->maxSubmissionCountPerProblem();
|
||||||
$contest = validateUInt($_GET['contest_id']) ? queryContest($_GET['contest_id']) : null;
|
if ($submit_time_limit != -1) {
|
||||||
if ($contest != null) {
|
$cur_contest_time = (UOJTime::$time_now->getTimestamp() - UOJContest::info('start_time')->getTimestamp()) / 60;
|
||||||
genMoreContestInfo($contest);
|
if ($cur_contest_time > $submit_time_limit) {
|
||||||
$problem_rank = queryContestProblemRank($contest, $problem);
|
$no_more_submission = "本题只能在比赛的前 {$submit_time_limit} 分钟提交,没法再交咯";
|
||||||
if ($problem_rank == null) {
|
}
|
||||||
become404Page();
|
}
|
||||||
|
if (!$no_more_submission) {
|
||||||
|
if ($max_cnt != -1) {
|
||||||
|
$cnt = UOJContestProblem::cur()->queryUserSubmissionCountInContest(Auth::user());
|
||||||
|
if ($cnt >= $max_cnt) {
|
||||||
|
$no_more_submission = "提交次数已达到 {$cnt} 次,没法再交咯";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$no_more_submission) {
|
||||||
|
if ($max_cnt != -1) {
|
||||||
|
$warning1 = "已使用 {$cnt}/{$max_cnt} 次提交机会";
|
||||||
} else {
|
} else {
|
||||||
$problem_letter = chr(ord('A') + $problem_rank - 1);
|
$warning1 = null;
|
||||||
|
}
|
||||||
|
if ($submit_time_limit != -1) {
|
||||||
|
$warning2 = "注意本题只能在比赛的前 {$submit_time_limit} 分钟提交";
|
||||||
|
} else {
|
||||||
|
$warning2 = null;
|
||||||
|
}
|
||||||
|
if ($warning1 && $warning2) {
|
||||||
|
$submission_warning = "{$warning1}({$warning2})";
|
||||||
|
} else {
|
||||||
|
$submission_warning = $warning1 !== null ? $warning1 : $warning2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$is_in_contest = false;
|
// 比赛导航
|
||||||
$ban_in_contest = false;
|
$tabs_info = [
|
||||||
if ($contest != null) {
|
'dashboard' => [
|
||||||
if (!hasContestPermission($myUser, $contest)) {
|
'name' => UOJLocale::get('contests::contest dashboard'),
|
||||||
if ($contest['cur_progress'] == CONTEST_NOT_STARTED) {
|
'url' => '/contest/' . UOJContest::info('id'),
|
||||||
become404Page();
|
],
|
||||||
} elseif ($contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
'submissions' => [
|
||||||
if (Auth::check()) {
|
'name' => UOJLocale::get('contests::contest submissions'),
|
||||||
if (hasParticipated($myUser, $contest)) {
|
'url' => '/contest/' . UOJContest::info('id') . '/submissions',
|
||||||
$is_in_contest = true;
|
],
|
||||||
} else {
|
'standings' => [
|
||||||
redirectTo("/contest/{$contest['id']}/confirm");
|
'name' => UOJLocale::get('contests::contest standings'),
|
||||||
}
|
'url' => '/contest/' . UOJContest::info('id') . '/standings',
|
||||||
} else {
|
],
|
||||||
redirectToLogin();
|
];
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$ban_in_contest = !isProblemVisibleToUser($problem, $myUser);
|
|
||||||
|
|
||||||
if (!hasRegistered($myUser, $contest) && !isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
if (UOJContest::cur()->progress() > CONTEST_TESTING) {
|
||||||
become403Page();
|
$tabs_info['after_contest_standings'] = [
|
||||||
}
|
'name' => UOJLocale::get('contests::after contest standings'),
|
||||||
}
|
'url' => '/contest/' . UOJContest::info('id') . '/after_contest_standings',
|
||||||
} else {
|
];
|
||||||
if ($contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
$tabs_info['self_reviews'] = [
|
||||||
if (hasRegistered($myUser, $contest)) {
|
'name' => UOJLocale::get('contests::contest self reviews'),
|
||||||
if (hasParticipated($myUser, $contest)) {
|
'url' => '/contest/' . UOJContest::info('id') . '/self_reviews',
|
||||||
$is_in_contest = true;
|
];
|
||||||
} else {
|
|
||||||
redirectTo("/contest/{$contest['id']}/confirm");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isProblemVisibleToUser($problem, $myUser)) {
|
|
||||||
become404Page();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
if (UOJContest::cur()->userCanManage(Auth::user())) {
|
||||||
become403Page();
|
$tabs_info['backstage'] = [
|
||||||
|
'name' => UOJLocale::get('contests::contest backstage'),
|
||||||
|
'url' => '/contest/' . UOJContest::info('id') . '/backstage',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$submission_requirement = json_decode($problem['submission_requirement'], true);
|
$submission_requirement = UOJProblem::cur()->getSubmissionRequirement();
|
||||||
$problem_extra_config = getProblemExtraConfig($problem);
|
$custom_test_requirement = UOJProblem::cur()->getCustomTestRequirement();
|
||||||
$custom_test_requirement = getProblemCustomTestRequirement($problem);
|
$custom_test_enabled = $custom_test_requirement && $pre_submit_check_ret === true;
|
||||||
|
|
||||||
if ($custom_test_requirement && Auth::check()) {
|
function handleUpload($zip_file_name, $content, $tot_size) {
|
||||||
$custom_test_submission = DB::selectFirst("select * from custom_test_submissions where submitter = '".Auth::id()."' and problem_id = {$problem['id']} order by id desc limit 1");
|
global $is_participating;
|
||||||
$custom_test_submission_result = json_decode($custom_test_submission['result'], true);
|
UOJSubmission::onUpload($zip_file_name, $content, $tot_size, $is_participating);
|
||||||
}
|
}
|
||||||
if ($custom_test_requirement && $_GET['get'] == 'custom-test-status-details' && Auth::check()) {
|
function handleCustomTestUpload($zip_file_name, $content, $tot_size) {
|
||||||
if ($custom_test_submission == null) {
|
UOJCustomTestSubmission::onUpload($zip_file_name, $content, $tot_size);
|
||||||
|
}
|
||||||
|
if ($custom_test_enabled) {
|
||||||
|
UOJCustomTestSubmission::init(UOJProblem::cur(), Auth::user());
|
||||||
|
|
||||||
|
if (UOJRequest::get('get') == 'custom-test-status-details') {
|
||||||
|
if (!UOJCustomTestSubmission::cur()) {
|
||||||
echo json_encode(null);
|
echo json_encode(null);
|
||||||
} elseif ($custom_test_submission['status'] != 'Judged') {
|
} elseif (!UOJCustomTestSubmission::cur()->hasJudged()) {
|
||||||
echo json_encode(array(
|
echo json_encode([
|
||||||
'judged' => false,
|
'judged' => false,
|
||||||
'html' => getSubmissionStatusDetails($custom_test_submission)
|
'waiting' => true,
|
||||||
));
|
'html' => UOJCustomTestSubmission::cur()->getStatusDetailsHTML(),
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
ob_start();
|
ob_start();
|
||||||
$styler = new CustomTestSubmissionDetailsStyler();
|
$styler = new CustomTestSubmissionDetailsStyler();
|
||||||
if (!hasViewPermission($problem_extra_config['view_details_type'], $myUser, $problem, $submission)) {
|
if (!UOJCustomTestSubmission::cur()->userPermissionCodeCheck(Auth::user(), UOJProblem::cur()->getExtraConfig('view_details_type'))) {
|
||||||
$styler->fade_all_details = true;
|
$styler->fade_all_details = true;
|
||||||
}
|
}
|
||||||
echoJudgementDetails($custom_test_submission_result['details'], $styler, 'custom_test_details');
|
echoJudgmentDetails(UOJCustomTestSubmission::cur()->getResult('details'), $styler, 'custom_test_details');
|
||||||
$result = ob_get_contents();
|
$result = ob_get_contents();
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
echo json_encode(array(
|
echo json_encode([
|
||||||
'judged' => true,
|
'judged' => true,
|
||||||
'html' => getSubmissionStatusDetails($custom_test_submission),
|
'waiting' => false,
|
||||||
|
'html' => UOJCustomTestSubmission::cur()->getStatusDetailsHTML(),
|
||||||
'result' => $result
|
'result' => $result
|
||||||
));
|
]);
|
||||||
}
|
}
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$custom_test_form = newSubmissionForm(
|
||||||
|
'custom_test',
|
||||||
|
$custom_test_requirement,
|
||||||
|
'FS::randomAvailableTmpFileName',
|
||||||
|
'handleCustomTestUpload'
|
||||||
|
);
|
||||||
|
$custom_test_form->appendHTML('<div id="div-custom_test_result"></div>');
|
||||||
|
$custom_test_form->succ_href = 'none';
|
||||||
|
$custom_test_form->extra_validator = function () {
|
||||||
|
if (UOJCustomTestSubmission::cur() && !UOJCustomTestSubmission::cur()->hasJudged()) {
|
||||||
|
return '上一个测评尚未结束';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
$custom_test_form->ctrl_enter_submit = true;
|
||||||
|
$custom_test_form->setAjaxSubmit(
|
||||||
|
<<<EOD
|
||||||
|
function(response_text) {
|
||||||
|
custom_test_onsubmit(
|
||||||
|
response_text,
|
||||||
|
$('#div-custom_test_result')[0],
|
||||||
|
'{$_SERVER['REQUEST_URI']}?get=custom-test-status-details'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
EOD
|
||||||
|
);
|
||||||
|
$custom_test_form->submit_button_config['text'] = UOJLocale::get('problems::run');
|
||||||
|
$custom_test_form->runAtServer();
|
||||||
|
}
|
||||||
|
|
||||||
$can_use_zip_upload = true;
|
$can_use_zip_upload = true;
|
||||||
foreach ($submission_requirement as $req) {
|
foreach ($submission_requirement as $req) {
|
||||||
if ($req['type'] == 'source code') {
|
if ($req['type'] == 'source code') {
|
||||||
@ -111,176 +177,49 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUpload($zip_file_name, $content, $tot_size) {
|
if ($pre_submit_check_ret === true && !$no_more_submission) {
|
||||||
global $problem, $contest, $myUser, $is_in_contest;
|
$submission_extra_validator = function () {
|
||||||
|
if (!submission_frequency_check()) {
|
||||||
$content['config'][] = array('problem_id', $problem['id']);
|
UOJLog::warning('a user exceeds the submission frequency limit! ' . Auth::id() . ' at problem #' . UOJProblem::info('id'));
|
||||||
if ($is_in_contest && $contest['extra_config']["contest_type"]!='IOI' && !isset($contest['extra_config']["problem_{$problem['id']}"])) {
|
return '交题交得太快啦,坐下来喝杯阿华田休息下吧?';
|
||||||
$content['final_test_config'] = $content['config'];
|
|
||||||
$content['config'][] = array('test_sample_only', 'on');
|
|
||||||
}
|
|
||||||
$esc_content = DB::escape(json_encode($content));
|
|
||||||
|
|
||||||
$language = '/';
|
|
||||||
foreach ($content['config'] as $row) {
|
|
||||||
if (strEndWith($row[0], '_language')) {
|
|
||||||
$language = $row[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($language != '/') {
|
|
||||||
Cookie::set('uoj_preferred_language', $language, time() + 60 * 60 * 24 * 365, '/');
|
|
||||||
}
|
|
||||||
$esc_language = DB::escape($language);
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
$result['status'] = "Waiting";
|
|
||||||
$result_json = json_encode($result);
|
|
||||||
|
|
||||||
if ($is_in_contest) {
|
|
||||||
DB::query("insert into submissions (problem_id, contest_id, submit_time, submitter, content, language, tot_size, status, result, is_hidden) values (${problem['id']}, ${contest['id']}, now(), '${myUser['username']}', '$esc_content', '$esc_language', $tot_size, '${result['status']}', '$result_json', 0)");
|
|
||||||
} else {
|
|
||||||
DB::query("insert into submissions (problem_id, submit_time, submitter, content, language, tot_size, status, result, is_hidden) values (${problem['id']}, now(), '${myUser['username']}', '$esc_content', '$esc_language', $tot_size, '${result['status']}', '$result_json', {$problem['is_hidden']})");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handleCustomTestUpload($zip_file_name, $content, $tot_size) {
|
|
||||||
global $problem, $contest, $myUser;
|
|
||||||
|
|
||||||
$content['config'][] = array('problem_id', $problem['id']);
|
|
||||||
$content['config'][] = array('custom_test', 'on');
|
|
||||||
$esc_content = DB::escape(json_encode($content));
|
|
||||||
|
|
||||||
$language = '/';
|
|
||||||
foreach ($content['config'] as $row) {
|
|
||||||
if (strEndWith($row[0], '_language')) {
|
|
||||||
$language = $row[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($language != '/') {
|
|
||||||
Cookie::set('uoj_preferred_language', $language, time() + 60 * 60 * 24 * 365, '/');
|
|
||||||
}
|
|
||||||
$esc_language = DB::escape($language);
|
|
||||||
|
|
||||||
$result = array();
|
|
||||||
$result['status'] = "Waiting";
|
|
||||||
$result_json = json_encode($result);
|
|
||||||
|
|
||||||
DB::insert("insert into custom_test_submissions (problem_id, submit_time, submitter, content, status, result) values ({$problem['id']}, now(), '{$myUser['username']}', '$esc_content', '{$result['status']}', '$result_json')");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($can_use_zip_upload) {
|
|
||||||
$zip_answer_form = newZipSubmissionForm('zip_answer',
|
|
||||||
$submission_requirement,
|
|
||||||
'uojRandAvaiableSubmissionFileName',
|
|
||||||
'handleUpload');
|
|
||||||
$zip_answer_form->extra_validator = function() {
|
|
||||||
global $ban_in_contest;
|
|
||||||
if ($ban_in_contest) {
|
|
||||||
return '请耐心等待比赛结束后题目对所有人可见了再提交';
|
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
$zip_answer_form->succ_href = $is_in_contest ? "/contest/{$contest['id']}/submissions" : '/submissions';
|
|
||||||
|
if (UOJProblem::cur()->userCanUploadSubmissionViaZip(Auth::user())) {
|
||||||
|
$zip_answer_form = newZipSubmissionForm(
|
||||||
|
'zip-answer',
|
||||||
|
$submission_requirement,
|
||||||
|
'FS::randomAvailableSubmissionFileName',
|
||||||
|
'handleUpload'
|
||||||
|
);
|
||||||
|
$zip_answer_form->extra_validators[] = $submission_extra_validator;
|
||||||
|
$zip_answer_form->succ_href = $is_participating ? '/contest/' . UOJContest::info('id') . '/submissions' : '/submissions';
|
||||||
$zip_answer_form->runAtServer();
|
$zip_answer_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
$answer_form = newSubmissionForm('answer',
|
$answer_form = newSubmissionForm(
|
||||||
|
'answer',
|
||||||
$submission_requirement,
|
$submission_requirement,
|
||||||
'uojRandAvaiableSubmissionFileName',
|
'FS::randomAvailableSubmissionFileName',
|
||||||
'handleUpload');
|
'handleUpload'
|
||||||
$answer_form->extra_validator = function() {
|
);
|
||||||
global $ban_in_contest;
|
$answer_form->extra_validator = $submission_extra_validator;
|
||||||
if ($ban_in_contest) {
|
$answer_form->succ_href = $is_participating ? '/contest/' . UOJContest::info('id') . '/submissions' : '/submissions';
|
||||||
return '请耐心等待比赛结束后题目对所有人可见了再提交';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
$answer_form->succ_href = $is_in_contest ? "/contest/{$contest['id']}/submissions" : '/submissions';
|
|
||||||
$answer_form->runAtServer();
|
$answer_form->runAtServer();
|
||||||
|
}
|
||||||
|
|
||||||
if ($custom_test_requirement) {
|
$conf = UOJProblem::cur()->getProblemConf();
|
||||||
$custom_test_form = newSubmissionForm('custom_test',
|
|
||||||
$custom_test_requirement,
|
|
||||||
function() {
|
|
||||||
return uojRandAvaiableFileName('/tmp/');
|
|
||||||
},
|
|
||||||
'handleCustomTestUpload');
|
|
||||||
$custom_test_form->appendHTML(<<<EOD
|
|
||||||
<div id="div-custom_test_result"></div>
|
|
||||||
EOD
|
|
||||||
);
|
|
||||||
$custom_test_form->succ_href = 'none';
|
|
||||||
$custom_test_form->extra_validator = function() {
|
|
||||||
global $ban_in_contest, $custom_test_submission;
|
|
||||||
if ($ban_in_contest) {
|
|
||||||
return '请耐心等待比赛结束后题目对所有人可见了再提交';
|
|
||||||
}
|
|
||||||
if ($custom_test_submission && $custom_test_submission['status'] != 'Judged') {
|
|
||||||
return '上一个测评尚未结束';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
$custom_test_form->ctrl_enter_submit = true;
|
|
||||||
$custom_test_form->setAjaxSubmit(<<<EOD
|
|
||||||
function(response_text) {custom_test_onsubmit(response_text, $('#div-custom_test_result')[0], '{$_SERVER['REQUEST_URI']}?get=custom-test-status-details')}
|
|
||||||
EOD
|
|
||||||
);
|
|
||||||
$custom_test_form->submit_button_config['text'] = UOJLocale::get('problems::run');
|
|
||||||
$custom_test_form->runAtServer();
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader(HTML::stripTags($problem['title']) . ' - ' . UOJLocale::get('problems::problem')) ?>
|
<?php echoUOJPageHeader(HTML::stripTags($problem['title']) . ' - ' . UOJLocale::get('problems::problem')) ?>
|
||||||
<?php
|
|
||||||
$limit = getUOJConf("/var/uoj_data/{$problem['id']}/problem.conf");
|
|
||||||
$time_limit = $limit['time_limit'];
|
|
||||||
$memory_limit = $limit['memory_limit'];
|
|
||||||
|
|
||||||
$problem_uploader = $problem['uploader'];
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<!-- Left col -->
|
<!-- Left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
|
||||||
<?php if ($contest): ?>
|
<?php if (isset($tabs_info)) : ?>
|
||||||
<!-- 比赛导航 -->
|
<!-- 比赛导航 -->
|
||||||
<?php
|
|
||||||
$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"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
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 (hasContestPermission(Auth::user(), $contest)) {
|
|
||||||
$tabs_info['backstage'] = array(
|
|
||||||
'name' => UOJLocale::get('contests::contest backstage'),
|
|
||||||
'url' => "/contest/{$contest['id']}/backstage"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<?= HTML::tablist($tabs_info, '', 'nav-pills') ?>
|
<?= HTML::tablist($tabs_info, '', 'nav-pills') ?>
|
||||||
</div>
|
</div>
|
||||||
@ -289,20 +228,24 @@ EOD
|
|||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<h1 class="h2 card-title text-center">
|
<h1 class="card-title text-center">
|
||||||
<?php if ($contest): ?>
|
<?php if (UOJContest::cur()) : ?>
|
||||||
<?= $problem_letter ?>. <?= $problem['title'] ?>
|
<?= UOJProblem::cur()->getTitle(['with' => 'letter', 'simplify' => true]) ?>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
#<?= $problem['id']?>. <?= $problem['title'] ?>
|
<?= UOJProblem::cur()->getTitle(['with' => 'id']) ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$time_limit = $conf instanceof UOJProblemConf ? $conf->getVal('time_limit', null) : null;
|
||||||
|
$memory_limit = $conf instanceof UOJProblemConf ? $conf->getVal('memory_limit', null) : null;
|
||||||
|
?>
|
||||||
<div class="text-center small">
|
<div class="text-center small">
|
||||||
时间限制: <?= $time_limit != null ? "$time_limit s" : "N/A" ?>
|
时间限制: <?= $time_limit ? "$time_limit s" : "N/A" ?>
|
||||||
 
|
 
|
||||||
空间限制: <?= $memory_limit != null ? "$memory_limit MB" : "N/A" ?>
|
空间限制: <?= $memory_limit ? "$memory_limit MB" : "N/A" ?>
|
||||||
 
|
 
|
||||||
上传者: <?= getUserLink($problem_uploader ?: "root") ?>
|
上传者: <?= UOJProblem::cur()->getUploaderLink() ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
@ -314,17 +257,24 @@ EOD
|
|||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="submit">
|
<div class="tab-pane" id="submit">
|
||||||
<div class="top-buffer-sm"></div>
|
<?php if ($pre_submit_check_ret !== true) : ?>
|
||||||
<?php if ($can_use_zip_upload): ?>
|
<h3 class="text-warning"><?= $pre_submit_check_ret ?></h3>
|
||||||
|
<?php elseif ($no_more_submission) : ?>
|
||||||
|
<h3 class="text-warning"><?= $no_more_submission ?></h3>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php if ($submission_warning) : ?>
|
||||||
|
<h3 class="text-warning"><?= $submission_warning ?></h3>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php if (isset($zip_answer_form)) : ?>
|
||||||
<?php $zip_answer_form->printHTML(); ?>
|
<?php $zip_answer_form->printHTML(); ?>
|
||||||
<hr />
|
<hr />
|
||||||
<strong><?= UOJLocale::get('problems::or upload files one by one') ?><br /></strong>
|
<strong><?= UOJLocale::get('problems::or upload files one by one') ?><br /></strong>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php $answer_form->printHTML(); ?>
|
<?php $answer_form->printHTML(); ?>
|
||||||
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($custom_test_requirement): ?>
|
<?php if ($custom_test_enabled) : ?>
|
||||||
<div class="tab-pane" id="custom-test">
|
<div class="tab-pane" id="custom-test">
|
||||||
<div class="top-buffer-sm"></div>
|
|
||||||
<?php $custom_test_form->printHTML(); ?>
|
<?php $custom_test_form->printHTML(); ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -339,17 +289,17 @@ EOD
|
|||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<!-- Right col -->
|
<!-- Right col -->
|
||||||
|
|
||||||
<?php if ($contest): ?>
|
<?php if (UOJContest::cur()) : ?>
|
||||||
<!-- Contest card -->
|
<!-- Contest card -->
|
||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h3 class="h5 card-title text-center">
|
<h3 class="h4 card-title text-center">
|
||||||
<a class="text-decoration-none text-body" href="/contest/<?= $contest['id'] ?>">
|
<a class="text-decoration-none text-body" href="/contest/<?= UOJContest::info('id') ?>">
|
||||||
<?= $contest['name'] ?>
|
<?= UOJContest::info('name') ?>
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="card-text text-center text-muted">
|
<div class="card-text text-center text-muted">
|
||||||
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS): ?>
|
<?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?>
|
||||||
<span id="contest-countdown"></span>
|
<span id="contest-countdown"></span>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<?= UOJLocale::get('contests::contest ended') ?>
|
<?= UOJLocale::get('contests::contest ended') ?>
|
||||||
@ -357,12 +307,12 @@ EOD
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
比赛评价:<?= getClickZanBlock('C', $contest['id'], $contest['zan']) ?>
|
比赛评价:<?= ClickZans::getBlock('C', UOJContest::info('id'), UOJContest::info('zan')) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS): ?>
|
<?php if (UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) : ?>
|
||||||
<script type="text/javascript">
|
<script>
|
||||||
$('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function(){}, '1.75rem', false);
|
$('#contest-countdown').countdown(<?= UOJContest::info('end_time')->getTimestamp() - UOJTime::$time_now->getTimestamp() ?>, function() {}, '1.75rem', false);
|
||||||
</script>
|
</script>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -382,7 +332,7 @@ $('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJ
|
|||||||
<?= UOJLocale::get('problems::submit') ?>
|
<?= UOJLocale::get('problems::submit') ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php if ($custom_test_requirement): ?>
|
<?php if ($custom_test_enabled) : ?>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="#custom-test" role="tab" data-bs-toggle="pill" data-bs-target="#custom-test">
|
<a class="nav-link" href="#custom-test" role="tab" data-bs-toggle="pill" data-bs-target="#custom-test">
|
||||||
<i class="bi bi-braces"></i>
|
<i class="bi bi-braces"></i>
|
||||||
@ -390,7 +340,7 @@ $('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJ
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php if (!$contest || $contest['cur_progress'] >= CONTEST_FINISHED): ?>
|
<?php if (!UOJContest::cur() || UOJContest::cur()->progress() >= CONTEST_FINISHED) : ?>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a href="/problem/<?= $problem['id'] ?>/solutions" class="nav-link" role="tab">
|
<a href="/problem/<?= $problem['id'] ?>/solutions" class="nav-link" role="tab">
|
||||||
<i class="bi bi-journal-bookmark"></i>
|
<i class="bi bi-journal-bookmark"></i>
|
||||||
@ -398,19 +348,22 @@ $('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJ
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
<?php if (UOJContest::cur() && UOJContest::cur()->userCanSeeProblemStatistics(Auth::user())) : ?>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link"
|
<a class="nav-link" href="/contest/<?= UOJContest::info('id') ?>/problem/<?= $problem['id'] ?>/statistics">
|
||||||
<?php if ($contest): ?>
|
|
||||||
href="/contest/<?= $contest['id'] ?>/problem/<?= $problem['id'] ?>/statistics"
|
|
||||||
<?php else: ?>
|
|
||||||
href="/problem/<?= $problem['id'] ?>/statistics"
|
|
||||||
<?php endif ?>
|
|
||||||
>
|
|
||||||
<i class="bi bi-graph-up"></i>
|
<i class="bi bi-graph-up"></i>
|
||||||
<?= UOJLocale::get('problems::statistics') ?>
|
<?= UOJLocale::get('problems::statistics') ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php if (hasProblemPermission($myUser, $problem)): ?>
|
<?php elseif (!UOJContest::cur()) : ?>
|
||||||
|
<li class="nav-item text-start">
|
||||||
|
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/statistics">
|
||||||
|
<i class="bi bi-graph-up"></i>
|
||||||
|
<?= UOJLocale::get('problems::statistics') ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php if (UOJProblem::cur()->userCanManage(Auth::user())) : ?>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab">
|
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab">
|
||||||
<i class="bi bi-sliders"></i>
|
<i class="bi bi-sliders"></i>
|
||||||
@ -420,21 +373,23 @@ $('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJ
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
评价:<?= getClickZanBlock('P', $problem['id'], $problem['zan']) ?>
|
评价:<?= ClickZans::getBlock('P', $problem['id'], $problem['zan']) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 附件 -->
|
<!-- 附件 -->
|
||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<ul class="nav nav-fill flex-column">
|
<ul class="nav nav-fill flex-column">
|
||||||
|
<?php if (UOJProblem::cur()->userCanDownloadTestData(Auth::user())) : ?>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="<?= HTML::url("/download.php?type=problem&id={$problem['id']}") ?>">
|
<a class="nav-link" href="<?= HTML::url("/download/problem/{$problem['id']}/data.zip") ?>">
|
||||||
<i class="bi bi-hdd-stack"></i>
|
<i class="bi bi-hdd-stack"></i>
|
||||||
测试数据
|
测试数据
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<?php endif ?>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="<?= HTML::url("/download.php?type=attachment&id={$problem['id']}") ?>">
|
<a class="nav-link" href="<?= HTML::url("/download/problem/{$problem['id']}/attachment.zip") ?>">
|
||||||
<i class="bi bi-download"></i>
|
<i class="bi bi-download"></i>
|
||||||
附件下载
|
附件下载
|
||||||
</a>
|
</a>
|
||||||
@ -443,8 +398,8 @@ $('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJ
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$sidebar_config = array();
|
$sidebar_config = [];
|
||||||
if ($contest && $contest['cur_progress'] <= CONTEST_IN_PROGRESS) {
|
if (UOJContest::cur() && UOJContest::cur()->progress() <= CONTEST_IN_PROGRESS) {
|
||||||
$sidebar_config['upcoming_contests_hidden'] = '';
|
$sidebar_config['upcoming_contests_hidden'] = '';
|
||||||
}
|
}
|
||||||
uojIncludeView('sidebar', $sidebar_config);
|
uojIncludeView('sidebar', $sidebar_config);
|
||||||
@ -473,10 +428,4 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php if ($contest && $contest['cur_progress'] <= CONTEST_IN_PROGRESS): ?>
|
|
||||||
<script type="text/javascript">
|
|
||||||
checkContestNotice(<?= $contest['id'] ?>, '<?= UOJTime::$time_now_str ?>');
|
|
||||||
</script>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8,15 +8,10 @@
|
|||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become404Page();
|
UOJProblem::cur()->userCanManage(Auth::user()) || UOJResponse::page403();
|
||||||
}
|
$problem = UOJProblem::info();
|
||||||
if (!hasProblemPermission($myUser, $problem)) {
|
$problem_extra_config = UOJProblem::cur()->getExtraConfig();
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$oj_name = UOJConfig::$data['profile']['oj-name'];
|
|
||||||
$problem_extra_config = getProblemExtraConfig($problem);
|
|
||||||
|
|
||||||
$data_dir = "/var/uoj_data/${problem['id']}";
|
$data_dir = "/var/uoj_data/${problem['id']}";
|
||||||
|
|
||||||
@ -24,6 +19,7 @@
|
|||||||
echo '<h5>', htmlspecialchars($file_name), '</h5>';
|
echo '<h5>', htmlspecialchars($file_name), '</h5>';
|
||||||
echo '<div class="small text-danger"> ', '文件未找到', '</div>';
|
echo '<div class="small text-danger"> ', '文件未找到', '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function echoFilePre($file_name) {
|
function echoFilePre($file_name) {
|
||||||
global $data_dir;
|
global $data_dir;
|
||||||
$file_full_name = $data_dir . '/' . $file_name;
|
$file_full_name = $data_dir . '/' . $file_name;
|
||||||
@ -49,7 +45,6 @@
|
|||||||
echo "\n</pre>";
|
echo "\n</pre>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 上传数据
|
// 上传数据
|
||||||
if ($_POST['problem_data_file_submit'] == 'submit') {
|
if ($_POST['problem_data_file_submit'] == 'submit') {
|
||||||
if ($_FILES["problem_data_file"]["error"] > 0) {
|
if ($_FILES["problem_data_file"]["error"] > 0) {
|
||||||
@ -130,10 +125,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$info_form = new UOJForm('info');
|
$info_form = new UOJBs4Form('info');
|
||||||
$http_host = HTML::escape(UOJContext::httpHost());
|
$http_host = HTML::escape(UOJContext::httpHost());
|
||||||
$attachment_url = HTML::url("/download.php?type=attachment&id={$problem['id']}");
|
$attachment_url = HTML::url("/download.php?type=attachment&id={$problem['id']}");
|
||||||
$info_form->appendHTML(<<<EOD
|
$info_form->appendHTML(
|
||||||
|
<<<EOD
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-3 control-label">problem_{$problem['id']}_attachment.zip</label>
|
<label class="col-sm-3 control-label">problem_{$problem['id']}_attachment.zip</label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -145,7 +141,8 @@
|
|||||||
EOD
|
EOD
|
||||||
);
|
);
|
||||||
$download_url = HTML::url("/download.php?type=problem&id={$problem['id']}");
|
$download_url = HTML::url("/download.php?type=problem&id={$problem['id']}");
|
||||||
$info_form->appendHTML(<<<EOD
|
$info_form->appendHTML(
|
||||||
|
<<<EOD
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-3 control-label">problem_{$problem['id']}.zip</label>
|
<label class="col-sm-3 control-label">problem_{$problem['id']}.zip</label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -156,7 +153,8 @@ EOD
|
|||||||
</div>
|
</div>
|
||||||
EOD
|
EOD
|
||||||
);
|
);
|
||||||
$info_form->appendHTML(<<<EOD
|
$info_form->appendHTML(
|
||||||
|
<<<EOD
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-3 control-label">testlib.h</label>
|
<label class="col-sm-3 control-label">testlib.h</label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -169,7 +167,8 @@ EOD
|
|||||||
);
|
);
|
||||||
|
|
||||||
$esc_submission_requirement = HTML::escape(json_encode(json_decode($problem['submission_requirement']), JSON_PRETTY_PRINT));
|
$esc_submission_requirement = HTML::escape(json_encode(json_decode($problem['submission_requirement']), JSON_PRETTY_PRINT));
|
||||||
$info_form->appendHTML(<<<EOD
|
$info_form->appendHTML(
|
||||||
|
<<<EOD
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-3 control-label">提交文件配置</label>
|
<label class="col-sm-3 control-label">提交文件配置</label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -182,7 +181,8 @@ $esc_submission_requirement
|
|||||||
EOD
|
EOD
|
||||||
);
|
);
|
||||||
$esc_extra_config = HTML::escape(json_encode(json_decode($problem['extra_config']), JSON_PRETTY_PRINT));
|
$esc_extra_config = HTML::escape(json_encode(json_decode($problem['extra_config']), JSON_PRETTY_PRINT));
|
||||||
$info_form->appendHTML(<<<EOD
|
$info_form->appendHTML(
|
||||||
|
<<<EOD
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-3 control-label">其它配置</label>
|
<label class="col-sm-3 control-label">其它配置</label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -195,7 +195,11 @@ $esc_extra_config
|
|||||||
EOD
|
EOD
|
||||||
);
|
);
|
||||||
if (isSuperUser($myUser)) {
|
if (isSuperUser($myUser)) {
|
||||||
$info_form->addVInput('submission_requirement', 'text', '提交文件配置', $problem['submission_requirement'],
|
$info_form->addVInput(
|
||||||
|
'submission_requirement',
|
||||||
|
'text',
|
||||||
|
'提交文件配置',
|
||||||
|
$problem['submission_requirement'],
|
||||||
function ($submission_requirement, &$vdata) {
|
function ($submission_requirement, &$vdata) {
|
||||||
$submission_requirement = json_decode($submission_requirement, true);
|
$submission_requirement = json_decode($submission_requirement, true);
|
||||||
if ($submission_requirement === null) {
|
if ($submission_requirement === null) {
|
||||||
@ -203,8 +207,13 @@ EOD
|
|||||||
}
|
}
|
||||||
$vdata['submission_requirement'] = json_encode($submission_requirement);
|
$vdata['submission_requirement'] = json_encode($submission_requirement);
|
||||||
},
|
},
|
||||||
null);
|
null
|
||||||
$info_form->addVInput('extra_config', 'text', '其它配置', $problem['extra_config'],
|
);
|
||||||
|
$info_form->addVInput(
|
||||||
|
'extra_config',
|
||||||
|
'text',
|
||||||
|
'其它配置',
|
||||||
|
$problem['extra_config'],
|
||||||
function ($extra_config, &$vdata) {
|
function ($extra_config, &$vdata) {
|
||||||
$extra_config = json_decode($extra_config, true);
|
$extra_config = json_decode($extra_config, true);
|
||||||
if ($extra_config === null) {
|
if ($extra_config === null) {
|
||||||
@ -212,250 +221,179 @@ EOD
|
|||||||
}
|
}
|
||||||
$vdata['extra_config'] = json_encode($extra_config);
|
$vdata['extra_config'] = json_encode($extra_config);
|
||||||
},
|
},
|
||||||
null);
|
null
|
||||||
$info_form->handle = function(&$vdata) {
|
);
|
||||||
global $problem;
|
$info_form->handle = function (&$vdata) use ($problem) {
|
||||||
$esc_submission_requirement = DB::escape($vdata['submission_requirement']);
|
DB::update([
|
||||||
$esc_extra_config = DB::escape($vdata['extra_config']);
|
"update problems",
|
||||||
DB::update("update problems set submission_requirement = '$esc_submission_requirement', extra_config = '$esc_extra_config' where id = {$problem['id']}");
|
"set", [
|
||||||
|
"submission_requirement" => $vdata['submission_requirement'],
|
||||||
|
"extra_config" => $vdata['extra_config']
|
||||||
|
], "where", ["id" => $problem['id']]
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
$info_form->no_submit = true;
|
$info_form->no_submit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataDisplayer {
|
|
||||||
public $problem_conf = array();
|
|
||||||
public $data_files = array();
|
|
||||||
public $displayers = array();
|
|
||||||
|
|
||||||
public function __construct($problem_conf = null, $data_files = null) {
|
|
||||||
global $data_dir;
|
|
||||||
|
|
||||||
if (isset($problem_conf)) {
|
|
||||||
foreach ($problem_conf as $key => $val) {
|
|
||||||
$this->problem_conf[$key] = array('val' => $val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($data_files)) {
|
|
||||||
$this->data_files = array_filter(scandir($data_dir), function($x) {
|
|
||||||
return $x !== '.' && $x !== '..' && $x !== 'problem.conf';
|
|
||||||
});
|
|
||||||
natsort($this->data_files);
|
|
||||||
array_unshift($this->data_files, 'problem.conf');
|
|
||||||
} else {
|
|
||||||
$this->data_files = $data_files;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setDisplayer('problem.conf', function($self) {
|
|
||||||
global $info_form;
|
|
||||||
$info_form->printHTML();
|
|
||||||
|
|
||||||
echo '<hr class="my-3">';
|
|
||||||
|
|
||||||
echo '<table class="table table-bordered text-center caption-top">';
|
|
||||||
echo '<caption>problem.conf</caption>';
|
|
||||||
echo '<thead>';
|
|
||||||
echo '<tr>';
|
|
||||||
echo '<th>key</th>';
|
|
||||||
echo '<th>value</th>';
|
|
||||||
echo '</tr>';
|
|
||||||
echo '</thead>';
|
|
||||||
echo '<tbody>';
|
|
||||||
foreach ($self->problem_conf as $key => $info) {
|
|
||||||
if (!isset($info['status'])) {
|
|
||||||
echo '<tr>';
|
|
||||||
echo '<td>', htmlspecialchars($key), '</td>';
|
|
||||||
echo '<td>', htmlspecialchars($info['val']), '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
} elseif ($info['status'] == 'danger') {
|
|
||||||
echo '<tr class="text-danger">';
|
|
||||||
echo '<td>', htmlspecialchars($key), '</td>';
|
|
||||||
echo '<td>', htmlspecialchars($info['val']), ' <span class="bi bi-x-large"></span>', '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo '</tbody>';
|
|
||||||
echo '</table>';
|
|
||||||
|
|
||||||
echoFilePre('problem.conf');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setProblemConfRowStatus($key, $status) {
|
|
||||||
$this->problem_conf[$key]['status'] = $status;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setDisplayer($file_name, $fun) {
|
|
||||||
$this->displayers[$file_name] = $fun;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
public function addDisplayer($file_name, $fun) {
|
|
||||||
$this->data_files[] = $file_name;
|
|
||||||
$this->displayers[$file_name] = $fun;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
public function echoDataFilesList($active_file) {
|
|
||||||
foreach ($this->data_files as $file_name) {
|
|
||||||
echo '<li class="nav-item">';
|
|
||||||
if ($file_name != $active_file) {
|
|
||||||
echo '<a class="nav-link" href="#">';
|
|
||||||
} else {
|
|
||||||
echo '<a class="nav-link active" href="#">';
|
|
||||||
}
|
|
||||||
echo htmlspecialchars($file_name), '</a>', '</li>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public function displayFile($file_name) {
|
|
||||||
global $data_dir;
|
|
||||||
|
|
||||||
if (isset($this->displayers[$file_name])) {
|
|
||||||
$fun = $this->displayers[$file_name];
|
|
||||||
$fun($this);
|
|
||||||
} elseif (in_array($file_name, $this->data_files)) {
|
|
||||||
echoFilePre($file_name);
|
|
||||||
} else {
|
|
||||||
echoFileNotFound($file_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$problem_conf = getUOJConf("$data_dir/problem.conf");
|
$problem_conf = getUOJConf("$data_dir/problem.conf");
|
||||||
|
|
||||||
function getDataDisplayer() {
|
function displayProblemConf(UOJProblemDataDisplayer $self) {
|
||||||
global $data_dir, $problem, $problem_conf;
|
|
||||||
|
|
||||||
$allow_files = array_flip(array_filter(scandir($data_dir), function($x) {
|
|
||||||
return $x !== '.' && $x !== '..';
|
|
||||||
}));
|
|
||||||
|
|
||||||
$getDisplaySrcFunc = function($name) use ($allow_files) {
|
|
||||||
return function() use ($name, $allow_files) {
|
|
||||||
$src_name = $name . '.cpp';
|
|
||||||
if (isset($allow_files[$src_name])) {
|
|
||||||
echoFilePre($src_name);
|
|
||||||
} else {
|
|
||||||
echoFileNotFound($src_name);
|
|
||||||
}
|
|
||||||
if (isset($allow_files[$name])) {
|
|
||||||
echoFilePre($name);
|
|
||||||
} else {
|
|
||||||
echoFileNotFound($name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
if ($problem_conf === -1) {
|
|
||||||
return (new DataDisplayer())->setDisplayer('problem.conf', function() {
|
|
||||||
global $info_form;
|
global $info_form;
|
||||||
$info_form->printHTML();
|
$info_form->printHTML();
|
||||||
|
|
||||||
echo '<hr class="my-3">';
|
echo '<hr class="my-3">';
|
||||||
|
|
||||||
echoFileNotFound('problem.conf');
|
$self->echoProblemConfTable();
|
||||||
});
|
|
||||||
|
$self->echoFilePre('problem.conf');
|
||||||
}
|
}
|
||||||
if ($problem_conf === -2) {
|
|
||||||
return (new DataDisplayer())->setDisplayer('problem.conf', function() {
|
function addTestsTab(UOJProblemDataDisplayer $disp, array $problem_conf) {
|
||||||
|
$n_tests = getUOJConfVal($problem_conf, 'n_tests', 10);
|
||||||
|
if (!validateUInt($n_tests)) {
|
||||||
|
$disp->setProblemConfRowStatus('n_tests', 'danger');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inputs = [];
|
||||||
|
$outputs = [];
|
||||||
|
for ($num = 1; $num <= $n_tests; $num++) {
|
||||||
|
$inputs[$num] = getUOJProblemInputFileName($problem_conf, $num);
|
||||||
|
$outputs[$num] = getUOJProblemOutputFileName($problem_conf, $num);
|
||||||
|
unset($disp->rest_data_files[$inputs[$num]]);
|
||||||
|
unset($disp->rest_data_files[$outputs[$num]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$disp->addTab('tests', function ($self) use ($inputs, $outputs, $n_tests) {
|
||||||
|
for ($num = 1; $num <= $n_tests; $num++) {
|
||||||
|
echo '<div class="row">';
|
||||||
|
echo '<div class="col-md-6">';
|
||||||
|
$self->echoFilePre($inputs[$num]);
|
||||||
|
echo '</div>';
|
||||||
|
echo '<div class="col-md-6">';
|
||||||
|
$self->echoFilePre($outputs[$num]);
|
||||||
|
echo '</div>';
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addExTestsTab(UOJProblemDataDisplayer $disp, array $problem_conf) {
|
||||||
|
$has_extra_tests = !(isset($problem_conf['submit_answer']) && $problem_conf['submit_answer'] == 'on');
|
||||||
|
|
||||||
|
if (!$has_extra_tests) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$n_ex_tests = getUOJConfVal($problem_conf, 'n_ex_tests', 0);
|
||||||
|
if (!validateUInt($n_ex_tests)) {
|
||||||
|
$disp->setProblemConfRowStatus('n_ex_tests', 'danger');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($n_ex_tests == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inputs = [];
|
||||||
|
$outputs = [];
|
||||||
|
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
||||||
|
$inputs[$num] = getUOJProblemExtraInputFileName($problem_conf, $num);
|
||||||
|
$outputs[$num] = getUOJProblemExtraOutputFileName($problem_conf, $num);
|
||||||
|
unset($disp->rest_data_files[$inputs[$num]]);
|
||||||
|
unset($disp->rest_data_files[$outputs[$num]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$disp->addTab('extra tests', function ($self) use ($inputs, $outputs, $n_ex_tests) {
|
||||||
|
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
||||||
|
echo '<div class="row">';
|
||||||
|
echo '<div class="col-md-6">';
|
||||||
|
$self->echoFilePre($inputs[$num]);
|
||||||
|
echo '</div>';
|
||||||
|
echo '<div class="col-md-6">';
|
||||||
|
$self->echoFilePre($outputs[$num]);
|
||||||
|
echo '</div>';
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSrcTab(UOJProblemDataDisplayer $disp, $tab_name, string $name) {
|
||||||
|
$src = UOJLang::findSourceCode($name, '', [$disp, 'isFile']);
|
||||||
|
if ($src !== false) {
|
||||||
|
unset($disp->rest_data_files[$src['path']]);
|
||||||
|
}
|
||||||
|
unset($disp->rest_data_files[$name]);
|
||||||
|
|
||||||
|
$disp->addTab($tab_name, function ($self) use ($name, $src) {
|
||||||
|
if ($src !== false) {
|
||||||
|
$self->echoFilePre($src['path']);
|
||||||
|
}
|
||||||
|
$self->echoFilePre($name);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDataDisplayer() {
|
||||||
|
$disp = new UOJProblemDataDisplayer(UOJProblem::cur());
|
||||||
|
|
||||||
|
$problem_conf = UOJProblem::cur()->getProblemConfArray();
|
||||||
|
if ($problem_conf === -1) {
|
||||||
|
return $disp->addTab('problem.conf', function ($self) {
|
||||||
global $info_form;
|
global $info_form;
|
||||||
|
|
||||||
|
$info_form->printHTML();
|
||||||
|
|
||||||
|
echo '<hr class="my-3">';
|
||||||
|
|
||||||
|
$self->echoFileNotFound('problem.conf');
|
||||||
|
});
|
||||||
|
} elseif ($problem_conf === -2) {
|
||||||
|
return $disp->addTab('problem.conf', function ($self) {
|
||||||
|
global $info_form;
|
||||||
|
|
||||||
$info_form->printHTML();
|
$info_form->printHTML();
|
||||||
|
|
||||||
echo '<hr class="my-3">';
|
echo '<hr class="my-3">';
|
||||||
|
|
||||||
echo '<div class="fw-bold text-danger">problem.conf 文件格式有误</div>';
|
echo '<div class="fw-bold text-danger">problem.conf 文件格式有误</div>';
|
||||||
echoFilePre('problem.conf');
|
$self->echoFilePre('problem.conf');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$disp->setProblemConf($problem_conf);
|
||||||
|
unset($disp->rest_data_files['problem.conf']);
|
||||||
|
unset($disp->rest_data_files['download.zip']);
|
||||||
|
$disp->addTab('problem.conf', 'displayProblemConf');
|
||||||
|
addTestsTab($disp, $problem_conf);
|
||||||
|
addExTestsTab($disp, $problem_conf);
|
||||||
|
|
||||||
$judger_name = getUOJConfVal($problem_conf, 'use_builtin_judger', null);
|
$judger_name = getUOJConfVal($problem_conf, 'use_builtin_judger', null);
|
||||||
if (!isset($problem_conf['use_builtin_judger'])) {
|
if ($judger_name === null) {
|
||||||
return new DataDisplayer($problem_conf);
|
return $disp;
|
||||||
}
|
} elseif ($judger_name === 'on') {
|
||||||
if ($problem_conf['use_builtin_judger'] == 'on') {
|
|
||||||
$n_tests = getUOJConfVal($problem_conf, 'n_tests', 10);
|
|
||||||
if (!validateUInt($n_tests)) {
|
|
||||||
return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('n_tests', 'danger');
|
|
||||||
}
|
|
||||||
|
|
||||||
$has_extra_tests = !(isset($problem_conf['submit_answer']) && $problem_conf['submit_answer'] == 'on');
|
|
||||||
|
|
||||||
$data_disp = new DataDisplayer($problem_conf, array('problem.conf'));
|
|
||||||
$data_disp->addDisplayer('tests',
|
|
||||||
function($self) use ($problem_conf, $allow_files, $n_tests, $n_ex_tests) {
|
|
||||||
for ($num = 1; $num <= $n_tests; $num++) {
|
|
||||||
$input_file_name = getUOJProblemInputFileName($problem_conf, $num);
|
|
||||||
$output_file_name = getUOJProblemOutputFileName($problem_conf, $num);
|
|
||||||
echo '<div class="row">';
|
|
||||||
echo '<div class="col-md-6">';
|
|
||||||
if (isset($allow_files[$input_file_name])) {
|
|
||||||
echoFilePre($input_file_name);
|
|
||||||
} else {
|
|
||||||
echoFileNotFound($input_file_name);
|
|
||||||
}
|
|
||||||
echo '</div>';
|
|
||||||
echo '<div class="col-md-6">';
|
|
||||||
if (isset($allow_files[$output_file_name])) {
|
|
||||||
echoFilePre($output_file_name);
|
|
||||||
} else {
|
|
||||||
echoFileNotFound($output_file_name);
|
|
||||||
}
|
|
||||||
echo '</div>';
|
|
||||||
echo '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
if ($has_extra_tests) {
|
|
||||||
$n_ex_tests = getUOJConfVal($problem_conf, 'n_ex_tests', 0);
|
|
||||||
if (!validateUInt($n_ex_tests)) {
|
|
||||||
return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('n_ex_tests', 'danger');
|
|
||||||
}
|
|
||||||
|
|
||||||
$data_disp->addDisplayer('extra tests',
|
|
||||||
function($self) use ($problem_conf, $allow_files, $n_tests, $n_ex_tests) {
|
|
||||||
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
|
||||||
$input_file_name = getUOJProblemExtraInputFileName($problem_conf, $num);
|
|
||||||
$output_file_name = getUOJProblemExtraOutputFileName($problem_conf, $num);
|
|
||||||
echo '<div class="row">';
|
|
||||||
echo '<div class="col-md-6">';
|
|
||||||
if (isset($allow_files[$input_file_name])) {
|
|
||||||
echoFilePre($input_file_name);
|
|
||||||
} else {
|
|
||||||
echoFileNotFound($input_file_name);
|
|
||||||
}
|
|
||||||
echo '</div>';
|
|
||||||
echo '<div class="col-md-6">';
|
|
||||||
if (isset($allow_files[$output_file_name])) {
|
|
||||||
echoFilePre($output_file_name);
|
|
||||||
} else {
|
|
||||||
echoFileNotFound($output_file_name);
|
|
||||||
}
|
|
||||||
echo '</div>';
|
|
||||||
echo '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($problem_conf['interaction_mode'])) {
|
if (!isset($problem_conf['interaction_mode'])) {
|
||||||
if (isset($problem_conf['use_builtin_checker'])) {
|
if (isset($problem_conf['use_builtin_checker'])) {
|
||||||
$data_disp->addDisplayer('checker', function($self) {
|
$disp->addTab('checker', function ($self) {
|
||||||
echo '<h5>use builtin checker : ', $self->problem_conf['use_builtin_checker']['val'], '</h5>';
|
echo '<h4>use builtin checker : ', $self->problem_conf['use_builtin_checker']['val'], '</h4>';
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$data_disp->addDisplayer('checker', $getDisplaySrcFunc('chk'));
|
addSrcTab($disp, 'checker', 'chk');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($problem['hackable']) {
|
if (UOJProblem::info('hackable')) {
|
||||||
$data_disp->addDisplayer('standard', $getDisplaySrcFunc('std'));
|
addSrcTab($disp, 'standard', 'std');
|
||||||
$data_disp->addDisplayer('validator', $getDisplaySrcFunc('val'));
|
addSrcTab($disp, 'validator', 'val');
|
||||||
}
|
}
|
||||||
if (isset($problem_conf['interaction_mode'])) {
|
if (isset($problem_conf['interaction_mode'])) {
|
||||||
$data_disp->addDisplayer('interactor', $getDisplaySrcFunc('interactor'));
|
addSrcTab($disp, 'interactor', 'interactor');
|
||||||
}
|
}
|
||||||
return $data_disp;
|
return $disp;
|
||||||
} else {
|
} else {
|
||||||
return (new DataDisplayer($problem_conf))->setProblemConfRowStatus('use_builtin_judger', 'danger');
|
return $disp->setProblemConfRowStatus('use_builtin_judger', 'danger');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,9 +408,8 @@ EOD
|
|||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
$hackable_form = new UOJForm('hackable');
|
$hackable_form = new UOJBs4Form('hackable');
|
||||||
$hackable_form->handle = function() {
|
$hackable_form->handle = function () use ($problem) {
|
||||||
global $problem;
|
|
||||||
$problem['hackable'] = !$problem['hackable'];
|
$problem['hackable'] = !$problem['hackable'];
|
||||||
$ret = dataSyncProblemData($problem);
|
$ret = dataSyncProblemData($problem);
|
||||||
if ($ret) {
|
if ($ret) {
|
||||||
@ -480,17 +417,20 @@ EOD
|
|||||||
}
|
}
|
||||||
|
|
||||||
$hackable = $problem['hackable'] ? 1 : 0;
|
$hackable = $problem['hackable'] ? 1 : 0;
|
||||||
DB::query("update problems set hackable = $hackable where id = ${problem['id']}");
|
DB::update([
|
||||||
|
"update problems",
|
||||||
|
"set", ["hackable" => $hackable],
|
||||||
|
"where", ["id" => $problem['id']]
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$hackable_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100';
|
$hackable_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100';
|
||||||
$hackable_form->submit_button_config['text'] = $problem['hackable'] ? '禁用 Hack 功能' : '启用 Hack 功能';
|
$hackable_form->submit_button_config['text'] = $problem['hackable'] ? '禁用 Hack 功能' : '启用 Hack 功能';
|
||||||
$hackable_form->submit_button_config['smart_confirm'] = '';
|
$hackable_form->submit_button_config['smart_confirm'] = '';
|
||||||
|
|
||||||
$data_form = new UOJForm('data');
|
$data_form = new UOJBs4Form('data');
|
||||||
$data_form->handle = function() {
|
$data_form->handle = function () use ($problem) {
|
||||||
global $problem, $myUser;
|
|
||||||
set_time_limit(60 * 5);
|
set_time_limit(60 * 5);
|
||||||
$ret = dataSyncProblemData($problem, $myUser);
|
$ret = dataSyncProblemData($problem, Auth::user());
|
||||||
if ($ret) {
|
if ($ret) {
|
||||||
becomeMsgPage('<div>' . $ret . '</div><a href="/problem/' . $problem['id'] . '/manage/data">返回</a>');
|
becomeMsgPage('<div>' . $ret . '</div><a href="/problem/' . $problem['id'] . '/manage/data">返回</a>');
|
||||||
}
|
}
|
||||||
@ -499,7 +439,7 @@ EOD
|
|||||||
$data_form->submit_button_config['text'] = '检验配置并同步数据';
|
$data_form->submit_button_config['text'] = '检验配置并同步数据';
|
||||||
$data_form->submit_button_config['smart_confirm'] = '';
|
$data_form->submit_button_config['smart_confirm'] = '';
|
||||||
|
|
||||||
$clear_data_form = new UOJForm('clear_data');
|
$clear_data_form = new UOJBs4Form('clear_data');
|
||||||
$clear_data_form->handle = function () {
|
$clear_data_form->handle = function () {
|
||||||
global $problem;
|
global $problem;
|
||||||
dataClearProblemData($problem);
|
dataClearProblemData($problem);
|
||||||
@ -508,37 +448,39 @@ EOD
|
|||||||
$clear_data_form->submit_button_config['text'] = '清空题目数据';
|
$clear_data_form->submit_button_config['text'] = '清空题目数据';
|
||||||
$clear_data_form->submit_button_config['smart_confirm'] = '';
|
$clear_data_form->submit_button_config['smart_confirm'] = '';
|
||||||
|
|
||||||
$rejudge_form = new UOJForm('rejudge');
|
$rejudge_form = new UOJBs4Form('rejudge');
|
||||||
$rejudge_form->handle = function () {
|
$rejudge_form->handle = function () {
|
||||||
global $problem;
|
UOJSubmission::rejudgeProblem(UOJProblem::cur());
|
||||||
rejudgeProblem($problem);
|
|
||||||
};
|
};
|
||||||
$rejudge_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
$rejudge_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
||||||
$rejudge_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
$rejudge_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||||||
$rejudge_form->submit_button_config['text'] = '重测该题';
|
$rejudge_form->submit_button_config['text'] = '重测该题';
|
||||||
$rejudge_form->submit_button_config['smart_confirm'] = '';
|
$rejudge_form->submit_button_config['smart_confirm'] = '';
|
||||||
|
|
||||||
$rejudgege97_form = new UOJForm('rejudgege97');
|
$rejudgege97_form = new UOJBs4Form('rejudgege97');
|
||||||
$rejudgege97_form->handle = function () {
|
$rejudgege97_form->handle = function () {
|
||||||
global $problem;
|
UOJSubmission::rejudgeProblemGe97(UOJProblem::cur());
|
||||||
rejudgeProblemGe97($problem);
|
|
||||||
};
|
};
|
||||||
$rejudgege97_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
$rejudgege97_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
||||||
$rejudgege97_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
$rejudgege97_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||||||
$rejudgege97_form->submit_button_config['text'] = '重测 >=97 的程序';
|
$rejudgege97_form->submit_button_config['text'] = '重测 >=97 的程序';
|
||||||
$rejudgege97_form->submit_button_config['smart_confirm'] = '';
|
$rejudgege97_form->submit_button_config['smart_confirm'] = '';
|
||||||
|
|
||||||
$view_type_form = new UOJForm('view_type');
|
$view_type_form = new UOJBs4Form('view_type');
|
||||||
$view_type_form->addVSelect('view_content_type',
|
$view_type_form->addVSelect(
|
||||||
array('NONE' => '禁止',
|
'view_content_type',
|
||||||
|
array(
|
||||||
|
'NONE' => '禁止',
|
||||||
'ALL_AFTER_AC' => 'AC后',
|
'ALL_AFTER_AC' => 'AC后',
|
||||||
'ALL' => '所有人'
|
'ALL' => '所有人'
|
||||||
),
|
),
|
||||||
'查看提交文件:',
|
'查看提交文件:',
|
||||||
$problem_extra_config['view_content_type']
|
$problem_extra_config['view_content_type']
|
||||||
);
|
);
|
||||||
$view_type_form->addVSelect('view_all_details_type',
|
$view_type_form->addVSelect(
|
||||||
array('NONE' => '禁止',
|
'view_all_details_type',
|
||||||
|
array(
|
||||||
|
'NONE' => '禁止',
|
||||||
'SELF' => '仅自己',
|
'SELF' => '仅自己',
|
||||||
'ALL_AFTER_AC' => 'AC后',
|
'ALL_AFTER_AC' => 'AC后',
|
||||||
'ALL' => '所有人'
|
'ALL' => '所有人'
|
||||||
@ -546,8 +488,10 @@ EOD
|
|||||||
'查看全部详细信息:',
|
'查看全部详细信息:',
|
||||||
$problem_extra_config['view_all_details_type']
|
$problem_extra_config['view_all_details_type']
|
||||||
);
|
);
|
||||||
$view_type_form->addVSelect('view_details_type',
|
$view_type_form->addVSelect(
|
||||||
array('NONE' => '禁止',
|
'view_details_type',
|
||||||
|
array(
|
||||||
|
'NONE' => '禁止',
|
||||||
'SELF' => '仅自己',
|
'SELF' => '仅自己',
|
||||||
'ALL_AFTER_AC' => 'AC后',
|
'ALL_AFTER_AC' => 'AC后',
|
||||||
'ALL' => '所有人'
|
'ALL' => '所有人'
|
||||||
@ -557,26 +501,36 @@ EOD
|
|||||||
);
|
);
|
||||||
$view_type_form->handle = function () {
|
$view_type_form->handle = function () {
|
||||||
global $problem, $problem_extra_config;
|
global $problem, $problem_extra_config;
|
||||||
|
|
||||||
$config = $problem_extra_config;
|
$config = $problem_extra_config;
|
||||||
$config['view_content_type'] = $_POST['view_content_type'];
|
$config['view_content_type'] = $_POST['view_content_type'];
|
||||||
$config['view_all_details_type'] = $_POST['view_all_details_type'];
|
$config['view_all_details_type'] = $_POST['view_all_details_type'];
|
||||||
$config['view_details_type'] = $_POST['view_details_type'];
|
$config['view_details_type'] = $_POST['view_details_type'];
|
||||||
$esc_config = DB::escape(json_encode($config));
|
$esc_config = json_encode($config);
|
||||||
DB::query("update problems set extra_config = '$esc_config' where id = '{$problem['id']}'");
|
|
||||||
|
DB::update([
|
||||||
|
"update problems",
|
||||||
|
"set", ["extra_config" => $esc_config],
|
||||||
|
"where", ["id" => $problem['id']]
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
$view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
||||||
|
|
||||||
$solution_view_type_form = new UOJForm('solution_view_type');
|
$solution_view_type_form = new UOJBs4Form('solution_view_type');
|
||||||
$solution_view_type_form->addVSelect('view_solution_type',
|
$solution_view_type_form->addVSelect(
|
||||||
array('NONE' => '禁止',
|
'view_solution_type',
|
||||||
|
array(
|
||||||
|
'NONE' => '禁止',
|
||||||
'ALL_AFTER_AC' => 'AC后',
|
'ALL_AFTER_AC' => 'AC后',
|
||||||
'ALL' => '所有人'
|
'ALL' => '所有人'
|
||||||
),
|
),
|
||||||
'查看题解:',
|
'查看题解:',
|
||||||
$problem_extra_config['view_solution_type']
|
$problem_extra_config['view_solution_type']
|
||||||
);
|
);
|
||||||
$solution_view_type_form->addVSelect('submit_solution_type',
|
$solution_view_type_form->addVSelect(
|
||||||
array('NONE' => '禁止',
|
'submit_solution_type',
|
||||||
|
array(
|
||||||
|
'NONE' => '禁止',
|
||||||
'ALL_AFTER_AC' => 'AC后',
|
'ALL_AFTER_AC' => 'AC后',
|
||||||
'ALL' => '所有人'
|
'ALL' => '所有人'
|
||||||
),
|
),
|
||||||
@ -585,23 +539,34 @@ EOD
|
|||||||
);
|
);
|
||||||
$solution_view_type_form->handle = function () {
|
$solution_view_type_form->handle = function () {
|
||||||
global $problem, $problem_extra_config;
|
global $problem, $problem_extra_config;
|
||||||
|
|
||||||
$config = $problem_extra_config;
|
$config = $problem_extra_config;
|
||||||
$config['view_solution_type'] = $_POST['view_solution_type'];
|
$config['view_solution_type'] = $_POST['view_solution_type'];
|
||||||
$config['submit_solution_type'] = $_POST['submit_solution_type'];
|
$config['submit_solution_type'] = $_POST['submit_solution_type'];
|
||||||
$esc_config = DB::escape(json_encode($config));
|
$esc_config = DB::escape(json_encode($config));
|
||||||
DB::query("update problems set extra_config = '$esc_config' where id = '{$problem['id']}'");
|
|
||||||
|
DB::update([
|
||||||
|
"update problems",
|
||||||
|
"set", ["extra_config" => $esc_config],
|
||||||
|
"where", ["id" => $problem['id']]
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$solution_view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
$solution_view_type_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
||||||
|
|
||||||
$difficulty_form = new UOJForm('difficulty');
|
$difficulty_form = new UOJBs4Form('difficulty');
|
||||||
$difficulty_form->addVInput('difficulty', 'text', '难度系数', $problem_extra_config['difficulty'],
|
$difficulty_form->addVInput(
|
||||||
|
'difficulty',
|
||||||
|
'text',
|
||||||
|
'难度系数',
|
||||||
|
$problem_extra_config['difficulty'],
|
||||||
function ($str) {
|
function ($str) {
|
||||||
if (!is_numeric($str)) {
|
if (!is_numeric($str)) {
|
||||||
return '难度系数必须是一个数字';
|
return '难度系数必须是一个数字';
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null);
|
null
|
||||||
|
);
|
||||||
$difficulty_form->handle = function () {
|
$difficulty_form->handle = function () {
|
||||||
global $problem, $problem_extra_config;
|
global $problem, $problem_extra_config;
|
||||||
$config = $problem_extra_config;
|
$config = $problem_extra_config;
|
||||||
@ -612,51 +577,62 @@ EOD
|
|||||||
$difficulty_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
$difficulty_form->submit_button_config['class_str'] = 'btn btn-warning d-block w-100 mt-2';
|
||||||
|
|
||||||
if ($problem['hackable']) {
|
if ($problem['hackable']) {
|
||||||
$test_std_form = new UOJForm('test_std');
|
$test_std_form = new UOJBs4Form('test_std');
|
||||||
$test_std_form->handle = function() {
|
$test_std_form->handle = function () use ($problem, $data_disp) {
|
||||||
global $myUser, $problem;
|
$user_std = UOJUser::query('std');
|
||||||
|
|
||||||
$user_std = queryUser('std');
|
|
||||||
if (!$user_std) {
|
if (!$user_std) {
|
||||||
becomeMsgPage('请建立 std 账号。');
|
UOJResponse::message('Please create an user named "std"');
|
||||||
}
|
}
|
||||||
|
|
||||||
$requirement = json_decode($problem['submission_requirement'], true);
|
$requirement = json_decode($problem['submission_requirement'], true);
|
||||||
|
|
||||||
$zip_file_name = uojRandAvaiableSubmissionFileName();
|
|
||||||
|
$src_std = UOJLang::findSourceCode('std', '', [$data_disp, 'isFile']);
|
||||||
|
if ($src_std === false) {
|
||||||
|
UOJResponse::message('未找到std!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$zip_file_name = FS::randomAvailableSubmissionFileName();
|
||||||
$zip_file = new ZipArchive();
|
$zip_file = new ZipArchive();
|
||||||
if ($zip_file->open(UOJContext::storagePath() . $zip_file_name, ZipArchive::CREATE) !== true) {
|
if ($zip_file->open(UOJContext::storagePath() . $zip_file_name, ZipArchive::CREATE) !== true) {
|
||||||
becomeMsgPage('提交失败');
|
UOJResponse::message('提交失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = array();
|
$content = [];
|
||||||
$content['file_name'] = $zip_file_name;
|
$content['file_name'] = $zip_file_name;
|
||||||
$content['config'] = array();
|
$content['config'] = [];
|
||||||
foreach ($requirement as $req) {
|
|
||||||
if ($req['type'] == "source code") {
|
|
||||||
$content['config'][] = array("{$req['name']}_language", "C++");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tot_size = 0;
|
$tot_size = 0;
|
||||||
foreach ($requirement as $req) {
|
foreach ($requirement as $req) {
|
||||||
$zip_file->addFile("/var/uoj_data/{$problem['id']}/std.cpp", $req['file_name']);
|
if ($req['type'] == "source code") {
|
||||||
|
$content['config'][] = ["{$req['name']}_language", $src_std['lang']];
|
||||||
|
if ($zip_file->addFromString($req['file_name'], $data_disp->getFile($src_std['path'])) === false) {
|
||||||
|
$zip_file->close();
|
||||||
|
unlink(UOJContext::storagePath() . $zip_file_name);
|
||||||
|
UOJResponse::message('提交失败');
|
||||||
|
}
|
||||||
$tot_size += $zip_file->statName($req['file_name'])['size'];
|
$tot_size += $zip_file->statName($req['file_name'])['size'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$zip_file->close();
|
$zip_file->close();
|
||||||
|
|
||||||
$content['config'][] = array('validate_input_before_test', 'on');
|
$content['config'][] = ['validate_input_before_test', 'on'];
|
||||||
$content['config'][] = array('problem_id', $problem['id']);
|
$content['config'][] = ['problem_id', $problem['id']];
|
||||||
$esc_content = DB::escape(json_encode($content));
|
$esc_content = json_encode($content);
|
||||||
$esc_language = DB::escape('C++');
|
|
||||||
|
|
||||||
$result = array();
|
$result = [];
|
||||||
$result['status'] = "Waiting";
|
$result['status'] = "Waiting";
|
||||||
$result_json = json_encode($result);
|
$result_json = json_encode($result);
|
||||||
$is_hidden = $problem['is_hidden'] ? 1 : 0;
|
$is_hidden = $problem['is_hidden'] ? 1 : 0;
|
||||||
|
|
||||||
DB::insert("insert into submissions (problem_id, submit_time, submitter, content, language, tot_size, status, result, is_hidden) values ({$problem['id']}, now(), '{$user_std['username']}', '$esc_content', '$esc_language', $tot_size, '{$result['status']}', '$result_json', $is_hidden)");
|
DB::insert([
|
||||||
|
"insert into submissions",
|
||||||
|
"(problem_id, submit_time, submitter, content, language, tot_size, status, result, is_hidden)",
|
||||||
|
"values", DB::tuple([
|
||||||
|
$problem['id'], DB::now(), $user_std['username'], $esc_content,
|
||||||
|
$src_std['lang'], $tot_size, $result['status'], $result_json, $is_hidden
|
||||||
|
])
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$test_std_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
$test_std_form->succ_href = "/submissions?problem_id={$problem['id']}";
|
||||||
$test_std_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
$test_std_form->submit_button_config['class_str'] = 'btn btn-danger d-block w-100';
|
||||||
@ -681,7 +657,7 @@ EOD
|
|||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-12 col-lg-9">
|
<div class="col-12 col-lg-9">
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
#<?= $problem['id'] ?>. <?= $problem['title'] ?> 管理
|
#<?= $problem['id'] ?>. <?= $problem['title'] ?> 管理
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -706,7 +682,7 @@ EOD
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header" id="div-file_list">
|
<div class="card-header" id="div-file_list">
|
||||||
<ul class="nav nav-tabs card-header-tabs">
|
<ul class="nav nav-tabs card-header-tabs">
|
||||||
<?php $data_disp->echoDataFilesList('problem.conf'); ?>
|
<?php $data_disp->echoAllTabs('problem.conf'); ?>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -773,7 +749,7 @@ EOD
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
评价:<?= getClickZanBlock('P', $problem['id'], $problem['zan']) ?>
|
评价:<?= ClickZans::getBlock('P', $problem['id'], $problem['zan']) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -2,49 +2,49 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
UOJProblem::cur()->userCanManage(Auth::user()) || UOJResponse::page403();
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
$managers_form = newAddDelCmdForm(
|
||||||
become404Page();
|
'managers',
|
||||||
}
|
'validateUserAndStoreByUsername',
|
||||||
if (!hasProblemPermission($myUser, $problem)) {
|
function ($type, $username, &$vdata) {
|
||||||
become403Page();
|
$user = $vdata['user'][$username];
|
||||||
}
|
|
||||||
|
|
||||||
$managers_form = newAddDelCmdForm('managers',
|
|
||||||
function($username) {
|
|
||||||
if (!validateUsername($username) || !queryUser($username)) {
|
|
||||||
return "不存在名为{$username}的用户";
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
function($type, $username) {
|
|
||||||
global $problem;
|
|
||||||
if ($type == '+') {
|
if ($type == '+') {
|
||||||
DB::query("insert into problems_permissions (problem_id, username) values (${problem['id']}, '$username')");
|
DB::insert([
|
||||||
|
"insert into problems_permissions",
|
||||||
|
"(problem_id, username)",
|
||||||
|
"values", DB::tuple([UOJProblem::info('id'), $user['username']])
|
||||||
|
]);
|
||||||
} else if ($type == '-') {
|
} else if ($type == '-') {
|
||||||
DB::query("delete from problems_permissions where problem_id = ${problem['id']} and username = '$username'");
|
DB::delete([
|
||||||
|
"delete from problems_permissions",
|
||||||
|
"where", [
|
||||||
|
"problem_id" => UOJProblem::info('id'),
|
||||||
|
"username" => $user['username']
|
||||||
|
]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
$managers_form->runAtServer();
|
$managers_form->runAtServer();
|
||||||
|
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
if (isSuperUser($myUser)) {
|
||||||
$update_uploader_form = new UOJForm('update_uploader');
|
$update_uploader_form = new UOJBs4Form('update_uploader');
|
||||||
$update_uploader_form->addInput('new_uploader_username', 'text', '用户名', $problem['uploader'] ?: 'root',
|
$update_uploader_form->addInput(
|
||||||
function ($x) {
|
'new_uploader_username',
|
||||||
if (!validateUsername($x)) {
|
'text',
|
||||||
return '用户名不合法';
|
'用户名',
|
||||||
}
|
$problem['uploader'] ?: 'root',
|
||||||
|
function ($username, &$vdata) {
|
||||||
if (!queryUser($x)) {
|
if (!UOJUser::query($username)) {
|
||||||
return '用户不存在';
|
return '用户不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$vdata['username'] = $username;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
@ -52,39 +52,38 @@
|
|||||||
$update_uploader_form->submit_button_config['align'] = 'compressed';
|
$update_uploader_form->submit_button_config['align'] = 'compressed';
|
||||||
$update_uploader_form->submit_button_config['text'] = '修改上传者';
|
$update_uploader_form->submit_button_config['text'] = '修改上传者';
|
||||||
$update_uploader_form->submit_button_config['class_str'] = 'mt-2 btn btn-warning';
|
$update_uploader_form->submit_button_config['class_str'] = 'mt-2 btn btn-warning';
|
||||||
$update_uploader_form->handle = function() {
|
$update_uploader_form->handle = function (&$vdata) {
|
||||||
global $problem;
|
DB::update([
|
||||||
|
"update problems",
|
||||||
$username = $_POST['new_uploader_username'];
|
"set", ["uploader" => $vdata['username']],
|
||||||
|
"where", ["id" => UOJProblem::info('id')]
|
||||||
DB::query("update problems set uploader = '{$username}' where id = {$problem['id']}");
|
]);
|
||||||
};
|
};
|
||||||
$update_uploader_form->runAtServer();
|
$update_uploader_form->runAtServer();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(HTML::stripTags($problem['title']) . ' - 管理者 - 题目管理') ?>
|
<?php echoUOJPageHeader('管理者 - ' . HTML::stripTags($problem['title'])) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
<h1>
|
||||||
<h1 class="h2">
|
<?= UOJProblem::cur()->getTitle() ?> 管理
|
||||||
#<?= $problem['id'] ?>. <?= $problem['title'] ?> 管理
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<ul class="nav nav-pills my-3" role="tablist">
|
<ul class="nav nav-pills my-3" role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/manage/statement" role="tab">
|
||||||
题面
|
题面
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/problem/<?= $problem['id'] ?>/manage/managers" role="tab">
|
<a class="nav-link active" href="/problem/<?= UOJProblem::info('id') ?>/manage/managers" role="tab">
|
||||||
管理者
|
管理者
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/data" role="tab">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/manage/data" role="tab">
|
||||||
数据
|
数据
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -103,8 +102,11 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php
|
<?php
|
||||||
$row_id = 0;
|
$row_id = 0;
|
||||||
$result = DB::query("select username from problems_permissions where problem_id = ${problem['id']}");
|
$res = DB::selectAll([
|
||||||
while ($row = DB::fetch($result, MYSQLI_ASSOC)) {
|
"select username from problems_permissions",
|
||||||
|
"where", ["problem_id" => UOJProblem::info('id')]
|
||||||
|
]);
|
||||||
|
foreach ($res as $row) {
|
||||||
$row_id++;
|
$row_id++;
|
||||||
echo '<tr>', '<td>', $row_id, '</td>', '<td>', getUserLink($row['username']), '</td>', '</tr>';
|
echo '<tr>', '<td>', $row_id, '</td>', '<td>', getUserLink($row['username']), '</td>', '</tr>';
|
||||||
}
|
}
|
||||||
@ -132,19 +134,19 @@
|
|||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a href="/problem/<?= $problem['id'] ?>" class="nav-link" role="tab">
|
<a href="/problem/<?= UOJProblem::info('id') ?>" class="nav-link" role="tab">
|
||||||
<i class="bi bi-journal-text"></i>
|
<i class="bi bi-journal-text"></i>
|
||||||
<?= UOJLocale::get('problems::statement') ?>
|
<?= UOJLocale::get('problems::statement') ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a href="/problem/<?= $problem['id'] ?>/solutions" class="nav-link" role="tab">
|
<a href="/problem/<?= UOJProblem::info('id') ?>/solutions" class="nav-link" role="tab">
|
||||||
<i class="bi bi-journal-bookmark"></i>
|
<i class="bi bi-journal-bookmark"></i>
|
||||||
<?= UOJLocale::get('problems::solutions') ?>
|
<?= UOJLocale::get('problems::solutions') ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/statistics">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/statistics">
|
||||||
<i class="bi bi-graph-up"></i>
|
<i class="bi bi-graph-up"></i>
|
||||||
<?= UOJLocale::get('problems::statistics') ?>
|
<?= UOJLocale::get('problems::statistics') ?>
|
||||||
</a>
|
</a>
|
||||||
@ -157,11 +159,11 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
评价:<?= getClickZanBlock('P', $problem['id'], $problem['zan']) ?>
|
评价:<?= ClickZans::getBlock('P', $problem['id'], $problem['zan']) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php uojIncludeView('sidebar', array()) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
<!-- end right col -->
|
<!-- end right col -->
|
||||||
|
|
||||||
|
@ -4,23 +4,22 @@
|
|||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
requirePHPLib('data');
|
requirePHPLib('data');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (isSuperUser($myUser) || isProblemManager($myUser) || isProblemUploader($myUser)) {
|
if (isSuperUser($myUser) || isProblemManager($myUser) || isProblemUploader($myUser)) {
|
||||||
$new_problem_form = new UOJForm('new_problem');
|
$new_problem_form = new UOJBs4Form('new_problem');
|
||||||
$new_problem_form->handle = function () {
|
$new_problem_form->handle = function () {
|
||||||
global $myUser;
|
DB::insert([
|
||||||
|
"insert into problems",
|
||||||
DB::query("insert into problems (title, uploader, is_hidden, submission_requirement) values ('New Problem', '{$myUser['username']}', 1, '{}')");
|
"(title, uploader, is_hidden, submission_requirement)",
|
||||||
|
"values", DB::tuple(["New Problem", Auth::id(), 1, "{}"])
|
||||||
|
]);
|
||||||
$id = DB::insert_id();
|
$id = DB::insert_id();
|
||||||
DB::query("insert into problems_contents (id, statement, statement_md) values ($id, '', '')");
|
DB::insert([
|
||||||
|
"insert into problems_contents",
|
||||||
|
"(id, statement, statement_md)",
|
||||||
|
"values", DB::tuple([$id, "", "## 题目描述\n\n## 输入格式\n\n## 输出格式\n\n## 输入输出样例\n\n### 输入样例 #1\n\n<!-- 请将样例用代码块包裹起来 -->\n\n### 输出样例 #1\n\n<!-- 请将样例用代码块包裹起来 -->\n\n### 样例解释 #1\n\n<!--\n后续添加样例时格式类似,如果声明大样例的话可以使用这种格式:\n\n### 样例 #2\n\n见右侧「附件下载」中的 `ex_data2.in/out`。\n\n-->\n\n## 数据范围与约定\n\n<!-- 数据范围与一些其他提示 -->\n"])
|
||||||
|
]);
|
||||||
dataNewProblem($id);
|
dataNewProblem($id);
|
||||||
};
|
};
|
||||||
$new_problem_form->submit_button_config['align'] = 'right';
|
$new_problem_form->submit_button_config['align'] = 'right';
|
||||||
@ -31,92 +30,95 @@
|
|||||||
$new_problem_form->runAtServer();
|
$new_problem_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
function echoProblem($problem) {
|
function getProblemTR($info) {
|
||||||
global $myUser;
|
$problem = new UOJProblem($info);
|
||||||
|
|
||||||
if (isProblemVisibleToUser($problem, $myUser)) {
|
$html = '<tr class="text-center">';
|
||||||
echo '<tr class="text-center">';
|
if ($info['submission_id']) {
|
||||||
if ($problem['submission_id']) {
|
$html .= '<td class="table-success">';
|
||||||
echo '<td class="table-success">';
|
|
||||||
} else {
|
} else {
|
||||||
echo '<td>';
|
$html .= '<td>';
|
||||||
}
|
}
|
||||||
echo '#', $problem['id'], '</td>';
|
$html .= "#{$info['id']}</td>";
|
||||||
|
$html .= '<td class="text-start">';
|
||||||
echo '<td class="text-start">';
|
$html .= $problem->getLink(['with' => 'none']);
|
||||||
echo '<a class="text-decoration-none" href="/problem/', $problem['id'], '">', $problem['title'], '</a>';
|
if ($problem->isUserOwnProblem(Auth::user())) {
|
||||||
|
$html .= ' <span class="badge text-white bg-info">' . UOJLocale::get('problems::my problem') . '</span> ';
|
||||||
if ($problem['uploader'] == $myUser['username']) {
|
|
||||||
echo ' <span class="badge text-white bg-info">', UOJLocale::get('problems::my problem') ,'</span> ';
|
|
||||||
}
|
}
|
||||||
|
if ($info['is_hidden']) {
|
||||||
if ($problem['is_hidden']) {
|
$html .= ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ' . UOJLocale::get('hidden') . '</span> ';
|
||||||
echo ' <span class="badge text-bg-danger"><i class="bi bi-eye-slash-fill"></i> ', UOJLocale::get('hidden'), '</span> ';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_COOKIE['show_tags_mode'])) {
|
if (isset($_COOKIE['show_tags_mode'])) {
|
||||||
foreach (queryProblemTags($problem['id']) as $tag) {
|
foreach ($problem->queryTags() as $tag) {
|
||||||
echo ' <a class="uoj-problem-tag my-1">';
|
$html .= ' <a class="uoj-problem-tag">' . '<span class="badge bg-secondary">' . HTML::escape($tag) . '</span>' . '</a> ';
|
||||||
echo '<span class="badge bg-secondary">';
|
|
||||||
echo HTML::escape($tag), '</span>';
|
|
||||||
echo '</a> ';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo '</td>';
|
$html .= '</td>';
|
||||||
if (isset($_COOKIE['show_submit_mode'])) {
|
if (isset($_COOKIE['show_submit_mode'])) {
|
||||||
$perc = $problem['submit_num'] > 0 ? round(100 * $problem['ac_num'] / $problem['submit_num']) : 0;
|
$perc = $info['submit_num'] > 0 ? round(100 * $info['ac_num'] / $info['submit_num']) : 0;
|
||||||
echo <<<EOD
|
$html .= '<td><a href="/submissions?problem_id=' . $info['id'] . '&min_score=100&max_score=100">×' . $info['ac_num'] . '</a></td>';
|
||||||
<td><a class="text-decoration-none" href="/submissions?problem_id={$problem['id']}&min_score=100&max_score=100">×{$problem['ac_num']}</a></td>
|
$html .= '<td><a href="/submissions?problem_id=' . $info['id'] . '">×' . $info['submit_num'] . '</a></td>';
|
||||||
<td><a class="text-decoration-none" href="/submissions?problem_id={$problem['id']}">×{$problem['submit_num']}</a></td>
|
$html .= '<td>';
|
||||||
<td>
|
$html .= '<div class="progress bot-buffer-no">';
|
||||||
<div class="progress bot-buffer-no">
|
$html .= '<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="' . $perc . '" aria-valuemin="0" aria-valuemax="100" style="width: ' . $perc . '%; min-width: 20px;">';
|
||||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="$perc" aria-valuemin="0" aria-valuemax="100" style="width: $perc%; min-width: 20px;">{$perc}%</div>
|
$html .= $perc . '%';
|
||||||
</div>
|
$html .= '</div>';
|
||||||
</td>
|
$html .= '</div>';
|
||||||
EOD;
|
$html .= '</td>';
|
||||||
}
|
|
||||||
if (isset($_COOKIE['show_difficulty'])) {
|
|
||||||
$extra_config = getProblemExtraConfig($problem);
|
|
||||||
if ($extra_config['difficulty'] == 0) {
|
|
||||||
echo "<td></td>";
|
|
||||||
} else {
|
|
||||||
echo "<td>{$extra_config['difficulty']}</td>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo '<td class="text-start">', getClickZanBlock('P', $problem['id'], $problem['zan'], null, false), '</td>';
|
|
||||||
echo '</tr>';
|
|
||||||
}
|
}
|
||||||
|
$html .= '<td class="text-center">' . ClickZans::getCntBlock($problem->info['zan']) . '</td>';
|
||||||
|
$html .= '</tr>';
|
||||||
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cond = array();
|
$cond = [];
|
||||||
|
$search_tag = UOJRequest::get('tag', 'is_string', null);
|
||||||
$search_tag = null;
|
$search_content = UOJRequest::get('search', 'is_string', '');
|
||||||
|
$search_is_effective = false;
|
||||||
$cur_tab = isset($_GET['tab']) ? $_GET['tab'] : 'all';
|
$cur_tab = UOJRequest::get('tab', 'is_string', 'all');
|
||||||
if ($cur_tab == 'template') {
|
if ($cur_tab == 'template') {
|
||||||
$search_tag = "模板题";
|
$search_tag = "模板题";
|
||||||
}
|
}
|
||||||
if (isset($_GET['tag'])) {
|
if (is_string($search_tag)) {
|
||||||
$search_tag = $_GET['tag'];
|
$cond[] = [
|
||||||
|
DB::rawvalue($search_tag), "in", DB::rawbracket([
|
||||||
|
"select tag from problems_tags",
|
||||||
|
"where", ["problems_tags.problem_id" => DB::raw("problems.id")]
|
||||||
|
])
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if ($search_content !== '') {
|
||||||
|
foreach (explode(' ', $search_content) as $key) {
|
||||||
|
if (strlen($key) > 0) {
|
||||||
|
$cond[] = DB::lor([
|
||||||
|
[DB::instr(DB::raw('title'), $key), '>', 0],
|
||||||
|
DB::exists([
|
||||||
|
"select tag from problems_tags",
|
||||||
|
"where", [
|
||||||
|
[DB::instr(DB::raw('tag'), $key), '>', 0],
|
||||||
|
"problems_tags.problem_id" => DB::raw("problems.id")
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
"id" => $key,
|
||||||
|
]);
|
||||||
|
$search_is_effective = true;
|
||||||
}
|
}
|
||||||
if ($search_tag) {
|
|
||||||
$cond[] = "'".DB::escape($search_tag)."' in (select tag from problems_tags where problems_tags.problem_id = problems.id)";
|
|
||||||
}
|
}
|
||||||
if (isset($_GET["search"])) {
|
|
||||||
$cond[]="(title like '%".DB::escape($_GET["search"])."%' or id like '%".DB::escape($_GET["search"])."%')";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_GET['is_hidden'])) {
|
if (isset($_GET['is_hidden'])) {
|
||||||
$cond[] = 'is_hidden = 1';
|
$cond[] = [
|
||||||
|
'is_hidden' => '1',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Auth::check() && isset($_GET['my'])) {
|
if (Auth::check() && isset($_GET['my'])) {
|
||||||
$cond[] = "uploader = '{$myUser['username']}'";
|
$cond[] = [
|
||||||
|
'uploader' => Auth::id(),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($cond) {
|
if (!$cond) {
|
||||||
$cond = join($cond, ' and ');
|
|
||||||
} else {
|
|
||||||
$cond = '1';
|
$cond = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +133,7 @@ EOD;
|
|||||||
if (isset($_COOKIE['show_difficulty'])) {
|
if (isset($_COOKIE['show_difficulty'])) {
|
||||||
$header .= '<th class="text-center" style="width:3em;">' . UOJLocale::get('problems::difficulty') . '</th>';
|
$header .= '<th class="text-center" style="width:3em;">' . UOJLocale::get('problems::difficulty') . '</th>';
|
||||||
}
|
}
|
||||||
$header .= '<th class="text-center" style="width:100px;">'.UOJLocale::get('appraisal').'</th>';
|
$header .= '<th class="text-center" style="width:50px;">' . UOJLocale::get('appraisal') . '</th>';
|
||||||
$header .= '</tr>';
|
$header .= '</tr>';
|
||||||
|
|
||||||
$tabs_info = array(
|
$tabs_info = array(
|
||||||
@ -145,15 +147,42 @@ EOD;
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
$pag_config = array('page_len' => 40);
|
$pag = new Paginator([
|
||||||
$pag_config['col_names'] = array('best_ac_submissions.submission_id as submission_id', 'problems.id as id', 'problems.is_hidden as is_hidden', 'problems.title as title', 'problems.submit_num as submit_num', 'problems.ac_num as ac_num', 'problems.zan as zan', 'problems.extra_config as extra_config', 'problems.uploader as uploader', 'problems.extra_config as extra_config');
|
'col_names' => ['*'],
|
||||||
$pag_config['table_name'] = "problems left join best_ac_submissions on best_ac_submissions.submitter = '{$myUser['username']}' and problems.id = best_ac_submissions.problem_id";
|
'table_name' => [
|
||||||
$pag_config['cond'] = $cond;
|
"problems left join best_ac_submissions",
|
||||||
$pag_config['tail'] = "order by id asc";
|
"on", [
|
||||||
$pag = new Paginator($pag_config);
|
"best_ac_submissions.submitter" => Auth::id(),
|
||||||
|
"problems.id" => DB::raw("best_ac_submissions.problem_id")
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'cond' => $cond,
|
||||||
|
'tail' => "order by id asc",
|
||||||
|
'page_len' => 40,
|
||||||
|
'post_filter' => function ($problem) {
|
||||||
|
return (new UOJProblem($problem))->userCanView(Auth::user());
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
$div_classes = ['card', 'my-3', 'table-responsive'];
|
// if ($search_is_effective) {
|
||||||
$table_classes = ['table', 'uoj-table', 'mb-0'];
|
// $search_summary = [
|
||||||
|
// 'count_in_cur_page' => $pag->countInCurPage(),
|
||||||
|
// 'first_a_few' => []
|
||||||
|
// ];
|
||||||
|
// foreach ($pag->get(5) as $info) {
|
||||||
|
// $problem = new UOJProblem($info);
|
||||||
|
// $search_summary['first_a_few'][] = [
|
||||||
|
// 'type' => 'problem',
|
||||||
|
// 'id' => $problem->info['id'],
|
||||||
|
// 'title' => $problem->getTitle()
|
||||||
|
// ];
|
||||||
|
// }
|
||||||
|
// DB::insert([
|
||||||
|
// "insert into search_requests",
|
||||||
|
// "(created_at, remote_addr, type, cache_id, q, content, result)",
|
||||||
|
// "values", DB::tuple([DB::now(), UOJContext::remoteAddr(), 'search', 0, $search_content, UOJContext::requestURI(), json_encode($search_summary)])
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('problems')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('problems')) ?>
|
||||||
|
|
||||||
@ -165,7 +194,7 @@ EOD;
|
|||||||
<!-- title -->
|
<!-- title -->
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('problems') ?>
|
<?= UOJLocale::get('problems') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -184,33 +213,21 @@ EOD;
|
|||||||
</div>
|
</div>
|
||||||
<div class="text-end p-2 col-12 col-sm-8">
|
<div class="text-end p-2 col-12 col-sm-8">
|
||||||
<div class="form-check d-inline-block me-2">
|
<div class="form-check d-inline-block me-2">
|
||||||
<input
|
<input type="checkbox" id="input-show_tags_mode" class="form-check-input" <?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ' : '' ?> />
|
||||||
type="checkbox" id="input-show_tags_mode"
|
|
||||||
class="form-check-input"
|
|
||||||
<?= isset($_COOKIE['show_tags_mode']) ? 'checked="checked" ': ''?>
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="input-show_tags_mode">
|
<label class="form-check-label" for="input-show_tags_mode">
|
||||||
<?= UOJLocale::get('problems::show tags') ?>
|
<?= UOJLocale::get('problems::show tags') ?>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check d-inline-block">
|
<div class="form-check d-inline-block">
|
||||||
<input
|
<input type="checkbox" id="input-show_submit_mode" class="form-check-input" <?= isset($_COOKIE['show_submit_mode']) ? 'checked="checked" ' : '' ?> />
|
||||||
type="checkbox" id="input-show_submit_mode"
|
|
||||||
class="form-check-input"
|
|
||||||
<?= isset($_COOKIE['show_submit_mode']) ? 'checked="checked" ': ''?>
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="input-show_submit_mode">
|
<label class="form-check-label" for="input-show_submit_mode">
|
||||||
<?= UOJLocale::get('problems::show statistics') ?>
|
<?= UOJLocale::get('problems::show statistics') ?>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check d-inline-block">
|
<div class="form-check d-inline-block">
|
||||||
<input
|
<input type="checkbox" id="input-show_difficulty" class="form-check-input" <?= isset($_COOKIE['show_difficulty']) ? 'checked="checked" ' : '' ?> />
|
||||||
type="checkbox" id="input-show_difficulty"
|
|
||||||
class="form-check-input"
|
|
||||||
<?= isset($_COOKIE['show_difficulty']) ? 'checked="checked" ': ''?>
|
|
||||||
/>
|
|
||||||
<label class="form-check-label" for="input-show_difficulty">
|
<label class="form-check-label" for="input-show_difficulty">
|
||||||
<?= UOJLocale::get('problems::show difficulty') ?>
|
<?= UOJLocale::get('problems::show difficulty') ?>
|
||||||
</label>
|
</label>
|
||||||
@ -218,56 +235,61 @@ EOD;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-center">
|
|
||||||
<?= $pag->pagination() ?>
|
<?= $pag->pagination() ?>
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('#input-show_tags_mode').click(function() {
|
$('#input-show_tags_mode').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_tags_mode', '', {path: '/problems'});
|
$.cookie('show_tags_mode', '', {
|
||||||
|
path: '/problems'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_tags_mode', {path: '/problems'});
|
$.removeCookie('show_tags_mode', {
|
||||||
|
path: '/problems'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
$('#input-show_submit_mode').click(function() {
|
$('#input-show_submit_mode').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_submit_mode', '', {path: '/problems'});
|
$.cookie('show_submit_mode', '', {
|
||||||
|
path: '/problems'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_submit_mode', {path: '/problems'});
|
$.removeCookie('show_submit_mode', {
|
||||||
|
path: '/problems'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
$('#input-show_difficulty').click(function() {
|
$('#input-show_difficulty').click(function() {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
$.cookie('show_difficulty', '', {path: '/'});
|
$.cookie('show_difficulty', '', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$.removeCookie('show_difficulty', {path: '/'});
|
$.removeCookie('show_difficulty', {
|
||||||
|
path: '/'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<div class="<?= join($div_classes, ' ') ?>">
|
|
||||||
<table class="<?= join($table_classes, ' ') ?>">
|
<div class="card my-3">
|
||||||
<thead><?= $header ?></thead>
|
<?=
|
||||||
<tbody>
|
HTML::responsive_table($header, $pag->get(), [
|
||||||
<?php
|
'table_attr' => [
|
||||||
foreach ($pag->get() as $idx => $row) {
|
'class' => ['table', 'uoj-table', 'mb-0'],
|
||||||
echoProblem($row);
|
],
|
||||||
echo "\n";
|
'tr' => function ($row, $idx) {
|
||||||
}
|
return getProblemTR($row);
|
||||||
if ($pag->isEmpty()) {
|
|
||||||
echo '<tr><td class="text-center" colspan="233">'.UOJLocale::get('none').'</td></tr>';
|
|
||||||
}
|
}
|
||||||
|
]);
|
||||||
?>
|
?>
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-center">
|
|
||||||
<?= $pag->pagination() ?>
|
<?= $pag->pagination() ?>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
@ -285,10 +307,7 @@ $('#input-show_difficulty').click(function() {
|
|||||||
</div>
|
</div>
|
||||||
<?php if (Auth::check()) : ?>
|
<?php if (Auth::check()) : ?>
|
||||||
<div class="form-check d-inline-block">
|
<div class="form-check d-inline-block">
|
||||||
<input
|
<input type="checkbox" name="my" <?= isset($_GET['my']) ? 'checked="checked"' : '' ?> class="form-check-input" id="input-my">
|
||||||
type="checkbox" name="my"
|
|
||||||
<?= isset($_GET['my']) ? 'checked="checked"' : '' ?>
|
|
||||||
class="form-check-input" id="input-my">
|
|
||||||
<label class="form-check-label" for="input-my">
|
<label class="form-check-label" for="input-my">
|
||||||
我的题目
|
我的题目
|
||||||
</label>
|
</label>
|
||||||
@ -296,10 +315,7 @@ $('#input-show_difficulty').click(function() {
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php if (isProblemManager(Auth::user())) : ?>
|
<?php if (isProblemManager(Auth::user())) : ?>
|
||||||
<div class="form-check d-inline-block ms-2">
|
<div class="form-check d-inline-block ms-2">
|
||||||
<input
|
<input type="checkbox" name="is_hidden" <?= isset($_GET['is_hidden']) ? 'checked="checked"' : '' ?> class="form-check-input" id="input-is_hidden">
|
||||||
type="checkbox" name="is_hidden"
|
|
||||||
<?= isset($_GET['is_hidden']) ? 'checked="checked"' : '' ?>
|
|
||||||
class="form-check-input" id="input-is_hidden">
|
|
||||||
<label class="form-check-label" for="input-is_hidden">
|
<label class="form-check-label" for="input-is_hidden">
|
||||||
隐藏题目
|
隐藏题目
|
||||||
</label>
|
</label>
|
||||||
@ -314,7 +330,7 @@ $('#input-show_difficulty').click(function() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- sidebar -->
|
<!-- sidebar -->
|
||||||
<?php uojIncludeView('sidebar', []) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,101 +5,69 @@
|
|||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
|
UOJProblem::cur()->userCanView(Auth::user()) || UOJResponse::page403();
|
||||||
|
|
||||||
|
if (!UOJProblem::cur()->userCanManage(Auth::user())) {
|
||||||
|
UOJProblem::cur()->userPermissionCodeCheck(Auth::user(), UOJProblem::cur()->getExtraConfig('view_solution_type')) || UOJResponse::page403();
|
||||||
|
|
||||||
|
foreach (UOJProblem::cur()->findInContests() as $cp) {
|
||||||
|
if ($cp->contest->progress() == CONTEST_IN_PROGRESS && $cp->contest->userHasRegistered(Auth::user())) {
|
||||||
|
UOJResponse::page403();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
if (UOJRequest::post('submit-remove_solution') === 'remove_solution') {
|
||||||
become403Page();
|
crsf_defend();
|
||||||
|
|
||||||
|
$blog = UOJBlog::query(UOJRequest::post('blog_id'));
|
||||||
|
|
||||||
|
if (!$blog || !$blog->userCanView(Auth::user())) {
|
||||||
|
dieWithAlert('博客不存在。');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
if (!UOJProblem::cur()->userCanManage(Auth::user()) && $blog->info['poster'] != Auth::id()) {
|
||||||
become404Page();
|
dieWithAlert('您没有权限移除该题解。');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isProblemVisibleToUser($problem, $myUser)) {
|
if ($blog->info['poster'] != Auth::id()) {
|
||||||
become404Page();
|
sendSystemMsg(
|
||||||
|
$blog->info['poster'],
|
||||||
|
'题解移除通知',
|
||||||
|
"<p>" . UOJUser::getLink($blog->info['poster']) . " 您好:</p>" .
|
||||||
|
"<p>您为问题 " . UOJProblem::cur()->getLink(['with' => 'id']) . " 提交的题解 " . $blog->getLink() . " 已被" . (isSuperUser(Auth::user()) ? "管理员" : " " . UOJUser::getLink(Auth::user()) . " ") . "移除。</p>"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$problem_extra_config = getProblemExtraConfig($problem);
|
DB::delete([
|
||||||
$solution_viewable = hasViewSolutionPermission($problem_extra_config['view_solution_type'], $myUser, $problem);
|
"delete from problems_solutions",
|
||||||
$solution_submittable = hasViewSolutionPermission($problem_extra_config['submit_solution_type'], $myUser, $problem);
|
"where", [
|
||||||
|
"problem_id" => UOJProblem::info('id'),
|
||||||
|
"blog_id" => $blog->info['id'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
if (!$solution_viewable) {
|
dieWithAlert('移除成功!');
|
||||||
become403Page();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasProblemPermission($myUser, $problem) && isRegisteredRunningContestProblem($myUser, $problem)) {
|
if (UOJProblem::cur()->userCanManage(Auth::user()) || UOJProblem::cur()->userPermissionCodeCheck(Auth::user(), UOJProblem::cur()->getExtraConfig('submit_solution_type'))) {
|
||||||
become403Page();
|
$add_new_solution_form = new UOJBs4Form('add_new_solution');
|
||||||
}
|
$add_new_solution_form->addVInput(
|
||||||
|
'blog_id_2',
|
||||||
function removeSolutionForm($blog_id) {
|
'text',
|
||||||
$res_form = new UOJForm("remove_solution_{$blog_id}");
|
'博客 ID',
|
||||||
$res_form->addHidden("blog_id", $blog_id, function($blog_id) {
|
'',
|
||||||
global $myUser, $problem;
|
function ($blog_id) {
|
||||||
|
$blog = UOJBlog::query($blog_id);
|
||||||
if (!validateUInt($blog_id)) {
|
|
||||||
return '博客 ID 不是有效的数字';
|
|
||||||
}
|
|
||||||
|
|
||||||
$blog = queryBlog($blog_id);
|
|
||||||
if (!$blog) {
|
if (!$blog) {
|
||||||
return '博客不存在';
|
return '博客不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasProblemPermission($myUser, $problem)) {
|
if (!$blog->userCanManage(Auth::user())) {
|
||||||
if ($blog['poster'] != $myUser['username']) {
|
if ($blog->info['poster'] != Auth::id()) {
|
||||||
return '您只能删除自己的题解';
|
if ($blog->info['is_hidden']) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}, null);
|
|
||||||
$res_form->handle = function() {
|
|
||||||
global $myUser, $problem;
|
|
||||||
|
|
||||||
$blog_id = $_POST["blog_id"];
|
|
||||||
DB::query("delete from problems_solutions where problem_id = {$problem['id']} and blog_id = {$blog_id}");
|
|
||||||
$blog = queryBlog($blog_id);
|
|
||||||
|
|
||||||
if ($blog['poster'] != $myUser['username']) {
|
|
||||||
$blog_link = getBlogLink($blog['id']);
|
|
||||||
$poster_user_link = getUserLink($blog['poster']);
|
|
||||||
$admin_user_link = isSuperUser($myUser) ? '管理员' : getUserLink($myUser['username']);
|
|
||||||
$content = <<<EOD
|
|
||||||
<p>{$poster_user_link} 您好:</p>
|
|
||||||
<p>您为问题 <a href="/problem/{$problem['id']}">#{$problem['id']} ({$problem['title']})</a> 提交的题解 {$blog_link} 已经被 {$admin_user_link} 移除。 </p>
|
|
||||||
EOD;
|
|
||||||
sendSystemMsg($blog['poster'], '题解移除通知', $content);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
$res_form->submit_button_config['margin_class'] = 'mt-0';
|
|
||||||
$res_form->submit_button_config['class_str'] = 'btn btn-link text-decoration-none text-danger p-0';
|
|
||||||
$res_form->submit_button_config['text'] = '移除';
|
|
||||||
$res_form->submit_button_config['confirm_text'] = '你真的要移除这篇题解吗?';
|
|
||||||
$res_form->submit_button_config['align'] = 'inline';
|
|
||||||
|
|
||||||
return $res_form;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($solution_submittable) {
|
|
||||||
$add_new_solution_form = new UOJForm('add_new_solution');
|
|
||||||
$add_new_solution_form->addVInput('blog_id_2', 'text', '博客 ID', '',
|
|
||||||
function ($x) {
|
|
||||||
global $myUser, $problem, $solution_submittable;
|
|
||||||
|
|
||||||
if (!validateUInt($x)) {
|
|
||||||
return 'ID 不合法';
|
|
||||||
}
|
|
||||||
|
|
||||||
$blog = queryBlog($x);
|
|
||||||
if (!$blog) {
|
|
||||||
return '博客不存在';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isSuperUser($myUser)) {
|
|
||||||
if ($blog['poster'] != $myUser['username']) {
|
|
||||||
if ($blog['is_hidden']) {
|
|
||||||
return '博客不存在';
|
return '博客不存在';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,93 +75,82 @@ EOD;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasProblemPermission($myUser, $problem)) {
|
if (!UOJProblem::cur()->userCanManage(Auth::user())) {
|
||||||
if ($blog['is_hidden']) {
|
if ($blog->info['is_hidden']) {
|
||||||
return '只能提交公开的博客';
|
return '只能提交公开的博客';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (querySolution($problem['id'], $x)) {
|
if (querySolution(UOJProblem::info('id'), $blog_id)) {
|
||||||
return '该题解已提交';
|
return '该题解已提交';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$solution_submittable) {
|
|
||||||
return '您无权提交题解';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_new_solution_form->submit_button_config['text'] = '发布';
|
$add_new_solution_form->submit_button_config['text'] = '发布';
|
||||||
$add_new_solution_form->submit_button_config['align'] = 'center';
|
$add_new_solution_form->submit_button_config['align'] = 'center';
|
||||||
|
$add_new_solution_form->submit_button_config['class_str'] = 'btn btn-secondary';
|
||||||
$add_new_solution_form->handle = function () {
|
$add_new_solution_form->handle = function () {
|
||||||
global $problem, $myUser;
|
DB::insert([
|
||||||
|
"insert into problems_solutions",
|
||||||
$blog_id_2 = $_POST['blog_id_2'];
|
DB::bracketed_fields(["problem_id", "blog_id"]),
|
||||||
$problem_id = $problem['id'];
|
"values", DB::tuple([UOJProblem::info('id'), $_POST['blog_id_2']]),
|
||||||
|
]);
|
||||||
DB::insert("insert into problems_solutions (problem_id, blog_id) values ({$problem_id}, {$blog_id_2})");
|
|
||||||
};
|
};
|
||||||
$add_new_solution_form->runAtServer();
|
$add_new_solution_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
$pag_config = array('page_len' => 5);
|
$pag_config = [
|
||||||
$pag_config['col_names'] = array('blog_id', 'content', 'poster', 'post_time', 'zan', 'is_hidden');
|
'page_len' => 5,
|
||||||
$pag_config['table_name'] = "problems_solutions inner join blogs on problems_solutions.blog_id = blogs.id";
|
'col_names' => ['blog_id', 'zan'],
|
||||||
$pag_config['cond'] = "problem_id = {$problem['id']}";
|
'table_name' => 'problems_solutions inner join blogs on blogs.id = problems_solutions.blog_id',
|
||||||
|
'cond' => ["problem_id" => UOJProblem::info('id')],
|
||||||
|
'post_filter' => function ($row) {
|
||||||
|
$blog = UOJBlog::query($row['blog_id']);
|
||||||
|
|
||||||
// 根据实际使用需要,题目管理员可以通过题解页面看到其他用户提交的题解,并且即使该题解对应的博客是隐藏状态也会照常显示
|
// 根据实际使用需要,题目管理员可以通过题解页面看到其他用户提交的题解,并且即使该题解对应的博客是隐藏状态也会照常显示
|
||||||
// 如需仅允许超级管理员查看,请将下一行中 if 语句的条件改为 (!isSuperUser($myUser))
|
// 如需仅允许超级管理员查看,请将下一行改为 return $blog->userCanView(Auth::user());
|
||||||
if (!hasProblemPermission($myUser, $problem)) {
|
return $blog->userCanView(Auth::user()) || UOJProblem::cur()->userCanManage(Auth::user());
|
||||||
$pag_config['cond'] .= " and (is_hidden = 0 or poster = '{$myUser['username']}')";
|
},
|
||||||
}
|
];
|
||||||
|
|
||||||
$pag_config['tail'] = "order by zan desc, post_time desc, id asc";
|
$pag_config['tail'] = "order by zan desc, post_time desc, id asc";
|
||||||
$pag = new Paginator($pag_config);
|
$pag = new Paginator($pag_config);
|
||||||
|
|
||||||
$rows = [];
|
|
||||||
|
|
||||||
foreach ($pag->get() as $idx => $row) {
|
|
||||||
$rows[$idx] = $row;
|
|
||||||
if ($row['poster'] == $myUser['username'] || hasProblemPermission($myUser, $problem)) {
|
|
||||||
$removeForm = removeSolutionForm($row['blog_id']);
|
|
||||||
$removeForm->runAtServer();
|
|
||||||
$rows[$idx]['removeForm'] = $removeForm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('problems::solutions') . ' - ' . HTML::stripTags($problem['title'])) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('problems::solutions') . ' - ' . HTML::stripTags($problem['title'])) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<!-- Left col -->
|
<!-- Left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
|
||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h1 class="h2 card-title text-center">
|
<h1 class="card-title text-center">
|
||||||
#<?= $problem['id']?>. <?= $problem['title'] ?>
|
<?= UOJProblem::cur()->getTitle(['with' => 'id']) ?>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<?php foreach ($rows as $row): ?>
|
<?php foreach ($pag->get() as $row) : ?>
|
||||||
|
<?php
|
||||||
|
$blog = UOJBlog::query($row['blog_id']);
|
||||||
|
$poster = UOJUser::query($blog->info['poster']);
|
||||||
|
?>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<?php $poster = queryUser($row['poster']); ?>
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<span class="me-2 d-inline-block">
|
<span class="me-2 d-inline-block">
|
||||||
<a class="text-decoration-none" href="<?= HTML::url('/user/' . $poster['username']) ?>">
|
<a class="text-decoration-none" href="<?= HTML::url('/user/' . $poster['username']) ?>">
|
||||||
<img src="<?= HTML::avatar_addr($poster, 64) ?>" width="32" height="32" class="rounded" />
|
<img src="<?= HTML::avatar_addr($poster, 64) ?>" width="32" height="32" class="rounded" />
|
||||||
</a>
|
</a>
|
||||||
<?= getUserLink($poster['username']) ?>
|
<?= UOJUser::getLink($poster) ?>
|
||||||
</span>
|
</span>
|
||||||
<span class="text-muted small d-inline-block">
|
<span class="text-muted small d-inline-block">
|
||||||
<?= UOJLocale::get('post time') ?>:
|
<?= UOJLocale::get('post time') ?>:
|
||||||
<time class="text-muted"><?= $row['post_time'] ?></time>
|
<time class="text-muted"><?= $blog->info['post_time'] ?></time>
|
||||||
</span>
|
</span>
|
||||||
<?php if ($row['is_hidden']): ?>
|
<?php if ($blog->info['is_hidden']) : ?>
|
||||||
<span class="badge text-bg-danger ms-2">
|
<span class="badge text-bg-danger ms-2">
|
||||||
<i class="bi bi-eye-slash-fill"></i>
|
<i class="bi bi-eye-slash-fill"></i>
|
||||||
<?= UOJLocale::get('hidden') ?>
|
<?= UOJLocale::get('hidden') ?>
|
||||||
@ -202,32 +159,41 @@ EOD;
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="markdown-body">
|
<div class="markdown-body">
|
||||||
<?= $row['content'] ?>
|
<?= $blog->queryContent()['content'] ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="mt-3 text-end list-inline">
|
<ul class="mt-3 text-end list-inline">
|
||||||
<?php if (isset($row['removeForm'])): ?>
|
<?php if (UOJProblem::cur()->userCanManage(Auth::user()) || $poster['username'] == Auth::id()) : ?>
|
||||||
<li class="list-inline-item">
|
<li class="list-inline-item">
|
||||||
<?php $row['removeForm']->printHTML(); ?>
|
<form class="d-inline-block" method="POST" onsubmit="return confirm('你真的要移除这篇题解吗?移除题解不会删除对应博客。')">
|
||||||
|
<input type="hidden" name="_token" value="<?= crsf_token() ?>">
|
||||||
|
<input type="hidden" name="blog_id" value="<?= $blog->info['id'] ?>">
|
||||||
|
<button class="btn btn-link text-decoration-none text-danger p-0 mt-0" type="submit" name="submit-remove_solution" value="remove_solution">
|
||||||
|
移除
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</li>
|
</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php if (Auth::check() && (isSuperUser(Auth::user()) || Auth::id() == $row['poster'])): ?>
|
<?php if ($blog->userCanManage(Auth::user())) : ?>
|
||||||
<li class="list-inline-item">
|
<li class="list-inline-item">
|
||||||
<a class="text-decoration-none" href="<?= HTML::blog_url($row['poster'], '/post/'.$row['blog_id'].'/write') ?>">
|
<a class="d-inline-block align-middle" href="<?= $blog->getUriForWrite() ?>">
|
||||||
修改
|
修改
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<li class="list-inline-item">
|
<li class="list-inline-item">
|
||||||
<a class="text-decoration-none" href="/blogs/<?= $row['blog_id'] ?>">在 Ta 的博客上查看</a>
|
<a class="d-inline-block align-middle" href="<?= $blog->getBlogUri() ?>">
|
||||||
|
在 Ta 的博客上查看
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="list-inline-item">
|
<li class="list-inline-item">
|
||||||
<?= getClickZanBlock('B', $row['blog_id'], $row['zan']) ?>
|
<?= ClickZans::getBlock('B', $blog->info['id'], $blog->info['zan']) ?>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
<?php if ($pag->isEmpty()) : ?>
|
<?php if ($pag->isEmpty()) : ?>
|
||||||
<div class="text-center py-2">
|
<div class="text-center text-muted py-4">
|
||||||
暂无题解
|
暂无题解
|
||||||
</div>
|
</div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -237,8 +203,8 @@ EOD;
|
|||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
<?= $pag->pagination() ?>
|
<?= $pag->pagination() ?>
|
||||||
|
|
||||||
<!-- End left col -->
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- End left col -->
|
||||||
|
|
||||||
<!-- Right col -->
|
<!-- Right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
@ -246,7 +212,7 @@ EOD;
|
|||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a href="/problem/<?= $problem['id'] ?>" class="nav-link" role="tab">
|
<a href="/problem/<?= UOJProblem::info('id') ?>" class="nav-link" role="tab">
|
||||||
<i class="bi bi-journal-text"></i>
|
<i class="bi bi-journal-text"></i>
|
||||||
<?= UOJLocale::get('problems::statement') ?>
|
<?= UOJLocale::get('problems::statement') ?>
|
||||||
</a>
|
</a>
|
||||||
@ -258,14 +224,14 @@ EOD;
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/statistics">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/statistics">
|
||||||
<i class="bi bi-graph-up"></i>
|
<i class="bi bi-graph-up"></i>
|
||||||
<?= UOJLocale::get('problems::statistics') ?>
|
<?= UOJLocale::get('problems::statistics') ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<?php if (hasProblemPermission($myUser, $problem)): ?>
|
<?php if (UOJProblem::cur()->userCanManage(Auth::user())) : ?>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/manage/statement" role="tab">
|
||||||
<i class="bi bi-sliders"></i>
|
<i class="bi bi-sliders"></i>
|
||||||
<?= UOJLocale::get('problems::manage') ?>
|
<?= UOJLocale::get('problems::manage') ?>
|
||||||
</a>
|
</a>
|
||||||
@ -273,7 +239,7 @@ EOD;
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
评价:<?= getClickZanBlock('P', $problem['id'], $problem['zan']) ?>
|
评价:<?= ClickZans::getBlock('P', UOJProblem::info('id'), UOJProblem::info('zan')) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -289,15 +255,14 @@ EOD;
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
<a target="_blank" class="text-decoration-none" href="<?= HTML::blog_url(Auth::id(), '/post/new/write?title=' . urlencode('【题解】#' . $problem['id'] . '. ' . $problem['title']) . '&is_hidden=0&add_solution_for=' . $problem['id']) ?>">
|
<a target="_blank" class="text-decoration-none" href="<?= HTML::blog_url(Auth::id(), '/post/new/write?title=' . urlencode('【题解】#' . UOJProblem::info('id') . '. ' . UOJProblem::info('title')) . '&is_hidden=0') ?>">
|
||||||
快速新建文章
|
快速新建文章
|
||||||
</a>
|
</a>
|
||||||
<div class="small text-muted mt-1">发布文章后,请返回本页输入博客 ID</div>
|
<div class="small text-muted mt-1">发布文章后,请返回本页输入博客 ID</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php uojIncludeView('sidebar', array()); ?>
|
<?php uojIncludeView('sidebar'); ?>
|
||||||
|
|
||||||
<!-- End right col -->
|
<!-- End right col -->
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
|
@ -2,78 +2,90 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become404Page();
|
UOJProblem::cur()->userCanManage(Auth::user()) || UOJResponse::page403();
|
||||||
}
|
$problem_content = UOJProblem::cur()->queryContent();
|
||||||
if (!hasProblemPermission($myUser, $problem)) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$problem_content = queryProblemContent($problem['id']);
|
|
||||||
$problem_tags = queryProblemTags($problem['id']);
|
|
||||||
|
|
||||||
$problem_editor = new UOJBlogEditor();
|
$problem_editor = new UOJBlogEditor();
|
||||||
$problem_editor->name = 'problem';
|
$problem_editor->name = 'problem';
|
||||||
$problem_editor->blog_url = "/problem/{$problem['id']}";
|
$problem_editor->blog_url = '/problem/' . UOJProblem::info('id');
|
||||||
$problem_editor->cur_data = array(
|
$problem_editor->cur_data = [
|
||||||
'title' => $problem['title'],
|
'title' => UOJProblem::info('title'),
|
||||||
'content_md' => $problem_content['statement_md'],
|
'content_md' => $problem_content['statement_md'],
|
||||||
'content' => $problem_content['statement'],
|
'content' => $problem_content['statement'],
|
||||||
'tags' => $problem_tags,
|
'tags' => UOJProblem::cur()->queryTags(),
|
||||||
'is_hidden' => $problem['is_hidden']
|
'is_hidden' => UOJProblem::info('is_hidden')
|
||||||
);
|
];
|
||||||
$problem_editor->label_text = array_merge($problem_editor->label_text, array(
|
$problem_editor->label_text = array_merge($problem_editor->label_text, [
|
||||||
'view blog' => '查看题目',
|
'view blog' => '查看题目',
|
||||||
'blog visibility' => '题目可见性'
|
'blog visibility' => '题目可见性'
|
||||||
));
|
]);
|
||||||
|
|
||||||
$problem_editor->save = function ($data) {
|
$problem_editor->save = function ($data) {
|
||||||
global $problem, $problem_tags;
|
DB::update([
|
||||||
DB::update("update problems set title = '".DB::escape($data['title'])."' where id = {$problem['id']}");
|
"update problems",
|
||||||
DB::update("update problems_contents set statement = '".DB::escape($data['content'])."', statement_md = '".DB::escape($data['content_md'])."' where id = {$problem['id']}");
|
"set", ["title" => $data['title']],
|
||||||
|
"where", ["id" => UOJProblem::info('id')]
|
||||||
|
]);
|
||||||
|
|
||||||
if ($data['tags'] !== $problem_tags) {
|
DB::update([
|
||||||
DB::delete("delete from problems_tags where problem_id = {$problem['id']}");
|
"update problems_contents",
|
||||||
foreach ($data['tags'] as $tag) {
|
"set", [
|
||||||
DB::insert("insert into problems_tags (problem_id, tag) values ({$problem['id']}, '".DB::escape($tag)."')");
|
"statement" => $data['content'],
|
||||||
}
|
"statement_md" => $data['content_md']
|
||||||
}
|
], "where", ["id" => UOJProblem::info('id')]
|
||||||
if ($data['is_hidden'] != $problem['is_hidden'] ) {
|
]);
|
||||||
DB::update("update problems set is_hidden = {$data['is_hidden']} where id = {$problem['id']}");
|
|
||||||
DB::update("update submissions set is_hidden = {$data['is_hidden']} where problem_id = {$problem['id']}");
|
UOJProblem::cur()->updateTags($data['tags']);
|
||||||
DB::update("update hacks set is_hidden = {$data['is_hidden']} where problem_id = {$problem['id']}");
|
|
||||||
|
if ($data['is_hidden'] != UOJProblem::info('is_hidden')) {
|
||||||
|
DB::update([
|
||||||
|
"update problems",
|
||||||
|
"set", ["is_hidden" => $data['is_hidden']],
|
||||||
|
"where", ["id" => UOJProblem::info('id')]
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update submissions",
|
||||||
|
"set", ["is_hidden" => $data['is_hidden']],
|
||||||
|
"where", ["problem_id" => UOJProblem::info('id')]
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update hacks",
|
||||||
|
"set", ["is_hidden" => $data['is_hidden']],
|
||||||
|
"where", ["problem_id" => UOJProblem::info('id')]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$problem_editor->runAtServer();
|
$problem_editor->runAtServer();
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(HTML::stripTags($problem['title']) . ' - 编辑 - 题目管理') ?>
|
|
||||||
|
<?php echoUOJPageHeader('题面编辑 - ' . HTML::stripTags(UOJProblem::info('title'))) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
<h1>
|
||||||
<h1 class="h2">
|
<?= UOJProblem::cur()->getTitle(['with' => 'id']) ?> 管理
|
||||||
#<?=$problem['id']?>. <?=$problem['title']?> 管理
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<ul class="nav nav-pills my-3" role="tablist">
|
<ul class="nav nav-pills my-3" role="tablist">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" href="/problem/<?= $problem['id'] ?>/manage/statement" role="tab">
|
<a class="nav-link active" href="/problem/<?= UOJProblem::info('id') ?>/manage/statement" role="tab">
|
||||||
题面
|
题面
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/managers" role="tab">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/manage/managers" role="tab">
|
||||||
管理者
|
管理者
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/manage/data" role="tab">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/manage/data" role="tab">
|
||||||
数据
|
数据
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@ -88,7 +100,7 @@
|
|||||||
<!-- 提示信息 -->
|
<!-- 提示信息 -->
|
||||||
<div class="card mt-3">
|
<div class="card mt-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="h4 card-title">提示</h2>
|
<h2 class="h3 card-title">提示</h2>
|
||||||
<ol>
|
<ol>
|
||||||
<li>请勿引用不稳定的外部资源(如来自个人服务器的图片或文档等),以便备份及后期维护;</li>
|
<li>请勿引用不稳定的外部资源(如来自个人服务器的图片或文档等),以便备份及后期维护;</li>
|
||||||
<li>请勿在题面中直接插入大段 HTML 代码,这可能会破坏页面的显示,可以考虑使用 <a class="text-decoration-none" href="/html2markdown" target="_blank">转换工具</a> 转换后再作修正;</li>
|
<li>请勿在题面中直接插入大段 HTML 代码,这可能会破坏页面的显示,可以考虑使用 <a class="text-decoration-none" href="/html2markdown" target="_blank">转换工具</a> 转换后再作修正;</li>
|
||||||
@ -99,28 +111,26 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
|
|
||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a href="/problem/<?= $problem['id'] ?>" class="nav-link" role="tab">
|
<a href="/problem/<?= UOJProblem::info('id') ?>" class="nav-link" role="tab">
|
||||||
<i class="bi bi-journal-text"></i>
|
<i class="bi bi-journal-text"></i>
|
||||||
<?= UOJLocale::get('problems::statement') ?>
|
<?= UOJLocale::get('problems::statement') ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a href="/problem/<?= $problem['id'] ?>/solutions" class="nav-link" role="tab">
|
<a href="/problem/<?= UOJProblem::info('id') ?>/solutions" class="nav-link" role="tab">
|
||||||
<i class="bi bi-journal-bookmark"></i>
|
<i class="bi bi-journal-bookmark"></i>
|
||||||
<?= UOJLocale::get('problems::solutions') ?>
|
<?= UOJLocale::get('problems::solutions') ?>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" href="/problem/<?= $problem['id'] ?>/statistics">
|
<a class="nav-link" href="/problem/<?= UOJProblem::info('id') ?>/statistics">
|
||||||
<i class="bi bi-graph-up"></i>
|
<i class="bi bi-graph-up"></i>
|
||||||
<?= UOJLocale::get('problems::statistics') ?>
|
<?= UOJLocale::get('problems::statistics') ?>
|
||||||
</a>
|
</a>
|
||||||
@ -133,11 +143,11 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
评价:<?= getClickZanBlock('P', $problem['id'], $problem['zan']) ?>
|
评价:<?= ClickZans::getBlock('P', UOJProblem::info('id'), UOJProblem::info('zan')) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php uojIncludeView('sidebar', array()) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,57 +2,44 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requireLib('morris');
|
requireLib('morris');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJProblem::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($problem = queryProblemBrief($_GET['id']))) {
|
$problem = UOJProblem::cur()->info;
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$contest = validateUInt($_GET['contest_id']) ? queryContest($_GET['contest_id']) : null;
|
if (UOJRequest::get('contest_id')) {
|
||||||
if ($contest != null) {
|
UOJContest::init(UOJRequest::get('contest_id')) || UOJResponse::page404();
|
||||||
genMoreContestInfo($contest);
|
UOJProblem::upgradeToContestProblem() || UOJResponse::page404();
|
||||||
if (!isContestProblemVisibleToUser($problem, $contest, $myUser)) {
|
UOJContest::cur()->userCanSeeProblemStatistics(Auth::user()) || UOJResponse::page403();
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$problem_rank = queryContestProblemRank($contest, $problem);
|
|
||||||
if ($problem_rank == null) {
|
|
||||||
become404Page();
|
|
||||||
} else {
|
|
||||||
$problem_letter = chr(ord('A') + $problem_rank - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isProblemVisibleToUser($problem, $myUser)) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
UOJProblem::cur()->userCanView(Auth::user(), ['ensure' => true]);
|
||||||
|
|
||||||
function scoreDistributionData() {
|
function scoreDistributionData() {
|
||||||
$data = array();
|
$data = array();
|
||||||
$result = DB::select("select score, count(*) from submissions where problem_id = {$_GET['id']} and score is not null group by score");
|
$res = DB::selectAll([
|
||||||
$is_res_empty = true;
|
"select score, count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"problem_id" => UOJProblem::info('id'),
|
||||||
|
["score", "is not", null],
|
||||||
|
UOJSubmission::sqlForUserCanView(Auth::user(), UOJProblem::cur())
|
||||||
|
], "group by score", "order by score"
|
||||||
|
], DB::NUM);
|
||||||
$has_score_0 = false;
|
$has_score_0 = false;
|
||||||
$has_score_100 = false;
|
$has_score_100 = false;
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
foreach ($res as $row) {
|
||||||
if ($row[0] == 0) {
|
if ($row[0] == 0) {
|
||||||
$has_score_0 = true;
|
$has_score_0 = true;
|
||||||
} else if ($row[0] == 100) {
|
} else if ($row[0] == 100) {
|
||||||
$has_score_100 = true;
|
$has_score_100 = true;
|
||||||
}
|
}
|
||||||
$score = $row[0] * 100;
|
$score = $row[0] * 100;
|
||||||
$data[] = array('score' => $score, 'count' => $row[1]);
|
$data[] = ['score' => $score, 'count' => $row[1]];
|
||||||
}
|
}
|
||||||
if (!$has_score_0) {
|
if (!$has_score_0) {
|
||||||
array_unshift($data, array('score' => 0, 'count' => 0));
|
array_unshift($data, ['score' => 0, 'count' => 0]);
|
||||||
}
|
}
|
||||||
if (!$has_score_100) {
|
if (!$has_score_100) {
|
||||||
$data[] = array('score' => 10000, 'count' => 0);
|
$data[] = ['score' => 10000, 'count' => 0];
|
||||||
}
|
}
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
@ -73,47 +60,45 @@
|
|||||||
$submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']) ? 'time' : 'tot_size';
|
$submissions_sort_by_choice = !isset($_COOKIE['submissions-sort-by-code-length']) ? 'time' : 'tot_size';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader(HTML::stripTags($problem['title']) . ' - ' . UOJLocale::get('problems::statistics')) ?>
|
<?php echoUOJPageHeader(HTML::stripTags(UOJProblem::info('title')) . ' - ' . UOJLocale::get('problems::statistics')) ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
<?php if (UOJContest::cur()) : ?>
|
||||||
<?php if ($contest): ?>
|
|
||||||
<!-- 比赛导航 -->
|
<!-- 比赛导航 -->
|
||||||
<?php
|
<?php
|
||||||
$tabs_info = array(
|
$tabs_info = [
|
||||||
'dashboard' => array(
|
'dashboard' => [
|
||||||
'name' => UOJLocale::get('contests::contest dashboard'),
|
'name' => UOJLocale::get('contests::contest dashboard'),
|
||||||
'url' => "/contest/{$contest['id']}"
|
'url' => '/contest/' . UOJContest::info('id'),
|
||||||
),
|
],
|
||||||
'submissions' => array(
|
'submissions' => [
|
||||||
'name' => UOJLocale::get('contests::contest submissions'),
|
'name' => UOJLocale::get('contests::contest submissions'),
|
||||||
'url' => "/contest/{$contest['id']}/submissions"
|
'url' => '/contest/' . UOJContest::info('id') . '/submissions',
|
||||||
),
|
],
|
||||||
'standings' => array(
|
'standings' => [
|
||||||
'name' => UOJLocale::get('contests::contest standings'),
|
'name' => UOJLocale::get('contests::contest standings'),
|
||||||
'url' => "/contest/{$contest['id']}/standings"
|
'url' => '/contest/' . UOJContest::info('id') . '/standings',
|
||||||
),
|
],
|
||||||
);
|
];
|
||||||
|
|
||||||
if ($contest['cur_progress'] > CONTEST_TESTING) {
|
if (UOJContest::cur()->progress() > CONTEST_TESTING) {
|
||||||
$tabs_info['after_contest_standings'] = array(
|
$tabs_info['after_contest_standings'] = [
|
||||||
'name' => UOJLocale::get('contests::after contest standings'),
|
'name' => UOJLocale::get('contests::after contest standings'),
|
||||||
'url' => "/contest/{$contest['id']}/after_contest_standings"
|
'url' => '/contest/' . UOJContest::info('id') . '/after_contest_standings',
|
||||||
);
|
];
|
||||||
$tabs_info['self_reviews'] = array(
|
$tabs_info['self_reviews'] = [
|
||||||
'name' => UOJLocale::get('contests::contest self reviews'),
|
'name' => UOJLocale::get('contests::contest self reviews'),
|
||||||
'url' => "/contest/{$contest['id']}/self_reviews"
|
'url' => '/contest/' . UOJContest::info('id') . '/self_reviews',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasContestPermission(Auth::user(), $contest)) {
|
if (UOJContest::cur()->userCanManage(Auth::user())) {
|
||||||
$tabs_info['backstage'] = array(
|
$tabs_info['backstage'] = [
|
||||||
'name' => UOJLocale::get('contests::contest backstage'),
|
'name' => UOJLocale::get('contests::contest backstage'),
|
||||||
'url' => "/contest/{$contest['id']}/backstage"
|
'url' => '/contest/' . UOJContest::info('id') . '/backstage',
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
@ -124,21 +109,17 @@
|
|||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<h1 class="page-header text-center h2">
|
<h1 class="text-center">
|
||||||
<?php if ($contest): ?>
|
<?php if (UOJContest::cur()) : ?>
|
||||||
<?= $problem_letter ?>.
|
<?= UOJProblem::cur()->getTitle(['with' => 'letter']) ?>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
#<?= $problem['id'] ?>.
|
<?= UOJProblem::cur()->getTitle(['with' => 'id']) ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?= $problem['title'] ?>
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<?php if ($contest && !hasContestPermission($myUser, $contest) && $contest['cur_progress'] <= CONTEST_IN_PROGRESS): ?>
|
<h2 class="text-center"><?= UOJLocale::get('problems::accepted submissions') ?></h2>
|
||||||
<h2 class="text-center text-muted">比赛尚未结束</h2>
|
|
||||||
<?php else: ?>
|
|
||||||
<h2 class="text-center h3"><?= UOJLocale::get('problems::accepted submissions') ?></h2>
|
|
||||||
<div class="text-end mb-2">
|
<div class="text-end mb-2">
|
||||||
<div class="btn-group btn-group-sm">
|
<div class="btn-group btn-group-sm">
|
||||||
<a href="<?= UOJContext::requestURI() ?>" class="btn btn-secondary btn-xs <?= $submissions_sort_by_choice == 'time' ? 'active' : '' ?>" id="submissions-sort-by-run-time">
|
<a href="<?= UOJContext::requestURI() ?>" class="btn btn-secondary btn-xs <?= $submissions_sort_by_choice == 'time' ? 'active' : '' ?>" id="submissions-sort-by-run-time">
|
||||||
@ -162,19 +143,30 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$table_config = [
|
if ($submissions_sort_by_choice == 'time') {
|
||||||
|
$submid = 'best_ac_submissions.submission_id = submissions.id';
|
||||||
|
$orderby = 'order by best_ac_submissions.used_time, best_ac_submissions.used_memory, best_ac_submissions.tot_size, best_ac_submissions.submission_id';
|
||||||
|
} else {
|
||||||
|
$submid = 'best_ac_submissions.shortest_id = submissions.id';
|
||||||
|
$orderby = 'order by best_ac_submissions.shortest_tot_size, best_ac_submissions.shortest_used_time, best_ac_submissions.shortest_used_memory, best_ac_submissions.shortest_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
echoSubmissionsList([
|
||||||
|
$submid,
|
||||||
|
"best_ac_submissions.problem_id" => UOJProblem::info('id')
|
||||||
|
], $orderby, [
|
||||||
|
'judge_time_hidden' => '',
|
||||||
|
'problem_hidden' => true,
|
||||||
|
'table_name' => 'best_ac_submissions, submissions',
|
||||||
|
'problem' => UOJProblem::cur(),
|
||||||
|
'table_config' => [
|
||||||
'div_classes' => ['table-responsive', 'mb-3'],
|
'div_classes' => ['table-responsive', 'mb-3'],
|
||||||
'table_classes' => ['table', 'mb-0', 'text-center'],
|
'table_classes' => ['table', 'mb-0', 'text-center'],
|
||||||
];
|
]
|
||||||
|
], Auth::user());
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php if ($submissions_sort_by_choice == 'time'): ?>
|
<h2 class="text-center mt-4">
|
||||||
<?php echoSubmissionsList("best_ac_submissions.submission_id = submissions.id and best_ac_submissions.problem_id = {$problem['id']}", 'order by best_ac_submissions.used_time, best_ac_submissions.used_memory, best_ac_submissions.tot_size', array('problem_hidden' => '', 'judge_time_hidden' => '', 'table_name' => 'best_ac_submissions, submissions', 'table_config' => $table_config), $myUser); ?>
|
|
||||||
<?php else: ?>
|
|
||||||
<?php echoSubmissionsList("best_ac_submissions.shortest_id = submissions.id and best_ac_submissions.problem_id = {$problem['id']}", 'order by best_ac_submissions.shortest_tot_size, best_ac_submissions.shortest_used_time, best_ac_submissions.shortest_used_memory', array('problem_hidden' => '', 'judge_time_hidden' => '', 'table_name' => 'best_ac_submissions, submissions', 'table_config' => $table_config), $myUser); ?>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<h2 class="text-center h3 mt-4">
|
|
||||||
<?= UOJLocale::get('problems::score distribution') ?>
|
<?= UOJLocale::get('problems::score distribution') ?>
|
||||||
</h2>
|
</h2>
|
||||||
<div id="score-distribution-chart" style="height: 250px;"></div>
|
<div id="score-distribution-chart" style="height: 250px;"></div>
|
||||||
@ -197,7 +189,7 @@ new Morris.Bar({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h2 class="text-center h3 mt-4">
|
<h2 class="text-center mt-4">
|
||||||
<?= UOJLocale::get('problems::prefix sum of score distribution') ?>
|
<?= UOJLocale::get('problems::prefix sum of score distribution') ?>
|
||||||
</h2>
|
</h2>
|
||||||
<div id="score-distribution-chart-pre" style="height: 250px;"></div>
|
<div id="score-distribution-chart-pre" style="height: 250px;"></div>
|
||||||
@ -226,7 +218,7 @@ new Morris.Line({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h2 class="text-center h3 mt-4">
|
<h2 class="text-center mt-4">
|
||||||
<?= UOJLocale::get('problems::suffix sum of score distribution') ?>
|
<?= UOJLocale::get('problems::suffix sum of score distribution') ?>
|
||||||
</h2>
|
</h2>
|
||||||
<div id="score-distribution-chart-suf" style="height: 250px;"></div>
|
<div id="score-distribution-chart-suf" style="height: 250px;"></div>
|
||||||
@ -254,9 +246,6 @@ new Morris.Line({
|
|||||||
resize: true
|
resize: true
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php endif // $contest && !hasContestPermission($myUser, $contest) && $contest['cur_progress'] <= CONTEST_IN_PROGRESS ?>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -270,7 +259,7 @@ new Morris.Line({
|
|||||||
<!-- Contest card -->
|
<!-- Contest card -->
|
||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h3 class="h5 card-title text-center">
|
<h3 class="h4 card-title text-center">
|
||||||
<a class="text-decoration-none text-body" href="/contest/<?= $contest['id'] ?>">
|
<a class="text-decoration-none text-body" href="/contest/<?= $contest['id'] ?>">
|
||||||
<?= $contest['name'] ?>
|
<?= $contest['name'] ?>
|
||||||
</a>
|
</a>
|
||||||
@ -284,7 +273,7 @@ new Morris.Line({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
比赛评价:<?= getClickZanBlock('C', $contest['id'], $contest['zan']) ?>
|
比赛评价:<?= ClickZans::getBlock('C', $contest['id'], $contest['zan']) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?>
|
<?php if ($contest['cur_progress'] <= CONTEST_IN_PROGRESS) : ?>
|
||||||
@ -297,12 +286,7 @@ $('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJ
|
|||||||
<div class="card card-default mb-2">
|
<div class="card card-default mb-2">
|
||||||
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
<ul class="nav nav-pills nav-fill flex-column" role="tablist">
|
||||||
<li class="nav-item text-start">
|
<li class="nav-item text-start">
|
||||||
<a class="nav-link" role="tab"
|
<a class="nav-link" role="tab" <?php if ($contest) : ?> href="/contest/<?= $contest['id'] ?>/problem/<?= $problem['id'] ?>" <?php else : ?> href="/problem/<?= $problem['id'] ?>" <?php endif ?>>
|
||||||
<?php if ($contest): ?>
|
|
||||||
href="/contest/<?= $contest['id'] ?>/problem/<?= $problem['id'] ?>"
|
|
||||||
<?php else: ?>
|
|
||||||
href="/problem/<?= $problem['id'] ?>"
|
|
||||||
<?php endif ?>>
|
|
||||||
<i class="bi bi-journal-text"></i>
|
<i class="bi bi-journal-text"></i>
|
||||||
<?= UOJLocale::get('problems::statement') ?>
|
<?= UOJLocale::get('problems::statement') ?>
|
||||||
</a>
|
</a>
|
||||||
@ -331,21 +315,15 @@ $('#contest-countdown').countdown(<?= $contest['end_time']->getTimestamp() - UOJ
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="card-footer bg-transparent">
|
<div class="card-footer bg-transparent">
|
||||||
评价:<?= getClickZanBlock('P', $problem['id'], $problem['zan']) ?>
|
评价:<?= ClickZans::getBlock('P', $problem['id'], $problem['zan']) ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php uojIncludeView('sidebar', array()); ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
|
|
||||||
<!-- End right col -->
|
<!-- End right col -->
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($contest && $contest['cur_progress'] <= CONTEST_IN_PROGRESS): ?>
|
|
||||||
<script type="text/javascript">
|
|
||||||
checkContestNotice(<?= $contest['id'] ?>, '<?= UOJTime::$time_now_str ?>');
|
|
||||||
</script>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = [
|
$config = [
|
||||||
'page_len' => 50,
|
'page_len' => 50,
|
||||||
'div_classes' => ['card', 'mb-3'],
|
'div_classes' => ['card', 'mb-3'],
|
||||||
'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'],
|
'table_classes' => ['table', 'uoj-table', 'mb-0', 'text-center'],
|
||||||
|
'card' => true
|
||||||
];
|
];
|
||||||
|
|
||||||
if (isset($_GET['type']) && $_GET['type'] == 'accepted') {
|
if (isset($_GET['type']) && $_GET['type'] == 'accepted') {
|
||||||
@ -28,15 +23,15 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
<h1 class="h2"><?= $title ?></h1>
|
<h1><?= $title ?></h1>
|
||||||
|
|
||||||
<?php echoRanklist($config) ?>
|
<?php UOJRanklist::printHTML($config) ?>
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<?php uojIncludeView('sidebar', array()) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
<!-- end right col -->
|
<!-- end right col -->
|
||||||
|
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
requireLib('bootstrap5');
|
||||||
|
requireLib('md5');
|
||||||
|
|
||||||
|
use Gregwar\Captcha\PhraseBuilder;
|
||||||
|
|
||||||
if (!UOJConfig::$data['switch']['open-register'] && DB::selectCount("SELECT COUNT(*) FROM user_info")) {
|
if (!UOJConfig::$data['switch']['open-register'] && DB::selectCount("SELECT COUNT(*) FROM user_info")) {
|
||||||
become404Page();
|
become404Page();
|
||||||
}
|
}
|
||||||
@ -7,100 +12,103 @@
|
|||||||
if (!crsf_check()) {
|
if (!crsf_check()) {
|
||||||
return '页面已过期';
|
return '页面已过期';
|
||||||
}
|
}
|
||||||
if (!isset($_POST['username'])) {
|
|
||||||
return "无效表单";
|
if (!isset($_SESSION['phrase']) || !PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha'])) {
|
||||||
|
return "bad_captcha";
|
||||||
}
|
}
|
||||||
if (!isset($_POST['password'])) {
|
|
||||||
return "无效表单";
|
if (!isset($_POST['username']) || !isset($_POST['password']) || !isset($_POST['email'])) {
|
||||||
}
|
|
||||||
if (!isset($_POST['email'])) {
|
|
||||||
return "无效表单";
|
return "无效表单";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!UOJConfig::$data['switch']['open-register'] && DB::selectCount("SELECT COUNT(*) FROM user_info")) {
|
try {
|
||||||
return "只有首位用户可以注册。";
|
$user = UOJUser::register([
|
||||||
|
'username' => UOJRequest::post('username'),
|
||||||
|
'password' => UOJRequest::post('password'),
|
||||||
|
'email' => UOJRequest::post('email')
|
||||||
|
]);
|
||||||
|
} catch (UOJInvalidArgumentException $e) {
|
||||||
|
return "失败:" . $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
$username = $_POST['username'];
|
return "欢迎你!" . $user['username'] . ",你已成功注册。";
|
||||||
$password = $_POST['password'];
|
|
||||||
$email = $_POST['email'];
|
|
||||||
if (!validateUsername($username)) {
|
|
||||||
return "失败:无效用户名。";
|
|
||||||
}
|
|
||||||
if (queryUser($username)) {
|
|
||||||
return "失败:用户名已存在。";
|
|
||||||
}
|
|
||||||
if (!validatePassword($password)) {
|
|
||||||
return "失败:无效密码。";
|
|
||||||
}
|
|
||||||
if (!validateEmail($email)) {
|
|
||||||
return "失败:无效电子邮箱。";
|
|
||||||
}
|
|
||||||
|
|
||||||
$password = getPasswordToStore($password, $username);
|
|
||||||
|
|
||||||
$esc_email = DB::escape($email);
|
|
||||||
|
|
||||||
$svn_pw = uojRandString(10);
|
|
||||||
if (!DB::selectCount("SELECT COUNT(*) FROM user_info")) {
|
|
||||||
DB::query("insert into user_info (username, email, password, svn_password, register_time, usergroup) values ('$username', '$esc_email', '$password', '$svn_pw', now(), 'S')");
|
|
||||||
} else {
|
|
||||||
DB::query("insert into user_info (username, email, password, svn_password, register_time) values ('$username', '$esc_email', '$password', '$svn_pw', now())");
|
|
||||||
}
|
|
||||||
|
|
||||||
return "欢迎你!" . $username . ",你已成功注册。";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_POST['register'])) {
|
if (isset($_POST['register'])) {
|
||||||
echo handleRegisterPost();
|
echo handleRegisterPost();
|
||||||
|
unset($_SESSION['phrase']);
|
||||||
die();
|
die();
|
||||||
} elseif (isset($_POST['check_username'])) {
|
} elseif (isset($_POST['check_username'])) {
|
||||||
$username = $_POST['username'];
|
$username = $_POST['username'];
|
||||||
if (validateUsername($username) && !queryUser($username)) {
|
if (validateUsername($username) && !queryUser($username)) {
|
||||||
echo '{"ok" : true}';
|
die('{"ok": true}');
|
||||||
} else {
|
} else {
|
||||||
echo '{"ok" : false}';
|
die('{"ok": false}');
|
||||||
}
|
}
|
||||||
die();
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?php
|
|
||||||
$REQUIRE_LIB['md5'] = '';
|
|
||||||
$REQUIRE_LIB['dialog'] = '';
|
|
||||||
?>
|
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('register')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('register')) ?>
|
||||||
<h2 class="page-header"><?= UOJLocale::get('register') ?></h2>
|
|
||||||
<form id="form-register" class="form-horizontal">
|
|
||||||
|
<form id="form-register" class="card mw-100 mx-auto" style="width:600px">
|
||||||
|
<div class="card-body">
|
||||||
|
<h1 class="card-title text-center mb-3">
|
||||||
|
<?= UOJLocale::get('register') ?>
|
||||||
|
</h1>
|
||||||
<div id="div-email" class="form-group">
|
<div id="div-email" class="form-group">
|
||||||
<label for="input-email" class="col-sm-2 control-label"><?= UOJLocale::get('email') ?></label>
|
<label for="input-email" class="form-label"><?= UOJLocale::get('email') ?></label>
|
||||||
<div class="col-sm-3">
|
|
||||||
<input type="email" class="form-control" id="input-email" name="email" placeholder="<?= UOJLocale::get('enter your email') ?>" maxlength="50" />
|
<input type="email" class="form-control" id="input-email" name="email" placeholder="<?= UOJLocale::get('enter your email') ?>" maxlength="50" />
|
||||||
<span class="help-block" id="help-email"></span>
|
<span class="help-block" id="help-email"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id="div-username" class="form-group">
|
<div id="div-username" class="form-group">
|
||||||
<label for="input-username" class="col-sm-2 control-label"><?= UOJLocale::get('username') ?></label>
|
<label for="input-username" class="form-label"><?= UOJLocale::get('username') ?></label>
|
||||||
<div class="col-sm-3">
|
|
||||||
<input type="text" class="form-control" id="input-username" name="username" placeholder="<?= UOJLocale::get('enter your username') ?>" maxlength="20" />
|
<input type="text" class="form-control" id="input-username" name="username" placeholder="<?= UOJLocale::get('enter your username') ?>" maxlength="20" />
|
||||||
<span class="help-block" id="help-username"></span>
|
<span class="help-block" id="help-username"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id="div-password" class="form-group">
|
<div id="div-password" class="form-group">
|
||||||
<label for="input-password" class="col-sm-2 control-label"><?= UOJLocale::get('password') ?></label>
|
<label for="input-password" class="form-label"><?= UOJLocale::get('password') ?></label>
|
||||||
<div class="col-sm-3">
|
|
||||||
<input type="password" class="form-control" id="input-password" name="password" placeholder="<?= UOJLocale::get('enter your password') ?>" maxlength="20" />
|
<input type="password" class="form-control" id="input-password" name="password" placeholder="<?= UOJLocale::get('enter your password') ?>" maxlength="20" />
|
||||||
<input type="password" class="form-control top-buffer-sm" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your password') ?>" maxlength="20" />
|
<input type="password" class="form-control mt-2" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your password') ?>" maxlength="20" />
|
||||||
<span class="help-block" id="help-password"></span>
|
<span class="help-block" id="help-password"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="div-captcha" class="form-group">
|
||||||
|
<label for="input-captcha"><?= UOJLocale::get('verification code') ?></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" id="input-captcha" name="captcha" placeholder="<?= UOJLocale::get('enter verification code') ?>" maxlength="20" />
|
||||||
|
<span class="input-group-text p-0">
|
||||||
|
<img id="captcha" class="col w-100 h-100" src="/captcha">
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<div class="col-sm-offset-2 col-sm-3">
|
<div class="text-center">
|
||||||
<button type="submit" id="button-submit" class="btn btn-secondary"><?= UOJLocale::get('submit') ?></button>
|
<button type="submit" id="button-submit" class="btn btn-primary"><?= UOJLocale::get('submit') ?></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<div id="dialog" class="modal fade" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="modal-title"></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p id="modal-text"></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" aria-label="Close">好的</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
function refreshCaptcha() {
|
||||||
|
var timestamp = new Date().getTime();
|
||||||
|
$("#captcha").attr("src", "/captcha" + '?' + timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
function checkUsernameNotInUse() {
|
function checkUsernameNotInUse() {
|
||||||
var ok = false;
|
var ok = false;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@ -123,6 +131,7 @@ function checkUsernameNotInUse() {
|
|||||||
});
|
});
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateRegisterPost() {
|
function validateRegisterPost() {
|
||||||
var ok = true;
|
var ok = true;
|
||||||
ok &= getFormErrorAndShowHelp('email', validateEmail);
|
ok &= getFormErrorAndShowHelp('email', validateEmail);
|
||||||
@ -148,47 +157,40 @@ function submitRegisterPost() {
|
|||||||
register: '',
|
register: '',
|
||||||
username: $('#input-username').val(),
|
username: $('#input-username').val(),
|
||||||
email: $('#input-email').val(),
|
email: $('#input-email').val(),
|
||||||
password : md5($('#input-password').val(), "<?= getPasswordClientSalt() ?>")
|
password: md5($('#input-password').val(), "<?= getPasswordClientSalt() ?>"),
|
||||||
|
captcha: $('#input-captcha').val(),
|
||||||
}, function(msg) {
|
}, function(msg) {
|
||||||
if (/^欢迎你!/.test(msg)) {
|
if (/^欢迎你!/.test(msg)) {
|
||||||
BootstrapDialog.show({
|
|
||||||
title : '注册成功',
|
|
||||||
message : msg,
|
|
||||||
type : BootstrapDialog.TYPE_SUCCESS,
|
|
||||||
buttons: [{
|
|
||||||
label: '好的',
|
|
||||||
action: function(dialog) {
|
|
||||||
dialog.close();
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
onhidden : function(dialog) {
|
|
||||||
var prevUrl = document.referrer;
|
var prevUrl = document.referrer;
|
||||||
if (!prevUrl) {
|
if (!prevUrl) {
|
||||||
prevUrl = '/';
|
prevUrl = '/';
|
||||||
};
|
};
|
||||||
|
$('#modal-title').html('注册成功');
|
||||||
|
$('#modal-text').html(msg);
|
||||||
|
$('#dialog')
|
||||||
|
.modal('show')
|
||||||
|
.on('hidden.bs.modal', function() {
|
||||||
window.location.href = prevUrl;
|
window.location.href = prevUrl;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
refreshCaptcha();
|
||||||
} else {
|
} else {
|
||||||
BootstrapDialog.show({
|
$('#modal-title').html('注册失败');
|
||||||
title : '注册失败',
|
$('#modal-text').html(msg);
|
||||||
message : msg,
|
$('#dialog').modal('show');
|
||||||
type : BootstrapDialog.TYPE_DANGER,
|
refreshCaptcha();
|
||||||
buttons: [{
|
|
||||||
label: '好的',
|
|
||||||
action: function(dialog) {
|
|
||||||
dialog.close();
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
refreshCaptcha();
|
||||||
|
|
||||||
|
$('#captcha').click(refreshCaptcha);
|
||||||
|
|
||||||
$('#form-register').submit(function(e) {
|
$('#form-register').submit(function(e) {
|
||||||
submitRegisterPost();
|
submitRegisterPost();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requireLib('calendar_heatmap');
|
requireLib('calendar_heatmap');
|
||||||
requirePHPLib('form');
|
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader('关于我') ?>
|
<?php echoUOJPageHeader('关于我') ?>
|
||||||
|
|
||||||
<?php uojIncludeView('user-info', array('user' => UOJContext::user(), 'is_blog_aboutme' => '')) ?>
|
<?php uojIncludeView('user-info', ['user' => UOJUserBlog::user(), 'is_blog_aboutme' => true]) ?>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -4,37 +4,50 @@
|
|||||||
requireLib('hljs');
|
requireLib('hljs');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
|
$blogs_conds = [
|
||||||
|
"poster" => UOJUserBlog::id(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!UOJUserBlog::userCanManage(Auth::user())) {
|
||||||
|
$blogs_conds["is_hidden"] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
$display_blogs_conds = $blogs_conds;
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$blogs_cond = "poster = '".UOJContext::userid()."'";
|
|
||||||
if (!UOJContext::hasBlogPermission()) {
|
|
||||||
$blogs_cond .= " and is_hidden = false";
|
|
||||||
}
|
|
||||||
|
|
||||||
$display_blogs_cond = $blogs_cond;
|
|
||||||
|
|
||||||
if (isset($_GET['tag'])) {
|
if (isset($_GET['tag'])) {
|
||||||
$blog_tag_required = $_GET['tag'];
|
$blog_tag_required = $_GET['tag'];
|
||||||
$display_blogs_cond .= " and '".DB::escape($blog_tag_required)."' in (select tag from blogs_tags where blogs_tags.blog_id = blogs.id)";
|
|
||||||
|
$display_blogs_conds[] = [
|
||||||
|
DB::rawvalue($blog_tag_required), "in", DB::rawbracket([
|
||||||
|
"select tag from blogs_tags",
|
||||||
|
"where", ["blogs_tags.blog_id" => DB::raw("blogs.id")]
|
||||||
|
])
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
$blog_tag_required = null;
|
$blog_tag_required = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$blogs_pag = new Paginator(array(
|
$blogs_pag = new Paginator([
|
||||||
'col_names' => array('*'),
|
'col_names' => ['*'],
|
||||||
'table_name' => 'blogs',
|
'table_name' => 'blogs',
|
||||||
'cond' => $display_blogs_cond,
|
'cond' => $display_blogs_conds,
|
||||||
'tail' => 'order by post_time desc',
|
'tail' => 'order by post_time desc',
|
||||||
'page_len' => 15
|
'page_len' => 15
|
||||||
));
|
]);
|
||||||
|
|
||||||
$all_tags = DB::selectAll("select distinct tag from blogs_tags where blog_id in (select id from blogs where $blogs_cond)");
|
$all_tags = DB::selectAll([
|
||||||
|
"select distinct tag from blogs_tags",
|
||||||
|
"where", [
|
||||||
|
[
|
||||||
|
"blog_id", "in", DB::rawbracket([
|
||||||
|
"select id from blogs",
|
||||||
|
"where", $blogs_conds
|
||||||
|
])
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader('日志') ?>
|
<?php echoUOJPageHeader('日志') ?>
|
||||||
|
|
||||||
@ -55,21 +68,24 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php $cnt = 0 ?>
|
<?php $cnt = 0; ?>
|
||||||
<?php foreach ($blogs_pag->get() as $blog): ?>
|
<?php foreach ($blogs_pag->get() as $blog_info) : ?>
|
||||||
<?php $cnt++ ?>
|
<?php
|
||||||
|
$blog = new UOJBlog($blog_info);
|
||||||
|
$cnt++;
|
||||||
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<?php if ($blog['is_hidden']): ?>
|
<?php if ($blog->info['is_hidden']) : ?>
|
||||||
<span class="text-danger">[隐藏]</span>
|
<span class="text-danger">[隐藏]</span>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?= getBlogLink($blog['id']) ?>
|
<?= $blog->getLink() ?>
|
||||||
<?php foreach (queryBlogTags($blog['id']) as $tag): ?>
|
<?php foreach ($blog->queryTags() as $tag) : ?>
|
||||||
<?php echoBlogTag($tag) ?>
|
<?php echoBlogTag($tag) ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</td>
|
</td>
|
||||||
<td><?= $blog['post_time'] ?></td>
|
<td><?= $blog->info['post_time'] ?></td>
|
||||||
<td><?= getClickZanBlock('B', $blog['id'], $blog['zan'], null, false) ?></td>
|
<td><?= ClickZans::getBlock('B', $blog->info['id'], $blog->info['zan'], null, false) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -96,23 +112,24 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>标题</th>
|
<th>标题</th>
|
||||||
<th style="width: 20%">发表时间</th>
|
<th style="width: 20%">发表时间</th>
|
||||||
<th class="text-center" style="width: 180px">评价</th>
|
<th class="text-center" style="width: 100px">评价</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($blogs_pag->get() as $blog): ?>
|
<?php foreach ($blogs_pag->get() as $blog_info) : ?>
|
||||||
|
<?php $blog = new UOJBlog($blog_info); ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<?php if ($blog['is_hidden']): ?>
|
<?php if ($blog->info['is_hidden']) : ?>
|
||||||
<span class="text-danger">[隐藏]</span>
|
<span class="text-danger">[隐藏]</span>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?= getBlogLink($blog['id']) ?>
|
<?= $blog->getLink() ?>
|
||||||
<?php foreach (queryBlogTags($blog['id']) as $tag): ?>
|
<?php foreach ($blog->queryTags() as $tag) : ?>
|
||||||
<?php echoBlogTag($tag) ?>
|
<?php echoBlogTag($tag) ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</td>
|
</td>
|
||||||
<td><?= $blog['post_time'] ?></td>
|
<td><?= $blog->info['post_time'] ?></td>
|
||||||
<td><?= getClickZanBlock('B', $blog['id'], $blog['zan']) ?></td>
|
<td><?= ClickZans::getBlock('B', $blog->info['id'], $blog->info['zan'], null, false) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -127,13 +144,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<?php if (UOJContext::hasBlogPermission()): ?>
|
<?php if (UOJUserBlog::userCanManage(Auth::user())) : ?>
|
||||||
<div class="btn-group d-flex">
|
<div class="btn-group d-flex">
|
||||||
<a href="<?= HTML::blog_url(UOJContext::userid(), '/post/new/write') ?>" class="btn btn-primary">
|
<a href="<?= HTML::blog_url(UOJUserBlog::id(), '/post/new/write') ?>" class="btn btn-primary">
|
||||||
<i class="bi bi-pencil-square"></i>
|
<i class="bi bi-pencil-square"></i>
|
||||||
写新博客
|
写新博客
|
||||||
</a>
|
</a>
|
||||||
<a href="<?= HTML::blog_url(UOJContext::userid(), '/slide/new/write') ?>" class="btn btn-primary">
|
<a href="<?= HTML::blog_url(UOJUserBlog::id(), '/slide/new/write') ?>" class="btn btn-primary">
|
||||||
<i class="bi bi-file-earmark-slides"></i>
|
<i class="bi bi-file-earmark-slides"></i>
|
||||||
写新幻灯片
|
写新幻灯片
|
||||||
</a>
|
</a>
|
||||||
|
@ -4,21 +4,24 @@
|
|||||||
requireLib('hljs');
|
requireLib('hljs');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
|
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
|
||||||
|
UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403();
|
||||||
|
|
||||||
|
$blog = UOJBlog::info();
|
||||||
|
|
||||||
|
function getCommentContentToDisplay($comment) {
|
||||||
|
if (!$comment['is_hidden']) {
|
||||||
|
return $comment['content'];
|
||||||
|
} else {
|
||||||
|
return '<span class="text-muted">【' . HTML::escape($comment['reason_to_hide']) . '】</span>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($_GET['id']) || !validateUInt($_GET['id']) || !($blog = queryBlog($_GET['id'])) || !UOJContext::isHis($blog)) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
if ($blog['is_hidden'] && !UOJContext::hasBlogPermission()) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$solutions = DB::selectAll("select * from problems_solutions where blog_id = {$blog['id']}");
|
$solutions = DB::selectAll("select * from problems_solutions where blog_id = {$blog['id']}");
|
||||||
if ($solutions) {
|
if ($solutions) {
|
||||||
foreach ($solutions as $solution) {
|
foreach ($solutions as $solution) {
|
||||||
@ -30,11 +33,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$comment_form = new UOJForm('comment');
|
$comment_form = new UOJBs4Form('comment');
|
||||||
$comment_form->addVTextArea('comment', '内容', '',
|
$comment_form->addVTextArea(
|
||||||
|
'comment',
|
||||||
|
'内容',
|
||||||
|
'',
|
||||||
function ($comment) {
|
function ($comment) {
|
||||||
global $myUser;
|
if (Auth::check()) {
|
||||||
if ($myUser == null) {
|
|
||||||
return '请先登录';
|
return '请先登录';
|
||||||
}
|
}
|
||||||
if (!$comment) {
|
if (!$comment) {
|
||||||
@ -53,11 +58,21 @@
|
|||||||
|
|
||||||
list($comment, $referrers) = uojHandleAtSign($comment, "/post/{$blog['id']}");
|
list($comment, $referrers) = uojHandleAtSign($comment, "/post/{$blog['id']}");
|
||||||
|
|
||||||
$esc_comment = DB::escape($comment);
|
DB::insert([
|
||||||
DB::insert("insert into blogs_comments (poster, blog_id, content, reply_id, post_time, zan) values ('{$myUser['username']}', '{$blog['id']}', '$esc_comment', 0, now(), 0)");
|
"insert into blogs_comments",
|
||||||
|
"(poster, blog_id, content, reply_id, post_time)",
|
||||||
|
"values", DB::tuple([Auth::id(), $blog['id'], $comment, 0, DB::now()])
|
||||||
|
]);
|
||||||
$comment_id = DB::insert_id();
|
$comment_id = DB::insert_id();
|
||||||
|
|
||||||
$rank = DB::selectCount("select count(*) from blogs_comments where blog_id = {$blog['id']} and reply_id = 0 and id < {$comment_id}");
|
$rank = DB::selectCount([
|
||||||
|
"select count(*) from blogs_comments",
|
||||||
|
"where", [
|
||||||
|
"blog_id" => $blog['id'],
|
||||||
|
"reply_id" => 0,
|
||||||
|
["id", "<", $comment_id]
|
||||||
|
]
|
||||||
|
]);
|
||||||
$page = floor($rank / 20) + 1;
|
$page = floor($rank / 20) + 1;
|
||||||
|
|
||||||
$uri = getLongTablePageUri($page) . '#' . "comment-{$comment_id}";
|
$uri = getLongTablePageUri($page) . '#' . "comment-{$comment_id}";
|
||||||
@ -68,24 +83,27 @@
|
|||||||
sendSystemMsg($referrer, '有人提到你', $content);
|
sendSystemMsg($referrer, '有人提到你', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($blog['poster'] !== $myUser['username']) {
|
if ($blog['poster'] !== Auth::id()) {
|
||||||
$content = $user_link . ' 回复了您的博客 ' . $blog['title'] . ' :<a href="' . $uri . '">点击此处查看</a>';
|
$content = $user_link . ' 回复了您的博客 ' . $blog['title'] . ' :<a href="' . $uri . '">点击此处查看</a>';
|
||||||
sendSystemMsg($blog['poster'], '博客新回复通知', $content);
|
sendSystemMsg($blog['poster'], '博客新回复通知', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UOJBlog::cur()->updateActiveTime();
|
||||||
$comment_form->succ_href = getLongTablePageRawUri($page);
|
$comment_form->succ_href = getLongTablePageRawUri($page);
|
||||||
};
|
};
|
||||||
$comment_form->ctrl_enter_submit = true;
|
$comment_form->ctrl_enter_submit = true;
|
||||||
$comment_form->runAtServer();
|
$comment_form->runAtServer();
|
||||||
|
|
||||||
$reply_form = new UOJForm('reply');
|
$reply_form = new UOJBs4Form('reply');
|
||||||
$reply_form->addHidden('reply_id', '0',
|
$reply_form->addHidden(
|
||||||
|
'reply_id',
|
||||||
|
'0',
|
||||||
function ($reply_id, &$vdata) {
|
function ($reply_id, &$vdata) {
|
||||||
global $blog;
|
global $blog;
|
||||||
if (!validateUInt($reply_id) || $reply_id == 0) {
|
if (!validateUInt($reply_id) || $reply_id == 0) {
|
||||||
return '您要回复的对象不存在';
|
return '您要回复的对象不存在';
|
||||||
}
|
}
|
||||||
$comment = queryBlogComment($reply_id);
|
$comment = UOJBlogComment::query($reply_id);
|
||||||
if (!$comment || $comment['blog_id'] != $blog['id']) {
|
if (!$comment || $comment['blog_id'] != $blog['id']) {
|
||||||
return '您要回复的对象不存在';
|
return '您要回复的对象不存在';
|
||||||
}
|
}
|
||||||
@ -94,10 +112,12 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$reply_form->addVTextArea('reply_comment', '内容', '',
|
$reply_form->addVTextArea(
|
||||||
|
'reply_comment',
|
||||||
|
'内容',
|
||||||
|
'',
|
||||||
function ($comment) {
|
function ($comment) {
|
||||||
global $myUser;
|
if (!Auth::check()) {
|
||||||
if ($myUser == null) {
|
|
||||||
return '请先登录';
|
return '请先登录';
|
||||||
}
|
}
|
||||||
if (!$comment) {
|
if (!$comment) {
|
||||||
@ -118,11 +138,21 @@
|
|||||||
|
|
||||||
$reply_id = $_POST['reply_id'];
|
$reply_id = $_POST['reply_id'];
|
||||||
|
|
||||||
$esc_comment = DB::escape($comment);
|
DB::insert([
|
||||||
DB::insert("insert into blogs_comments (poster, blog_id, content, reply_id, post_time, zan) values ('{$myUser['username']}', '{$blog['id']}', '$esc_comment', $reply_id, now(), 0)");
|
"insert into blogs_comments",
|
||||||
|
"(poster, blog_id, content, reply_id, post_time)",
|
||||||
|
"values", DB::tuple([Auth::id(), $blog['id'], $comment, $reply_id, DB::now()])
|
||||||
|
]);
|
||||||
$comment_id = DB::insert_id();
|
$comment_id = DB::insert_id();
|
||||||
|
|
||||||
$rank = DB::selectCount("select count(*) from blogs_comments where blog_id = {$blog['id']} and reply_id = 0 and id < {$reply_id}");
|
$rank = DB::selectCount([
|
||||||
|
"select count(*) from blogs_comments",
|
||||||
|
"where", [
|
||||||
|
"blog_id" => $blog['id'],
|
||||||
|
"reply_id" => 0,
|
||||||
|
["id", "<", $reply_id]
|
||||||
|
]
|
||||||
|
]);
|
||||||
$page = floor($rank / 20) + 1;
|
$page = floor($rank / 20) + 1;
|
||||||
|
|
||||||
$uri = getLongTablePageUri($page) . '#' . "comment-{$reply_id}";
|
$uri = getLongTablePageUri($page) . '#' . "comment-{$reply_id}";
|
||||||
@ -134,50 +164,59 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$parent = $vdata['parent'];
|
$parent = $vdata['parent'];
|
||||||
$notified = array();
|
$notified = [];
|
||||||
if ($parent['poster'] !== $myUser['username']) {
|
if ($parent->info['poster'] !== Auth::id()) {
|
||||||
$notified[] = $parent['poster'];
|
$notified[] = $parent->info['poster'];
|
||||||
$content = $user_link . ' 回复了您在博客 ' . $blog['title'] . ' 下的评论 :<a href="' . $uri . '">点击此处查看</a>';
|
$content = $user_link . ' 回复了您在博客 ' . $blog['title'] . ' 下的评论 :<a href="' . $uri . '">点击此处查看</a>';
|
||||||
sendSystemMsg($parent['poster'], '评论新回复通知', $content);
|
sendSystemMsg($parent->info['poster'], '评论新回复通知', $content);
|
||||||
}
|
}
|
||||||
if ($blog['poster'] !== $myUser['username'] && !in_array($blog['poster'], $notified)) {
|
if ($blog['poster'] !== Auth::id() && !in_array($blog['poster'], $notified)) {
|
||||||
$notified[] = $blog['poster'];
|
$notified[] = $blog['poster'];
|
||||||
$content = $user_link . '回复了您的博客 ' . $blog['title'] . ' :<a href="' . $uri . '">点击此处查看</a>';
|
$content = $user_link . '回复了您的博客 ' . $blog['title'] . ' :<a href="' . $uri . '">点击此处查看</a>';
|
||||||
sendSystemMsg($blog['poster'], '博客新回复通知', $content);
|
sendSystemMsg($blog['poster'], '博客新回复通知', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UOJBlog::cur()->updateActiveTime();
|
||||||
|
|
||||||
$reply_form->succ_href = getLongTablePageRawUri($page);
|
$reply_form->succ_href = getLongTablePageRawUri($page);
|
||||||
};
|
};
|
||||||
$reply_form->ctrl_enter_submit = true;
|
$reply_form->ctrl_enter_submit = true;
|
||||||
|
|
||||||
$reply_form->runAtServer();
|
$reply_form->runAtServer();
|
||||||
|
|
||||||
$comments_pag = new Paginator(array(
|
$comments_pag = new Paginator([
|
||||||
'col_names' => array('*'),
|
'col_names' => ['*'],
|
||||||
'table_name' => 'blogs_comments',
|
'table_name' => 'blogs_comments',
|
||||||
'cond' => 'blog_id = ' . $blog['id'] . ' and reply_id = 0',
|
'cond' => 'blog_id = ' . $blog['id'] . ' and reply_id = 0',
|
||||||
'tail' => 'order by id asc',
|
'tail' => 'order by id asc',
|
||||||
'page_len' => 20
|
'page_len' => 20
|
||||||
));
|
]);
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(HTML::stripTags($blog['title']) . ' - 博客') ?>
|
<?php echoUOJPageHeader(HTML::stripTags($blog['title']) . ' - 博客') ?>
|
||||||
<?php echoBlog($blog, array('show_title_only' => isset($_GET['page']) && $_GET['page'] != 1)) ?>
|
<?php UOJBlog::cur()->echoView(['show_title_only' => isset($_GET['page']) && $_GET['page'] != 1]) ?>
|
||||||
|
|
||||||
<h2>
|
<h2>
|
||||||
评论
|
评论
|
||||||
<i class="bi bi-chat-fill"></i>
|
<i class="bi bi-chat-fill"></i>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<?php if ($comments_pag->isEmpty()) : ?>
|
<?php if ($comments_pag->isEmpty()) : ?>
|
||||||
<div class="list-group-item text-muted">暂无评论</div>
|
<div class="list-group-item text-muted">暂无评论</div>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<?php foreach ($comments_pag->get() as $comment) :
|
<?php foreach ($comments_pag->get() as $comment) :
|
||||||
$poster = queryUser($comment['poster']);
|
$poster = UOJUser::query($comment['poster']);
|
||||||
$esc_email = HTML::escape($poster['email']);
|
$esc_email = HTML::escape($poster['email']);
|
||||||
$asrc = HTML::avatar_addr($poster, 80);
|
$asrc = HTML::avatar_addr($poster, 80);
|
||||||
|
|
||||||
$replies = DB::selectAll("select id, poster, content, post_time from blogs_comments where reply_id = {$comment['id']} order by id");
|
$replies = DB::selectAll([
|
||||||
|
"select id, poster, content, post_time, is_hidden, reason_to_hide from blogs_comments",
|
||||||
|
"where", ["reply_id" => $comment['id']],
|
||||||
|
"order by id"
|
||||||
|
]);
|
||||||
foreach ($replies as $idx => $reply) {
|
foreach ($replies as $idx => $reply) {
|
||||||
$replies[$idx]['poster_realname'] = queryUser($reply['poster'])['realname'];
|
$replies[$idx]['poster_realname'] = UOJUser::query($reply['poster'])['realname'];
|
||||||
|
$replies[$idx]['content'] = getCommentContentToDisplay($reply);
|
||||||
}
|
}
|
||||||
$replies_json = json_encode($replies);
|
$replies_json = json_encode($replies);
|
||||||
?>
|
?>
|
||||||
@ -191,7 +230,7 @@
|
|||||||
<div id="comment-body-<?= $comment['id'] ?>" class="comtbox flex-grow-1 ms-3">
|
<div id="comment-body-<?= $comment['id'] ?>" class="comtbox flex-grow-1 ms-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6"><?= getUserLink($poster['username']) ?></div>
|
<div class="col-sm-6"><?= getUserLink($poster['username']) ?></div>
|
||||||
<div class="col-sm-6 text-end"><?= getClickZanBlock('BC', $comment['id'], $comment['zan']) ?></div>
|
<div class="col-sm-6 text-end"><?= ClickZans::getBlock('BC', $comment['id'], $comment['zan']) ?></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="comtbox1"><?= $comment['content'] ?></div>
|
<div class="comtbox1"><?= $comment['content'] ?></div>
|
||||||
<ul class="list-inline mb-0 text-end">
|
<ul class="list-inline mb-0 text-end">
|
||||||
@ -209,7 +248,9 @@
|
|||||||
<?php if ($replies) : ?>
|
<?php if ($replies) : ?>
|
||||||
<div id="replies-<?= $comment['id'] ?>" class="comtbox5"></div>
|
<div id="replies-<?= $comment['id'] ?>" class="comtbox5"></div>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<script type="text/javascript">showCommentReplies('<?= $comment['id'] ?>', <?= $replies_json ?>);</script>
|
<script type="text/javascript">
|
||||||
|
showCommentReplies('<?= $comment['id'] ?>', <?= $replies_json ?>);
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,48 +2,28 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become403Page();
|
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
|
||||||
}
|
UOJBlog::cur()->userCanManage(Auth::user()) || UOJResponse::page403();
|
||||||
|
|
||||||
if (!UOJContext::hasBlogPermission()) {
|
$delete_form = new UOJBs4Form('delete');
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
if (!isset($_GET['id']) || !validateUInt($_GET['id']) || !($blog = queryBlog($_GET['id'])) || !UOJContext::isHis($blog)) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$delete_form = new UOJForm('delete');
|
|
||||||
$delete_form->handle = function () {
|
$delete_form->handle = function () {
|
||||||
global $myUser, $blog;
|
UOJBlog::cur()->delete();
|
||||||
|
|
||||||
if ($myUser['username'] != $blog['poster']) {
|
|
||||||
$poster_user_link = getUserLink($blog['poster']);
|
|
||||||
$admin_user_link = isSuperUser($myUser) ? '管理员' : getUserLink($myUser['username']);
|
|
||||||
$blog_content = HTML::escape($blog['content_md']);
|
|
||||||
$content = <<<EOD
|
|
||||||
<p>{$poster_user_link} 您好:</p>
|
|
||||||
<p>您的博客 <b>{$blog['title']}</b>(ID:{$blog['id']})已经被 {$admin_user_link} 删除,现将博客原文备份发送给您,请查收。</p>
|
|
||||||
<pre><code class="language-markdown">{$blog_content}</code></pre>
|
|
||||||
EOD;
|
|
||||||
sendSystemMsg($blog['poster'], '博客删除通知', $content);
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteBlog($blog['id']);
|
|
||||||
};
|
};
|
||||||
$delete_form->submit_button_config['class_str'] = 'btn btn-danger';
|
$delete_form->submit_button_config['class_str'] = 'btn btn-danger';
|
||||||
$delete_form->submit_button_config['text'] = '是的,我确定要删除';
|
$delete_form->submit_button_config['text'] = '是的,我确定要删除';
|
||||||
$delete_form->succ_href = HTML::blog_url($blog['poster'], '/archive');
|
$delete_form->succ_href = HTML::blog_url(UOJBlog::info('poster'), '/archive');
|
||||||
|
|
||||||
$delete_form->runAtServer();
|
$delete_form->runAtServer();
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader('删除博客 - ' . HTML::stripTags($blog['title'])) ?>
|
<?php echoUOJPageHeader('删除博客 - ' . HTML::stripTags(UOJBlog::info('title'))) ?>
|
||||||
<h1 class="h3 text-center">
|
|
||||||
您真的要删除博客 “<?= $blog['title'] ?>” <span class="fs-5">(博客 ID:<?= $blog['id'] ?>)</span>吗?该操作不可逆!
|
<h1 class="h2 text-center">
|
||||||
|
您真的要删除博客 “<?= UOJBlog::info('title') ?>” <span class="fs-5">(博客 ID:<?= UOJBlog::info('id') ?>)</span>吗?该操作不可逆!
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<?php $delete_form->printHTML(); ?>
|
<?php $delete_form->printHTML(); ?>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -2,21 +2,19 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
UOJUserBlog::userCanManage(Auth::user()) || UOJResponse::page403();
|
||||||
|
|
||||||
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UOJContext::hasBlogPermission()) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
if (isset($_GET['id'])) {
|
if (isset($_GET['id'])) {
|
||||||
if (!validateUInt($_GET['id']) || !($blog = queryBlog($_GET['id'])) || !UOJContext::isHisBlog($blog)) {
|
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become404Page();
|
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
|
||||||
}
|
UOJBlog::info('type') == 'B' || UOJResponse::page404();
|
||||||
|
$blog = UOJBlog::info();
|
||||||
|
$blog['content'] = UOJBlog::cur()->queryContent()['content'];
|
||||||
|
$blog['content_md'] = UOJBlog::cur()->queryContent()['content_md'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$blog_editor = new UOJBlogEditor();
|
$blog_editor = new UOJBlogEditor();
|
||||||
@ -26,7 +24,7 @@
|
|||||||
'title' => $blog['title'],
|
'title' => $blog['title'],
|
||||||
'content_md' => $blog['content_md'],
|
'content_md' => $blog['content_md'],
|
||||||
'content' => $blog['content'],
|
'content' => $blog['content'],
|
||||||
'tags' => queryBlogTags($blog['id']),
|
'tags' => UOJBlog::cur()->queryTags(),
|
||||||
'is_hidden' => $blog['is_hidden']
|
'is_hidden' => $blog['is_hidden']
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -34,41 +32,53 @@
|
|||||||
'title' => $_GET['title'] ?: '新博客',
|
'title' => $_GET['title'] ?: '新博客',
|
||||||
'content_md' => '',
|
'content_md' => '',
|
||||||
'content' => '',
|
'content' => '',
|
||||||
'tags' => array(),
|
'tags' => [],
|
||||||
'is_hidden' => isset($_GET['is_hidden']) ? $_GET['is_hidden'] : true,
|
'is_hidden' => isset($_GET['is_hidden']) ? $_GET['is_hidden'] : true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ($blog) {
|
if ($blog) {
|
||||||
$blog_editor->blog_url = HTML::blog_url(UOJContext::userid(), "/post/{$blog['id']}");
|
$blog_editor->blog_url = HTML::blog_url(UOJUserBlog::id(), "/post/{$blog['id']}");
|
||||||
} else {
|
} else {
|
||||||
$blog_editor->blog_url = null;
|
$blog_editor->blog_url = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBlog($id, $data) {
|
function updateBlog($id, $data) {
|
||||||
DB::update("update blogs set title = '".DB::escape($data['title'])."', content = '".DB::escape($data['content'])."', content_md = '".DB::escape($data['content_md'])."', is_hidden = {$data['is_hidden']} where id = {$id}");
|
DB::update([
|
||||||
|
"update blogs",
|
||||||
|
"set", [
|
||||||
|
"title" => $data['title'],
|
||||||
|
"content" => $data['content'],
|
||||||
|
"content_md" => $data['content_md'],
|
||||||
|
"is_hidden" => $data['is_hidden']
|
||||||
|
],
|
||||||
|
"where", ["id" => $id]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
function insertBlog($data) {
|
function insertBlog($data) {
|
||||||
DB::insert("insert into blogs (title, content, content_md, poster, is_hidden, post_time) values ('".DB::escape($data['title'])."', '".DB::escape($data['content'])."', '".DB::escape($data['content_md'])."', '".UOJContext::userid()."', {$data['is_hidden']}, now())");
|
DB::insert([
|
||||||
|
"insert into blogs",
|
||||||
|
"(title, content, content_md, poster, is_hidden, post_time, active_time)",
|
||||||
|
"values", DB::tuple([
|
||||||
|
$data['title'], $data['content'], $data['content_md'],
|
||||||
|
UOJUserBlog::id(), $data['is_hidden'], DB::now(), DB::now()
|
||||||
|
])
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$blog_editor->save = function ($data) {
|
$blog_editor->save = function ($data) {
|
||||||
global $blog;
|
global $blog;
|
||||||
$ret = array();
|
$ret = [];
|
||||||
if ($blog) {
|
if ($blog) {
|
||||||
updateBlog($blog['id'], $data);
|
updateBlog($blog['id'], $data);
|
||||||
} else {
|
} else {
|
||||||
insertBlog($data);
|
insertBlog($data);
|
||||||
$blog = array('id' => DB::insert_id(), 'tags' => array());
|
$blog_id = DB::insert_id();
|
||||||
$ret['blog_id'] = $blog['id'];
|
(new UOJBlog(['id' => $blog_id, 'type' => 'B']))->setAsCur();
|
||||||
$ret['blog_write_url'] = HTML::blog_url(UOJContext::userid(), "/post/{$blog['id']}/write");
|
$ret['blog_id'] = $blog_id;
|
||||||
$ret['blog_url'] = HTML::blog_url(UOJContext::userid(), "/post/{$blog['id']}");
|
$ret['blog_write_url'] = UOJBlog::cur()->getUriForWrite();
|
||||||
}
|
$ret['blog_url'] = UOJBlog::cur()->getBlogUri();
|
||||||
if ($data['tags'] !== $blog['tags']) {
|
|
||||||
DB::delete("delete from blogs_tags where blog_id = {$blog['id']}");
|
|
||||||
foreach ($data['tags'] as $tag) {
|
|
||||||
DB::insert("insert into blogs_tags (blog_id, tag) values ({$blog['id']}, '".DB::escape($tag)."')");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
UOJBlog::cur()->updateTags($data['tags']);
|
||||||
return $ret;
|
return $ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,11 +89,7 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header bg-transparent d-flex justify-content-between">
|
<div class="card-header bg-transparent d-flex justify-content-between">
|
||||||
<div class="fw-bold">写博客</div>
|
<div class="fw-bold">写博客</div>
|
||||||
<div id="div-blog-id"
|
<div id="div-blog-id" <?php if (!$blog) : ?> style="display: none" <?php endif ?>>
|
||||||
<?php if (!$blog): ?>
|
|
||||||
style="display: none"
|
|
||||||
<?php endif ?>
|
|
||||||
>
|
|
||||||
<?php if ($blog) : ?>
|
<?php if ($blog) : ?>
|
||||||
<small>博客 ID:<b><?= $blog['id'] ?></b></small>
|
<small>博客 ID:<b><?= $blog['id'] ?></b></small>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
@ -97,7 +103,7 @@
|
|||||||
<!-- 提示信息 -->
|
<!-- 提示信息 -->
|
||||||
<div class="card mt-3">
|
<div class="card mt-3">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="h4 card-title">提示</h2>
|
<h2 class="h3 card-title">提示</h2>
|
||||||
<ol>
|
<ol>
|
||||||
<li>题解发布后还需要返回对应题目的题解页面 <b>手动输入博客 ID</b> 来将本文添加到题目的题解列表中(博客 ID 可以在右上角找到);</li>
|
<li>题解发布后还需要返回对应题目的题解页面 <b>手动输入博客 ID</b> 来将本文添加到题目的题解列表中(博客 ID 可以在右上角找到);</li>
|
||||||
<li>请勿引用不稳定的外部资源(如来自个人服务器的图片或文档等),以便备份及后期维护;</li>
|
<li>请勿引用不稳定的外部资源(如来自个人服务器的图片或文档等),以便备份及后期维护;</li>
|
||||||
|
@ -3,48 +3,43 @@
|
|||||||
requireLib('hljs');
|
requireLib('hljs');
|
||||||
requireLib('mathjax');
|
requireLib('mathjax');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
$blogs_pag = new Paginator([
|
||||||
become403Page();
|
'col_names' => ['*'],
|
||||||
}
|
|
||||||
|
|
||||||
$blogs_pag = new Paginator(array(
|
|
||||||
'col_names' => array('*'),
|
|
||||||
'table_name' => 'blogs',
|
'table_name' => 'blogs',
|
||||||
'cond' => "poster = '".UOJContext::userid()."' and is_hidden = 0",
|
'cond' => "poster = '" . UOJUserBlog::id() . "' and is_hidden = 0",
|
||||||
'tail' => 'order by post_time desc',
|
'tail' => 'order by post_time desc',
|
||||||
'page_len' => 5
|
'page_len' => 5
|
||||||
));
|
]);
|
||||||
|
|
||||||
$all_tags = DB::selectAll("select distinct tag from blogs_tags where blog_id in (select id from blogs where $blogs_cond)");
|
$all_tags = DB::selectAll("select distinct tag from blogs_tags where blog_id in (select id from blogs where $blogs_cond)");
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJContext::user()['username'] . '的博客') ?>
|
<?php echoUOJPageHeader(UOJUserBlog::id() . '的博客') ?>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
<?php if ($blogs_pag->isEmpty()) : ?>
|
<?php if ($blogs_pag->isEmpty()) : ?>
|
||||||
<div class="text-muted">此人很懒,什么博客也没留下。</div>
|
<div class="text-muted">此人很懒,什么博客也没留下。</div>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<?php foreach ($blogs_pag->get() as $blog): ?>
|
<?php
|
||||||
<?php echoBlog($blog, array('is_preview' => true)) ?>
|
foreach ($blogs_pag->get() as $blog_info) {
|
||||||
<?php endforeach ?>
|
$blog = new UOJBlog($blog_info);
|
||||||
|
$blog->echoView(['is_preview' => true]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<div class="text-center">
|
<?= $blogs_pag->pagination() ?>
|
||||||
<?= $blogs_pag->pagination(); ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-3">
|
||||||
<img class="media-object img-thumbnail center-block" alt="<?= UOJContext::user()['username'] ?> Avatar" src="<?= HTML::avatar_addr(UOJContext::user(), 512) ?>" />
|
<img class="media-object img-thumbnail center-block" alt="<?= UOJUserBlog::id() ?> Avatar" src="<?= HTML::avatar_addr(UOJUserBlog::user(), 512) ?>" />
|
||||||
<?php if (UOJContext::hasBlogPermission()): ?>
|
<?php if (UOJUserBlog::userCanManage(Auth::user())) : ?>
|
||||||
<div class="btn-group d-flex mt-3">
|
<div class="btn-group d-flex mt-3">
|
||||||
<a href="<?= HTML::blog_url(UOJContext::userid(), '/post/new/write') ?>" class="btn btn-primary">
|
<a href="<?= HTML::blog_url(UOJUserBlog::id(), '/post/new/write') ?>" class="btn btn-primary">
|
||||||
<i class="bi bi-pencil-square"></i>
|
<i class="bi bi-pencil-square"></i>
|
||||||
写新博客
|
写新博客
|
||||||
</a>
|
</a>
|
||||||
<a href="<?= HTML::blog_url(UOJContext::userid(), '/slide/new/write') ?>" class="btn btn-primary">
|
<a href="<?= HTML::blog_url(UOJUserBlog::id(), '/slide/new/write') ?>" class="btn btn-primary">
|
||||||
<i class="bi bi-file-earmark-slides"></i>
|
<i class="bi bi-file-earmark-slides"></i>
|
||||||
写新幻灯片
|
写新幻灯片
|
||||||
</a>
|
</a>
|
||||||
@ -64,4 +59,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -19,20 +19,24 @@ call_user_func(function() { // to prevent variable scope leak
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Route::group([
|
Route::group(
|
||||||
|
[
|
||||||
'domain' => UOJConfig::$data['web']['blog']['host']
|
'domain' => UOJConfig::$data['web']['blog']['host']
|
||||||
], function() {
|
],
|
||||||
|
function () {
|
||||||
Route::any("/", '/blogs.php');
|
Route::any("/", '/blogs.php');
|
||||||
Route::any("/blogs/{id}", '/blog_show.php');
|
Route::any("/blogs/{id}", '/blog_show.php');
|
||||||
Route::any("/post/{id}", '/blog_show.php');
|
Route::any("/post/{id}", '/blog_show.php');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Route::group([
|
Route::group(
|
||||||
|
[
|
||||||
'domain' => $domain,
|
'domain' => $domain,
|
||||||
'onload' => function () {
|
'onload' => function () {
|
||||||
UOJContext::setupBlog();
|
UOJContext::setupBlog();
|
||||||
}
|
}
|
||||||
], function() use ($prefix) {
|
],
|
||||||
|
function () use ($prefix) {
|
||||||
Route::any("$prefix/", '/subdomain/blog/index.php');
|
Route::any("$prefix/", '/subdomain/blog/index.php');
|
||||||
Route::any("$prefix/archive", '/subdomain/blog/archive.php');
|
Route::any("$prefix/archive", '/subdomain/blog/archive.php');
|
||||||
Route::any("$prefix/aboutme", '/subdomain/blog/aboutme.php');
|
Route::any("$prefix/aboutme", '/subdomain/blog/aboutme.php');
|
||||||
|
@ -1,75 +1,77 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requireLib('mathjax');
|
requireLib('mathjax');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
$username = UOJContext::userid();
|
Auth::check() || redirectToLogin();
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('contests::contest self reviews')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('contests::contest self reviews')) ?>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= $username ?> 的所有赛后总结
|
<?= UOJUserBlog::id() ?> 的所有赛后总结
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$col_names = array('contest_id');
|
$col_names = ['contest_id'];
|
||||||
$from = 'contests_registrants a left join contests b on a.contest_id = b.id';
|
$from = 'contests_registrants inner join contests on contests_registrants.contest_id = contests.id';
|
||||||
$cond = "username = '$username' and has_participated = 1";
|
$cond = ["username" => UOJUserBlog::id(), "has_participated" => 1];
|
||||||
$tail = 'order by start_time desc, id desc';
|
$tail = 'order by start_time desc, id desc';
|
||||||
$config = array(
|
$config = [
|
||||||
'pagination_table' => 'contests_registrants',
|
|
||||||
'page_len' => 10,
|
'page_len' => 10,
|
||||||
'div_classes' => ['card', 'card-default', 'table-responsive'],
|
'div_classes' => ['card', 'card-default', 'table-responsive'],
|
||||||
'table_classes' => ['table', 'table-bordered', 'text-center', 'align-middle', 'uoj-table', 'mb-0'],
|
'table_classes' => ['table', 'table-bordered', 'text-center', 'align-middle', 'uoj-table', 'mb-0'],
|
||||||
);
|
];
|
||||||
|
|
||||||
$header_row = '';
|
$header_row = '';
|
||||||
$header_row .= '<tr>';
|
$header_row .= '<tr>';
|
||||||
$header_row .= '<th style="width: 28em;">'.UOJLocale::get('contests::contest name').'</th>';
|
$header_row .= '<th style="width:28em">' . UOJLocale::get('contests::contest name') . '</th>';
|
||||||
$header_row .= '<th style="width: 14em;">'.UOJLocale::get('problems::problem').'</th>';
|
$header_row .= '<th style="width:14em">' . UOJLocale::get('problems::problem') . '</th>';
|
||||||
$header_row .= '<th style="width: 35em;">'.UOJLocale::get('contests::problem self review').'</th>';
|
$header_row .= '<th style="width:35em">' . UOJLocale::get('contests::problem self review') . '</th>';
|
||||||
$header_row .= '<th style="width: 35em;">'.UOJLocale::get('contests::contest self review').'</th>';
|
$header_row .= '<th style="width:35em">' . UOJLocale::get('contests::contest self review') . '</th>';
|
||||||
$header_row .= '</tr>';
|
$header_row .= '</tr>';
|
||||||
|
|
||||||
$parsedown = HTML::parsedown();
|
$parsedown = HTML::parsedown();
|
||||||
$purifier = HTML::purifier_inline();
|
$purifier = HTML::purifier_inline();
|
||||||
|
|
||||||
$print_row = function ($row) use ($parsedown, $purifier) {
|
$print_row = function ($row) use ($parsedown, $purifier) {
|
||||||
global $username;
|
$contest = UOJContest::query($row['contest_id']);
|
||||||
|
$problems = $contest->getProblemIDs();
|
||||||
|
$result = '';
|
||||||
|
|
||||||
$contest_id = $row['contest_id'];
|
for ($i = 0; $i < count($problems); $i++) {
|
||||||
$contest = queryContest($contest_id);
|
$problem = UOJContestProblem::query($problems[$i], $contest);
|
||||||
$contest_problems = queryContestProblems($contest_id);
|
$review = DB::selectSingle([
|
||||||
$n_contest_problems = count($contest_problems);
|
"select content",
|
||||||
|
"from contests_reviews",
|
||||||
for ($i = 0; $i < $n_contest_problems; $i++) {
|
"where", [
|
||||||
$problem_id = $contest_problems[$i]['problem_id'];
|
"contest_id" => $contest->info['id'],
|
||||||
$problem = queryProblemBrief($problem_id);
|
"problem_id" => $problem->info['id'],
|
||||||
$problem_self_review = DB::selectFirst("select content from contests_reviews where contest_id = $contest_id and problem_id = $problem_id and poster = '$username'");
|
"poster" => UOJUserBlog::id(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
$result .= '<tr>';
|
$result .= '<tr>';
|
||||||
|
|
||||||
if ($i == 0) {
|
if ($i == 0) {
|
||||||
$result .= '<td rowspan="' . $n_contest_problems . '"><a href="' . HTML::url("/contest/$contest_id") . '">' . $contest['name'] . '</a></td>';
|
$result .= '<td rowspan="' . count($problems) . '"><a href="' . $contest->getUri() . '">' . $contest->info['name'] . '</a></td>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$problem_review_id = "review-$contest_id-$i";
|
$result .= '<td>' . $problem->getLink(['with' => 'letter', 'simplify' => true]) . '</td>';
|
||||||
$result .= '<td>' . chr(ord('A') + $i) . '. <a href="/problem/' . $problem_id . '">' . $problem['title'] . '</a></td>';
|
$result .= '<td>' . $purifier->purify($review ? $parsedown->line($review) : '') . '</td>';
|
||||||
$result .= '<td>' . $purifier->purify($problem_self_review != null ? $parsedown->line($problem_self_review['content']) : '') . '</td>';
|
|
||||||
|
|
||||||
if ($i == 0) {
|
if ($i == 0) {
|
||||||
$contest_review_id = "review-$contest_id-overall";
|
$review = DB::selectSingle([
|
||||||
$contest_self_review = DB::selectFirst("select content from contests_reviews where contest_id = $contest_id and problem_id = -1 and poster = '$username'");
|
"select content",
|
||||||
$result .= '<td rowspan="' . $n_contest_problems . '">' . $purifier->purify($contest_self_review != null ? $parsedown->line($contest_self_review['content']) : '') . '</td>';
|
"from contests_reviews",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest->info['id'],
|
||||||
|
"problem_id" => -1,
|
||||||
|
"poster" => UOJUserBlog::id(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$result .= '<td rowspan="' . count($problems) . '">' . $purifier->purify($review ? $parsedown->line($review) : '') . '</td>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$result .= '</tr>';
|
$result .= '</tr>';
|
||||||
|
@ -1,23 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
|
||||||
|
UOJBlog::cur()->userCanView(Auth::user()) || UOJResponse::page403();
|
||||||
|
UOJBlog::cur()->isTypeS() || UOJResponse::page404();
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($_GET['id']) || !validateUInt($_GET['id']) || !($blog = queryBlog($_GET['id'])) || !UOJContext::isHisSlide($blog)) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
if ($blog['is_hidden'] && !UOJContext::hasBlogPermission()) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$page_config = UOJContext::pageConfig();
|
$page_config = UOJContext::pageConfig();
|
||||||
$page_config['PageTitle'] = HTML::stripTags($blog['title']) . ' - 幻灯片';
|
$page_config += [
|
||||||
$page_config['content'] = $blog['content'];
|
'PageTitle' => HTML::stripTags(UOJBlog::info('title')) . ' - 幻灯片',
|
||||||
|
'content' => UOJBlog::cur()->queryContent()['content']
|
||||||
|
];
|
||||||
uojIncludeView('slide', $page_config);
|
uojIncludeView('slide', $page_config);
|
||||||
?>
|
|
||||||
|
@ -1,22 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
requirePHPLib('form');
|
|
||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJUserBlog::userCanManage(Auth::user()) || UOJResponse::page403();
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UOJContext::hasBlogPermission()) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
if (isset($_GET['id'])) {
|
if (isset($_GET['id'])) {
|
||||||
if (!validateUInt($_GET['id']) || !($blog = queryBlog($_GET['id'])) || !UOJContext::isHisSlide($blog)) {
|
UOJBlog::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
become404Page();
|
UOJBlog::cur()->belongsToUserBlog() || UOJResponse::page404();
|
||||||
}
|
UOJBlog::info('type') == 'S' || UOJResponse::page404();
|
||||||
|
$blog = UOJBlog::info();
|
||||||
|
$blog['content'] = UOJBlog::cur()->queryContent()['content'];
|
||||||
|
$blog['content_md'] = UOJBlog::cur()->queryContent()['content_md'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$blog_editor = new UOJBlogEditor();
|
$blog_editor = new UOJBlogEditor();
|
||||||
@ -27,7 +22,7 @@
|
|||||||
'title' => $blog['title'],
|
'title' => $blog['title'],
|
||||||
'content_md' => $blog['content_md'],
|
'content_md' => $blog['content_md'],
|
||||||
'content' => $blog['content'],
|
'content' => $blog['content'],
|
||||||
'tags' => queryBlogTags($blog['id']),
|
'tags' => UOJBlog::cur()->queryTags(),
|
||||||
'is_hidden' => $blog['is_hidden']
|
'is_hidden' => $blog['is_hidden']
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -35,18 +30,25 @@
|
|||||||
'title' => '新幻灯片',
|
'title' => '新幻灯片',
|
||||||
'content_md' => '',
|
'content_md' => '',
|
||||||
'content' => '',
|
'content' => '',
|
||||||
'tags' => array(),
|
'tags' => [],
|
||||||
'is_hidden' => true
|
'is_hidden' => true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ($blog) {
|
if ($blog) {
|
||||||
$blog_editor->blog_url = HTML::blog_url(UOJContext::user()['username'], "/post/{$blog['id']}");
|
$blog_editor->blog_url = HTML::blog_url(UOJUserBlog::id(), "/post/{$blog['id']}");
|
||||||
} else {
|
} else {
|
||||||
$blog_editor->blog_url = null;
|
$blog_editor->blog_url = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBlog($id, $data) {
|
function insertBlog($data) {
|
||||||
DB::update("update blogs set title = '".DB::escape($data['title'])."', content = '".DB::escape($data['content'])."', content_md = '".DB::escape($data['content_md'])."', is_hidden = {$data['is_hidden']} where id = {$id}");
|
DB::insert([
|
||||||
|
"insert into blogs",
|
||||||
|
"(title, content, content_md, poster, is_hidden, post_time, active_time)",
|
||||||
|
"values", DB::tuple([
|
||||||
|
$data['title'], $data['content'], $data['content_md'],
|
||||||
|
UOJUserBlog::id(), $data['is_hidden'], DB::now(), DB::now()
|
||||||
|
])
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
function insertSlide($data) {
|
function insertSlide($data) {
|
||||||
DB::insert("insert into blogs (type, title, content, content_md, poster, is_hidden, post_time) values ('S', '" . DB::escape($data['title']) . "', '" . DB::escape($data['content']) . "', '" . DB::escape($data['content_md']) . "', '" . Auth::id() . "', {$data['is_hidden']}, now())");
|
DB::insert("insert into blogs (type, title, content, content_md, poster, is_hidden, post_time) values ('S', '" . DB::escape($data['title']) . "', '" . DB::escape($data['content']) . "', '" . DB::escape($data['content_md']) . "', '" . Auth::id() . "', {$data['is_hidden']}, now())");
|
||||||
@ -54,21 +56,18 @@
|
|||||||
|
|
||||||
$blog_editor->save = function ($data) {
|
$blog_editor->save = function ($data) {
|
||||||
global $blog;
|
global $blog;
|
||||||
$ret = array();
|
$ret = [];
|
||||||
if ($blog) {
|
if ($blog) {
|
||||||
updateBlog($blog['id'], $data);
|
updateBlog($blog['id'], $data);
|
||||||
} else {
|
} else {
|
||||||
insertSlide($data);
|
insertSlide($data);
|
||||||
$blog = array('id' => DB::insert_id(), 'tags' => array());
|
$blog_id = DB::insert_id();
|
||||||
$ret['blog_write_url'] = HTML::blog_url(UOJContext::user()['username'], "/slide/{$blog['id']}/write");
|
(new UOJBlog(['id' => $blog_id, 'type' => 'S']))->setAsCur();
|
||||||
$ret['blog_url'] = HTML::blog_url(UOJContext::user()['username'], "/slide/{$blog['id']}");
|
$ret['blog_id'] = $blog_id;
|
||||||
}
|
$ret['blog_write_url'] = UOJBlog::cur()->getUriForWrite();
|
||||||
if ($data['tags'] !== $blog['tags']) {
|
$ret['blog_url'] = UOJBlog::cur()->getBlogUri();
|
||||||
DB::delete("delete from blogs_tags where blog_id = {$blog['id']}");
|
|
||||||
foreach ($data['tags'] as $tag) {
|
|
||||||
DB::insert("insert into blogs_tags (blog_id, tag) values ({$blog['id']}, '".DB::escape($tag)."')");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
UOJBlog::cur()->updateTags($data['tags']);
|
||||||
return $ret;
|
return $ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,5 +77,19 @@
|
|||||||
<div class="text-end">
|
<div class="text-end">
|
||||||
<a class="text-decoration-none" href="http://uoj.ac/blog/75">这玩意儿怎么用?</a>
|
<a class="text-decoration-none" href="http://uoj.ac/blog/75">这玩意儿怎么用?</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header bg-transparent d-flex justify-content-between">
|
||||||
|
<div class="fw-bold">写幻灯片</div>
|
||||||
|
<div id="div-blog-id" <?php if (!$blog) : ?> style="display: none" <?php endif ?>>
|
||||||
|
<?php if ($blog) : ?>
|
||||||
|
<small>博客 ID:<b><?= $blog['id'] ?></b></small>
|
||||||
|
<?php endif ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
<?php $blog_editor->printHTML() ?>
|
<?php $blog_editor->printHTML() ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -4,64 +4,67 @@
|
|||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
UOJSubmission::init(UOJRequest::get('id')) || UOJResponse::page404();
|
||||||
}
|
UOJSubmission::initProblemAndContest() || UOJResponse::page404();
|
||||||
|
UOJSubmission::cur()->userCanView(Auth::user(), ['ensure' => true]);
|
||||||
|
|
||||||
if (!validateUInt($_GET['id']) || !($submission = querySubmission($_GET['id']))) {
|
$perm = UOJSubmission::cur()->viewerCanSeeComponents(Auth::user());
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$submission_result = json_decode($submission['result'], true);
|
$can_see_minor = false;
|
||||||
|
if ($perm['score']) {
|
||||||
$problem = queryProblemBrief($submission['problem_id']);
|
$can_see_minor = UOJSubmission::cur()->userCanSeeMinorVersions(Auth::user());
|
||||||
$problem_extra_config = getProblemExtraConfig($problem);
|
UOJSubmissionHistory::init(UOJSubmission::cur(), ['minor' => $can_see_minor]) || UOJResponse::page404();
|
||||||
|
if (isset($_GET['time'])) {
|
||||||
if ($submission['contest_id']) {
|
$history_time = UOJRequest::get('time', 'is_short_string');
|
||||||
$contest = queryContest($submission['contest_id']);
|
!empty($history_time) || UOJResponse::page404();
|
||||||
genMoreContestInfo($contest);
|
UOJSubmission::cur()->loadHistoryByTime($history_time) || UOJResponse::page404();
|
||||||
} else {
|
UOJSubmission::cur()->isMajor() || UOJResponse::page404();
|
||||||
$contest = null;
|
} elseif (isset($_GET['tid'])) {
|
||||||
|
$can_see_minor || UOJResponse::page404();
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
UOJSubmission::cur()->loadHistoryByTID(UOJRequest::get('tid', 'validateUInt')) || UOJResponse::page404();
|
||||||
become403Page();
|
!UOJSubmission::cur()->isMajor() || UOJResponse::page404();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSubmissionVisibleToUser($submission, $problem, $myUser)) {
|
$submission = UOJSubmission::info();
|
||||||
become403Page();
|
$submission_result = UOJSubmission::cur()->getResult();
|
||||||
|
$problem = UOJProblem::info();
|
||||||
|
|
||||||
|
if ($can_see_minor) {
|
||||||
|
$minor_rejudge_form = new UOJBs4Form('minor_rejudge');
|
||||||
|
$minor_rejudge_form->handle = function () {
|
||||||
|
UOJSubmission::rejudgeById(UOJSubmission::info('id'), [
|
||||||
|
'reason_text' => '管理员偷偷重测该提交记录',
|
||||||
|
'major' => false
|
||||||
|
]);
|
||||||
|
$tid = DB::insert_id();
|
||||||
|
redirectTo(UOJSubmission::cur()->getUriForNewTID($tid));
|
||||||
|
};
|
||||||
|
$minor_rejudge_form->submit_button_config['class_str'] = 'btn btn-sm btn-primary';
|
||||||
|
$minor_rejudge_form->submit_button_config['text'] = '偷偷重新测试';
|
||||||
|
$minor_rejudge_form->submit_button_config['align'] = 'right';
|
||||||
|
$minor_rejudge_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
$out_status = explode(', ', $submission['status'])[0];
|
if (UOJSubmission::cur()->isLatest()) {
|
||||||
|
if (UOJSubmission::cur()->preHackCheck()) {
|
||||||
if ($_GET['get'] == 'status-details' && Auth::check() && $submission['submitter'] === Auth::id()) {
|
$hack_form = new UOJBs4Form('hack');
|
||||||
echo json_encode(array(
|
|
||||||
'judged' => $out_status == 'Judged',
|
|
||||||
'html' => getSubmissionStatusDetails($submission)
|
|
||||||
));
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
|
|
||||||
$hackable = $submission['score'] == 100 && $problem['hackable'] == 1;
|
|
||||||
if ($hackable) {
|
|
||||||
$hack_form = new UOJForm('hack');
|
|
||||||
|
|
||||||
$hack_form->addTextFileInput('input', '输入数据');
|
$hack_form->addTextFileInput('input', '输入数据');
|
||||||
$hack_form->addCheckBox('use_formatter', '帮我整理文末回车、行末空格、换行符', true);
|
$hack_form->addCheckBox('use_formatter', '帮我整理文末回车、行末空格、换行符', true);
|
||||||
$hack_form->handle = function (&$vdata) {
|
$hack_form->handle = function (&$vdata) {
|
||||||
global $myUser, $problem, $submission;
|
global $problem, $submission;
|
||||||
if ($myUser == null) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($_POST["input_upload_type"] == 'file') {
|
if ($_POST["input_upload_type"] == 'file') {
|
||||||
$tmp_name = UOJForm::uploadedFileTmpName("input_file");
|
$tmp_name = UOJBs4Form::uploadedFileTmpName("input_file");
|
||||||
if ($tmp_name == null) {
|
if ($tmp_name == null) {
|
||||||
becomeMsgPage('你在干啥……怎么什么都没交过来……?');
|
UOJResponse::message('你在干啥……怎么什么都没交过来……?');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileName = uojRandAvaiableTmpFileName();
|
$fileName = FS::randomAvailableTmpFileName();
|
||||||
$fileFullName = UOJContext::storagePath() . $fileName;
|
$fileFullName = UOJContext::storagePath() . $fileName;
|
||||||
if ($_POST["input_upload_type"] == 'editor') {
|
if ($_POST["input_upload_type"] == 'editor') {
|
||||||
file_put_contents($fileFullName, $_POST['input_editor']);
|
file_put_contents($fileFullName, $_POST['input_editor']);
|
||||||
@ -69,71 +72,57 @@
|
|||||||
move_uploaded_file($_FILES["input_file"]['tmp_name'], $fileFullName);
|
move_uploaded_file($_FILES["input_file"]['tmp_name'], $fileFullName);
|
||||||
}
|
}
|
||||||
$input_type = isset($_POST['use_formatter']) ? "USE_FORMATTER" : "DONT_USE_FORMATTER";
|
$input_type = isset($_POST['use_formatter']) ? "USE_FORMATTER" : "DONT_USE_FORMATTER";
|
||||||
DB::insert("insert into hacks (problem_id, submission_id, hacker, owner, input, input_type, submit_time, details, is_hidden) values ({$problem['id']}, {$submission['id']}, '{$myUser['username']}', '{$submission['submitter']}', '$fileName', '$input_type', now(), '', {$problem['is_hidden']})");
|
DB::insert([
|
||||||
|
"insert into hacks",
|
||||||
|
"(problem_id, submission_id, hacker, owner, input, input_type, submit_time, status, details, is_hidden)",
|
||||||
|
"values", DB::tuple([
|
||||||
|
$problem['id'], $submission['id'], Auth::id(), $submission['submitter'],
|
||||||
|
$fileName, $input_type, DB::now(), 'Waiting', '', $problem['is_hidden']
|
||||||
|
])
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
$hack_form->max_post_size = 25 * 1024 * 1024;
|
||||||
|
$hack_form->max_file_size_mb = 20;
|
||||||
$hack_form->succ_href = "/hacks";
|
$hack_form->succ_href = "/hacks";
|
||||||
|
|
||||||
$hack_form->runAtServer();
|
$hack_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($submission['status'] == 'Judged' && hasProblemPermission($myUser, $problem)) {
|
if (UOJSubmission::cur()->userCanRejudge(Auth::user())) {
|
||||||
$rejudge_form = new UOJForm('rejudge');
|
$rejudge_form = new UOJBs4Form('rejudge');
|
||||||
$rejudge_form->handle = function () {
|
$rejudge_form->handle = function () {
|
||||||
global $submission;
|
UOJSubmission::rejudgeById(UOJSubmission::info('id'));
|
||||||
rejudgeSubmission($submission);
|
|
||||||
};
|
};
|
||||||
$rejudge_form->submit_button_config['class_str'] = 'btn btn-primary';
|
$rejudge_form->submit_button_config['class_str'] = 'btn btn-sm btn-primary';
|
||||||
$rejudge_form->submit_button_config['text'] = '重新测试';
|
$rejudge_form->submit_button_config['text'] = '重新测试';
|
||||||
$rejudge_form->submit_button_config['align'] = 'right';
|
$rejudge_form->submit_button_config['align'] = 'end';
|
||||||
$rejudge_form->runAtServer();
|
$rejudge_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
if (UOJSubmission::cur()->userCanDelete(Auth::user())) {
|
||||||
$delete_form = new UOJForm('delete');
|
$delete_form = new UOJBs4Form('delete');
|
||||||
$delete_form->handle = function () {
|
$delete_form->handle = function () {
|
||||||
global $submission;
|
UOJSubmission::cur()->delete();
|
||||||
$content = json_decode($submission['content'], true);
|
|
||||||
unlink(UOJContext::storagePath().$content['file_name']);
|
|
||||||
DB::delete("delete from submissions where id = {$submission['id']}");
|
|
||||||
updateBestACSubmissions($submission['submitter'], $submission['problem_id']);
|
|
||||||
};
|
};
|
||||||
$delete_form->submit_button_config['class_str'] = 'btn btn-danger';
|
$delete_form->submit_button_config['class_str'] = 'btn btn-sm btn-danger';
|
||||||
$delete_form->submit_button_config['text'] = '删除此提交记录';
|
$delete_form->submit_button_config['text'] = '删除此提交记录';
|
||||||
$delete_form->submit_button_config['align'] = 'right';
|
$delete_form->submit_button_config['align'] = 'end';
|
||||||
$delete_form->submit_button_config['smart_confirm'] = '';
|
$delete_form->submit_button_config['smart_confirm'] = '';
|
||||||
$delete_form->succ_href = "/submissions";
|
$delete_form->succ_href = "/submissions";
|
||||||
$delete_form->runAtServer();
|
$delete_form->runAtServer();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
$should_show_content = hasViewPermission($problem_extra_config['view_content_type'], $myUser, $problem, $submission);
|
if (UOJSubmission::cur()->userCanDelete(Auth::user()) && !UOJSubmission::cur()->isMajor()) {
|
||||||
$should_show_all_details = hasViewPermission($problem_extra_config['view_all_details_type'], $myUser, $problem, $submission);
|
$delete_form = new UOJBs4Form('delete');
|
||||||
$should_show_details = hasViewPermission($problem_extra_config['view_details_type'], $myUser, $problem, $submission);
|
$delete_form->handle = function () {
|
||||||
$should_show_details_to_me = isSuperUser($myUser);
|
UOJSubmission::cur()->deleteThisMinorVersion();
|
||||||
if (explode(', ', $submission['status'])[0] != 'Judged') {
|
};
|
||||||
$should_show_all_details = false;
|
$delete_form->submit_button_config['class_str'] = 'btn btn-sm btn-danger';
|
||||||
}
|
$delete_form->submit_button_config['text'] = '删除当前历史记录(保留其他历史记录)';
|
||||||
if ($contest != null && $contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
$delete_form->submit_button_config['align'] = 'end';
|
||||||
if ($contest['extra_config']["problem_{$submission['problem_id']}"] === 'no-details') {
|
$delete_form->submit_button_config['smart_confirm'] = '';
|
||||||
$should_show_details = false;
|
$delete_form->succ_href = UOJSubmission::cur()->getUriForLatest();
|
||||||
}
|
$delete_form->runAtServer();
|
||||||
}
|
|
||||||
if (!isSubmissionFullVisibleToUser($submission, $contest, $problem, $myUser)) {
|
|
||||||
$should_show_content = $should_show_all_details = false;
|
|
||||||
}
|
|
||||||
if ($contest != null && hasContestPermission($myUser, $contest)) {
|
|
||||||
$should_show_details_to_me = true;
|
|
||||||
$should_show_content = true;
|
|
||||||
$should_show_all_details = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($should_show_all_details) {
|
|
||||||
$styler = new SubmissionDetailsStyler();
|
|
||||||
if ((!$should_show_details || ($contest['extra_config']['contest_type']=='IOI' && $contest['cur_progress'] == CONTEST_IN_PROGRESS)) && !hasContestPermission($myUser, $contest)) {
|
|
||||||
$styler->fade_all_details = true;
|
|
||||||
$styler->show_small_tip = false;
|
|
||||||
if ($contest['extra_config']['contest_type']=='IOI' && $contest['cur_progress'] == CONTEST_IN_PROGRESS) {
|
|
||||||
$styler->ioi_contest_is_running = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@ -142,19 +131,53 @@
|
|||||||
</script>
|
</script>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('problems::submission') . ' #' . $submission['id']) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('problems::submission') . ' #' . $submission['id']) ?>
|
||||||
|
|
||||||
<h1 class="h3">
|
<h1>
|
||||||
<?= UOJLocale::get('problems::submission') . ' #' . $submission['id'] ?>
|
<?= UOJLocale::get('problems::submission') . ' #' . $submission['id'] ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<?php echoSubmissionsListOnlyOne($submission, array('id_hidden' => ''), $myUser) ?>
|
<?php UOJSubmission::cur()->echoStatusTable(['show_actual_score' => $perm['score'], 'id_hidden' => true], Auth::user()) ?>
|
||||||
|
|
||||||
<?php if ($should_show_content): ?>
|
<?php
|
||||||
<?php echoSubmissionContent($submission, getProblemSubmissionRequirement($problem)) ?>
|
if ($perm['score']) {
|
||||||
<?php if ($hackable): ?>
|
HTML::echoPanel('mb-3', '测评历史', function () {
|
||||||
|
UOJSubmissionHistory::cur()->echoTimeline();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
if ($perm['manager_view']) {
|
||||||
|
HTML::echoPanel('mb-3', '测评机信息(管理员可见)', function () {
|
||||||
|
if (empty(UOJSubmission::info('judger'))) {
|
||||||
|
echo '暂无';
|
||||||
|
} else {
|
||||||
|
$judger = DB::selectFirst([
|
||||||
|
"select * from judger_info",
|
||||||
|
"where", [
|
||||||
|
"judger_name" => UOJSubmission::info('judger')
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if (!$judger) {
|
||||||
|
echo '测评机信息损坏';
|
||||||
|
} else {
|
||||||
|
echo '<strong>', $judger['display_name'], ': </strong>', $judger['description'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php if ($perm['content'] || $perm['manager_view']) : ?>
|
||||||
|
<?php UOJSubmission::cur()->echoContent() ?>
|
||||||
|
|
||||||
|
<?php if (isset($hack_form)) : ?>
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
这程序好像有点Bug,我给组数据试试? <button id="button-display-hack" type="button" class="btn btn-danger btn-xs">Hack!</button>
|
这程序好像有点Bug,我给组数据试试? <button id="button-display-hack" type="button" class="btn btn-danger btn-xs">Hack!</button>
|
||||||
</p>
|
</p>
|
||||||
<div id="div-form-hack" style="display:none" class="bot-buffer-md">
|
<div id="div-form-hack" style="display:none" class="mb-3">
|
||||||
|
<p class="text-center text-danger">
|
||||||
|
Hack 功能是给大家互相查错用的。请勿故意提交错误代码,然后自己 Hack 自己、贼喊捉贼哦(故意贼喊捉贼会予以封禁处理)
|
||||||
|
</p>
|
||||||
<?php $hack_form->printHTML() ?>
|
<?php $hack_form->printHTML() ?>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@ -167,36 +190,48 @@
|
|||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php if ($should_show_all_details): ?>
|
<?php
|
||||||
<div class="card border-info mb-3">
|
if (UOJSubmission::cur()->hasJudged()) {
|
||||||
<div class="card-header bg-info">
|
if ($perm['high_level_details']) {
|
||||||
<h4 class="card-title"><?= UOJLocale::get('details') ?></h4>
|
HTML::echoPanel(['card' => 'mb-3', 'body' => 'p-0'], UOJLocale::get('details'), function () use ($perm, $submission_result) {
|
||||||
</div>
|
$styler = new SubmissionDetailsStyler();
|
||||||
|
if (!$perm['low_level_details']) {
|
||||||
|
$styler->fade_all_details = true;
|
||||||
|
$styler->show_small_tip = false;
|
||||||
|
}
|
||||||
|
echoJudgmentDetails($submission_result['details'], $styler, 'details');
|
||||||
|
|
||||||
<?php echoJudgementDetails($submission_result['details'], $styler, 'details') ?>
|
if ($perm['manager_view'] && !$perm['low_level_details']) {
|
||||||
<?php if ($should_show_details_to_me): ?>
|
echo '<hr />';
|
||||||
<?php if (isset($submission_result['final_result'])): ?>
|
echo '<h4 class="text-info">全部详细信息(管理员可见)</h4>';
|
||||||
<hr />
|
echoSubmissionDetails($submission_result['details'], 'all_details');
|
||||||
<?php echoSubmissionDetails($submission_result['final_result']['details'], 'final_details') ?>
|
}
|
||||||
<?php endif ?>
|
});
|
||||||
<?php if ($styler->fade_all_details): ?>
|
} else if ($perm['manager_view']) {
|
||||||
<hr />
|
HTML::echoPanel(['card' => 'mb-3', 'body' => 'p-0'], '详细(管理员可见)', function () use ($submission_result) {
|
||||||
<?php echoSubmissionDetails($submission_result['details'], 'final_details') ?>
|
echoSubmissionDetails($submission_result['details'], 'details');
|
||||||
<?php endif ?>
|
});
|
||||||
<?php endif ?>
|
}
|
||||||
</div>
|
if ($perm['manager_view'] && isset($submission_result['final_result'])) {
|
||||||
|
HTML::echoPanel(['card' => 'mb-3', 'body' => 'p-0'], '终测结果预测(管理员可见)', function () use ($submission_result) {
|
||||||
|
echoSubmissionDetails($submission_result['final_result']['details'], 'final_details');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="d-flex gap-2 justify-content-end">
|
||||||
|
<?php if (isset($minor_rejudge_form)) : ?>
|
||||||
|
<?php $minor_rejudge_form->printHTML() ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php if (isset($rejudge_form)) : ?>
|
<?php if (isset($rejudge_form)) : ?>
|
||||||
<div class="text-end">
|
|
||||||
<?php $rejudge_form->printHTML() ?>
|
<?php $rejudge_form->printHTML() ?>
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php if (isset($delete_form)) : ?>
|
<?php if (isset($delete_form)) : ?>
|
||||||
<div class="text-end">
|
|
||||||
<?php $delete_form->printHTML() ?>
|
<?php $delete_form->printHTML() ?>
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -1,37 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || UOJResponse::page403();
|
||||||
redirectToLogin();
|
is_array($_GET['get']) || UOJResponse::page404();
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_array($_GET['get'])) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$res = [];
|
$res = [];
|
||||||
|
|
||||||
foreach ($_GET['get'] as $id) {
|
foreach ($_GET['get'] as $id) {
|
||||||
if (!validateUInt($id)) {
|
($submission = UOJSubmission::query($id)) || UOJResponse::page404();
|
||||||
become404Page();
|
$submission->setProblem() || UOJResponse::page404();
|
||||||
}
|
$submission->userIsSubmitter(Auth::user()) || UOJResponse::page403();
|
||||||
$submission = querySubmission($id);
|
$submission->userCanView(Auth::user(), ['ensure' => true]);
|
||||||
if ($submission['submitter'] !== Auth::id()) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
if ($submission['contest_id'] == null && !(isNormalUser($myUser) && UOJConfig::$data['switch']['force-login'])) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$problem = queryProblemBrief($submission['problem_id']);
|
|
||||||
if (!isSubmissionVisibleToUser($submission, $problem, Auth::user())) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$out_status = explode(', ', $submission['status'])[0];
|
|
||||||
|
|
||||||
$res[] = [
|
$res[] = [
|
||||||
'judged' => $out_status == 'Judged',
|
'judged' => $submission->hasJudged(),
|
||||||
'html' => getSubmissionStatusDetails($submission)
|
'waiting' => $submission->isWaiting(),
|
||||||
|
'html' => $submission->getStatusDetailsHTML()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,48 +2,51 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
|
$conds = [];
|
||||||
|
$config = [
|
||||||
|
'judge_time_hidden' => true,
|
||||||
|
'table_config' => [
|
||||||
|
'div_classes' => ['card', 'mb-3', 'table-responsive'],
|
||||||
|
'table_classes' => ['table', 'mb-0', 'uoj-table', 'text-center'],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$q_problem_id = UOJRequest::get('problem_id', 'validateUInt', null);
|
||||||
|
$q_submitter = UOJRequest::get('submitter', 'validateUsername', null);
|
||||||
|
$q_min_score = UOJRequest::get('min_score', 'validateUInt', null);
|
||||||
|
$q_max_score = UOJRequest::get('max_score', 'validateUInt', null);
|
||||||
|
$q_lang = UOJRequest::get('language', 'is_short_string', null);
|
||||||
|
|
||||||
|
if ($q_problem_id !== null) {
|
||||||
|
$problem = UOJProblem::query($q_problem_id);
|
||||||
|
if ($problem) {
|
||||||
|
$config['problem'] = $problem;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
$conds['problem_id'] = $q_problem_id;
|
||||||
become403Page();
|
}
|
||||||
|
if ($q_submitter !== null) {
|
||||||
|
$conds['submitter'] = $q_submitter;
|
||||||
|
}
|
||||||
|
if ($q_min_score !== null) {
|
||||||
|
$conds[] = ['score', '>=', $q_min_score];
|
||||||
|
}
|
||||||
|
if ($q_max_score !== null) {
|
||||||
|
$conds[] = ['score', '<=', $q_max_score];
|
||||||
|
}
|
||||||
|
if ($q_lang != null) {
|
||||||
|
$conds['language'] = $q_lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
$conds = array();
|
if (!$conds) {
|
||||||
|
$conds = '1';
|
||||||
$q_problem_id = isset($_GET['problem_id']) && validateUInt($_GET['problem_id']) ? $_GET['problem_id'] : null;
|
|
||||||
$q_submitter = isset($_GET['submitter']) && validateUsername($_GET['submitter']) ? $_GET['submitter'] : null;
|
|
||||||
$q_min_score = isset($_GET['min_score']) && validateUInt($_GET['min_score']) ? $_GET['min_score'] : null;
|
|
||||||
$q_max_score = isset($_GET['max_score']) && validateUInt($_GET['max_score']) ? $_GET['max_score'] : null;
|
|
||||||
$q_language = isset($_GET['language']) ? $_GET['language'] : null;
|
|
||||||
if ($q_problem_id != null) {
|
|
||||||
$conds[] = "problem_id = $q_problem_id";
|
|
||||||
}
|
|
||||||
if ($q_submitter != null) {
|
|
||||||
$conds[] = "submitter = '$q_submitter'";
|
|
||||||
}
|
|
||||||
if ($q_min_score != null) {
|
|
||||||
$conds[] = "score >= $q_min_score";
|
|
||||||
}
|
|
||||||
if ($q_max_score != null) {
|
|
||||||
$conds[] = "score <= $q_max_score";
|
|
||||||
}
|
|
||||||
if ($q_language != null) {
|
|
||||||
$conds[] = sprintf("language = '%s'", DB::escape($q_language));
|
|
||||||
}
|
|
||||||
|
|
||||||
$html_esc_q_language = htmlspecialchars($q_language);
|
|
||||||
|
|
||||||
if ($conds) {
|
|
||||||
$cond = join($conds, ' and ');
|
|
||||||
} else {
|
|
||||||
$cond = '1';
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('submissions')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('submissions')) ?>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('submissions') ?>
|
<?= UOJLocale::get('submissions') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -89,8 +92,8 @@
|
|||||||
<label for="input-language" class="control-label"><?= UOJLocale::get('problems::language') ?>:</label>
|
<label for="input-language" class="control-label"><?= UOJLocale::get('problems::language') ?>:</label>
|
||||||
<select class="form-select form-select-sm" id="input-language" name="language">
|
<select class="form-select form-select-sm" id="input-language" name="language">
|
||||||
<option value="">All</option>
|
<option value="">All</option>
|
||||||
<?php foreach ($uojSupportedLanguages as $lang): ?>
|
<?php foreach (UOJLang::$supported_languages as $name => $lang) : ?>
|
||||||
<option value="<?= HTML::escape($lang) ?>" <?= $lang == $q_language ? 'selected' : '' ?>><?= HTML::escape($lang) ?></option>
|
<option value="<?= HTML::escape($name) ?>" <?= $name == $q_lang ? 'selected' : '' ?>><?= HTML::escape($lang) ?></option>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -100,17 +103,6 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php echoSubmissionsList($conds, 'order by id desc', $config, Auth::user()) ?>
|
||||||
echoSubmissionsList($cond,
|
|
||||||
'order by id desc',
|
|
||||||
[
|
|
||||||
'judge_time_hidden' => '',
|
|
||||||
'table_config' => [
|
|
||||||
'div_classes' => ['card', 'mb-3', 'table-responsive'],
|
|
||||||
'table_classes' => ['table', 'mb-0', 'uoj-table', 'text-center'],
|
|
||||||
]
|
|
||||||
],
|
|
||||||
$myUser);
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
requirePHPLib('judger');
|
requirePHPLib('judger');
|
||||||
|
|
||||||
define('SCRIPT_REFRESH_AS_GET', '<script>;window.location = window.location.origin + window.location.pathname + (window.location.search.length ? window.location.search + "&" : "?") + "_=" + (+new Date()) + window.location.hash;</script>');
|
|
||||||
|
|
||||||
if (!Auth::check()) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
@ -50,24 +48,47 @@
|
|||||||
|
|
||||||
if ($cur_tab == 'index') {
|
if ($cur_tab == 'index') {
|
||||||
// ========== 公告 ==========
|
// ========== 公告 ==========
|
||||||
if (isset($_POST['submit-delete_announcement']) && $_POST['submit-delete_announcement'] == 'delete_announcement') {
|
if (UOJRequest::post('submit-delete_announcement') === 'delete_announcement') {
|
||||||
crsf_defend();
|
crsf_defend();
|
||||||
|
|
||||||
$blog_id = $_POST['blog_id'];
|
$blog_id = UOJRequest::post('blog_id');
|
||||||
|
|
||||||
if (!validateUInt($blog_id)) {
|
if (!validateUInt($blog_id)) {
|
||||||
dieWithAlert('移除失败:博客 ID 无效');
|
dieWithAlert('移除失败:博客 ID 无效');
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::delete("DELETE FROM important_blogs WHERE blog_id = {$blog_id}");
|
DB::delete([
|
||||||
|
"delete from important_blogs",
|
||||||
|
"where", [
|
||||||
|
"blog_id" => $blog_id,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithAlert('移除成功!');
|
dieWithAlert('移除成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$announcements = DB::selectAll("SELECT blogs.id as id, blogs.title as title, blogs.poster as poster, user_info.realname as realname, blogs.post_time as post_time, important_blogs.level as level, blogs.is_hidden as is_hidden FROM important_blogs INNER JOIN blogs ON important_blogs.blog_id = blogs.id INNER JOIN user_info ON blogs.poster = user_info.username ORDER BY level DESC, important_blogs.blog_id DESC");
|
$announcements = DB::selectAll([
|
||||||
|
"select", DB::fields([
|
||||||
|
"id" => "blogs.id",
|
||||||
|
"title" => "blogs.title",
|
||||||
|
"poster" => "blogs.poster",
|
||||||
|
"realname" => "user_info.realname",
|
||||||
|
"post_time" => "blogs.post_time",
|
||||||
|
"level" => "important_blogs.level",
|
||||||
|
"is_hidden" => "blogs.is_hidden",
|
||||||
|
]),
|
||||||
|
"from blogs",
|
||||||
|
"inner join important_blogs on important_blogs.blog_id = blogs.id",
|
||||||
|
"inner join user_info on blogs.poster = user_info.username",
|
||||||
|
"order by level desc, important_blogs.blog_id desc",
|
||||||
|
]);
|
||||||
|
|
||||||
$add_announcement_form = new UOJForm('add_announcement');
|
$add_announcement_form = new UOJBs4Form('add_announcement');
|
||||||
$add_announcement_form->addInput('blog_id', 'text', '博客 ID', '',
|
$add_announcement_form->addInput(
|
||||||
|
'blog_id',
|
||||||
|
'text',
|
||||||
|
'博客 ID',
|
||||||
|
'',
|
||||||
function ($id, &$vdata) {
|
function ($id, &$vdata) {
|
||||||
if (!validateUInt($id)) {
|
if (!validateUInt($id)) {
|
||||||
return '博客 ID 无效';
|
return '博客 ID 无效';
|
||||||
@ -83,7 +104,11 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_announcement_form->addInput('blog_level', 'text', '置顶级别', '0',
|
$add_announcement_form->addInput(
|
||||||
|
'blog_level',
|
||||||
|
'text',
|
||||||
|
'置顶级别',
|
||||||
|
'0',
|
||||||
function ($x, &$vdata) {
|
function ($x, &$vdata) {
|
||||||
if (!validateUInt($x)) {
|
if (!validateUInt($x)) {
|
||||||
return '数字不合法';
|
return '数字不合法';
|
||||||
@ -103,10 +128,28 @@
|
|||||||
$blog_id = $vdata['blog_id'];
|
$blog_id = $vdata['blog_id'];
|
||||||
$blog_level = $vdata['level'];
|
$blog_level = $vdata['level'];
|
||||||
|
|
||||||
if (DB::selectFirst("select * from important_blogs where blog_id = {$blog_id}")) {
|
if (DB::selectExists([
|
||||||
DB::update("update important_blogs set level = {$blog_level} where blog_id = {$blog_id}");
|
"select * from important_blogs",
|
||||||
|
"where", [
|
||||||
|
"blog_id" => $blog_id,
|
||||||
|
]
|
||||||
|
])) {
|
||||||
|
DB::update([
|
||||||
|
"update important_blogs",
|
||||||
|
"set", [
|
||||||
|
"level" => $blog_level,
|
||||||
|
],
|
||||||
|
"where", [
|
||||||
|
"blog_id" => $blog_id,
|
||||||
|
]
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
DB::insert("insert into important_blogs (blog_id, level) values ({$blog_id}, {$blog_level})");
|
DB::insert([
|
||||||
|
"insert into important_blogs",
|
||||||
|
DB::bracketed_fields(["blog_id", "level"]),
|
||||||
|
"values",
|
||||||
|
DB::tuple([$blog_id, $blog_level]),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$add_announcement_form->submit_button_config['align'] = 'compressed';
|
$add_announcement_form->submit_button_config['align'] = 'compressed';
|
||||||
@ -115,24 +158,37 @@
|
|||||||
$add_announcement_form->runAtServer();
|
$add_announcement_form->runAtServer();
|
||||||
|
|
||||||
// ========== 倒计时 ==========
|
// ========== 倒计时 ==========
|
||||||
if (isset($_POST['submit-delete_countdown']) && $_POST['submit-delete_countdown'] == 'delete_countdown') {
|
if (UOJRequest::post('submit-delete_countdown') === 'delete_countdown') {
|
||||||
crsf_defend();
|
crsf_defend();
|
||||||
|
|
||||||
$countdown_id = $_POST['countdown_id'];
|
$countdown_id = UOJRequest::post('countdown_id');
|
||||||
|
|
||||||
if (!validateUInt($countdown_id)) {
|
if (!validateUInt($countdown_id)) {
|
||||||
dieWithAlert('删除失败:倒计时 ID 无效');
|
dieWithAlert('删除失败:倒计时 ID 无效');
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::delete("DELETE FROM countdowns WHERE id = {$countdown_id}");
|
DB::delete([
|
||||||
|
"delete from countdowns",
|
||||||
|
"where", [
|
||||||
|
"id" => $countdown_id,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithAlert('删除成功!');
|
dieWithAlert('删除成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$countdowns = DB::selectAll("SELECT id, title, end_time FROM countdowns ORDER BY end_time ASC");
|
$countdowns = DB::selectAll([
|
||||||
|
"select", DB::fields(["id", "title", "end_time"]),
|
||||||
|
"from countdowns",
|
||||||
|
"order by end_time asc",
|
||||||
|
]);
|
||||||
|
|
||||||
$add_countdown_form = new UOJForm('add_countdown');
|
$add_countdown_form = new UOJBs4Form('add_countdown');
|
||||||
$add_countdown_form->addInput('countdown_title', 'text', '标题', '',
|
$add_countdown_form->addInput(
|
||||||
|
'countdown_title',
|
||||||
|
'text',
|
||||||
|
'标题',
|
||||||
|
'',
|
||||||
function ($title, &$vdata) {
|
function ($title, &$vdata) {
|
||||||
if ($title == '') {
|
if ($title == '') {
|
||||||
return '标题不能为空';
|
return '标题不能为空';
|
||||||
@ -144,7 +200,11 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_countdown_form->addInput('countdown_end_time', 'text', '结束时间', date("Y-m-d H:i:s"),
|
$add_countdown_form->addInput(
|
||||||
|
'countdown_end_time',
|
||||||
|
'text',
|
||||||
|
'结束时间',
|
||||||
|
date("Y-m-d H:i:s"),
|
||||||
function ($end_time, &$vdata) {
|
function ($end_time, &$vdata) {
|
||||||
try {
|
try {
|
||||||
$vdata['end_time'] = new DateTime($end_time);
|
$vdata['end_time'] = new DateTime($end_time);
|
||||||
@ -157,10 +217,12 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_countdown_form->handle = function (&$vdata) {
|
$add_countdown_form->handle = function (&$vdata) {
|
||||||
$esc_title = DB::escape($vdata['title']);
|
DB::insert([
|
||||||
$esc_end_time = DB::escape($vdata['end_time']->format('Y-m-d H:i:s'));
|
"insert into countdowns",
|
||||||
|
DB::bracketed_fields(["title", "end_time"]),
|
||||||
DB::insert("INSERT INTO countdowns (title, end_time) VALUES ('{$esc_title}', '{$esc_end_time}')");
|
"values",
|
||||||
|
DB::tuple([$vdata['title'], $vdata['end_time']->format('Y-m-d H:i:s')]),
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$add_countdown_form->submit_button_config['align'] = 'compressed';
|
$add_countdown_form->submit_button_config['align'] = 'compressed';
|
||||||
$add_countdown_form->submit_button_config['text'] = '添加';
|
$add_countdown_form->submit_button_config['text'] = '添加';
|
||||||
@ -168,24 +230,37 @@
|
|||||||
$add_countdown_form->runAtServer();
|
$add_countdown_form->runAtServer();
|
||||||
|
|
||||||
// ========== 常用链接 ==========
|
// ========== 常用链接 ==========
|
||||||
if (isset($_POST['submit-delete_link']) && $_POST['submit-delete_link'] == 'delete_link') {
|
if (UOJRequest::post('submit-delete_link') === 'delete_link') {
|
||||||
crsf_defend();
|
crsf_defend();
|
||||||
|
|
||||||
$item_id = $_POST['item_id'];
|
$link_id = UOJRequest::post('link_id');
|
||||||
|
|
||||||
if (!validateUInt($item_id)) {
|
if (!validateUInt($link_id)) {
|
||||||
dieWithAlert('删除失败:ID 无效');
|
dieWithAlert('删除失败:ID 无效');
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::delete("DELETE FROM links WHERE id = {$item_id}");
|
DB::delete([
|
||||||
|
"delete from friend_links",
|
||||||
|
"where", [
|
||||||
|
"id" => $link_id,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithAlert('删除成功!');
|
dieWithAlert('删除成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
$links = DB::selectAll("SELECT `id`, `title`, `url`, `level` FROM `friend_links` ORDER BY `level` DESC, `id` ASC");
|
$links = DB::selectAll([
|
||||||
|
"select", DB::fields(["id", "title", "url", "level"]),
|
||||||
|
"from friend_links",
|
||||||
|
"order by level desc, id asc",
|
||||||
|
]);
|
||||||
|
|
||||||
$add_link_form = new UOJForm('add_link');
|
$add_link_form = new UOJBs4Form('add_link');
|
||||||
$add_link_form->addInput('link_title', 'text', '标题', '',
|
$add_link_form->addInput(
|
||||||
|
'link_title',
|
||||||
|
'text',
|
||||||
|
'标题',
|
||||||
|
'',
|
||||||
function ($title, &$vdata) {
|
function ($title, &$vdata) {
|
||||||
if ($title == '') {
|
if ($title == '') {
|
||||||
return '标题不能为空';
|
return '标题不能为空';
|
||||||
@ -197,7 +272,11 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_link_form->addInput('link_url', 'text', '链接', '',
|
$add_link_form->addInput(
|
||||||
|
'link_url',
|
||||||
|
'text',
|
||||||
|
'链接',
|
||||||
|
'',
|
||||||
function ($url, &$vdata) {
|
function ($url, &$vdata) {
|
||||||
if (!validateURL($url)) {
|
if (!validateURL($url)) {
|
||||||
return '链接不合法';
|
return '链接不合法';
|
||||||
@ -209,7 +288,11 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_link_form->addInput('link_level', 'text', '权重', '10',
|
$add_link_form->addInput(
|
||||||
|
'link_level',
|
||||||
|
'text',
|
||||||
|
'权重',
|
||||||
|
'10',
|
||||||
function ($level, &$vdata) {
|
function ($level, &$vdata) {
|
||||||
if (!validateUInt($level)) {
|
if (!validateUInt($level)) {
|
||||||
return '数字不合法';
|
return '数字不合法';
|
||||||
@ -222,11 +305,12 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$add_link_form->handle = function (&$vdata) {
|
$add_link_form->handle = function (&$vdata) {
|
||||||
$esc_title = DB::escape($vdata['title']);
|
DB::insert([
|
||||||
$esc_url = DB::escape($vdata['url']);
|
"insert into friend_links",
|
||||||
$level = $vdata['level'];
|
DB::bracketed_fields(["title", "url", "level"]),
|
||||||
|
"values",
|
||||||
DB::insert("INSERT INTO friend_links (title, url, level) VALUES ('{$esc_title}', '{$esc_url}', {$level})");
|
DB::tuple([$vdata['title'], $vdata['url'], $vdata['level']]),
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
$add_link_form->submit_button_config['align'] = 'compressed';
|
$add_link_form->submit_button_config['align'] = 'compressed';
|
||||||
$add_link_form->submit_button_config['text'] = '添加';
|
$add_link_form->submit_button_config['text'] = '添加';
|
||||||
@ -246,13 +330,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($user_list_cond) {
|
if ($user_list_cond) {
|
||||||
$user_list_cond = join($user_list_cond, ' and ');
|
$user_list_cond = implode(' and ', $user_list_cond);
|
||||||
} else {
|
} else {
|
||||||
$user_list_cond = '1';
|
$user_list_cond = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
$register_form = new UOJForm('register');
|
$register_form = new UOJBs4Form('register');
|
||||||
$register_form->addVInput('new_username', 'text', '用户名', '',
|
$register_form->addVInput(
|
||||||
|
'new_username',
|
||||||
|
'text',
|
||||||
|
'用户名',
|
||||||
|
'',
|
||||||
function ($username, &$vdata) {
|
function ($username, &$vdata) {
|
||||||
if (!validateUsername($username)) {
|
if (!validateUsername($username)) {
|
||||||
return '用户名不合法';
|
return '用户名不合法';
|
||||||
@ -268,7 +356,11 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$register_form->addVInput('new_password', 'password', '密码', '',
|
$register_form->addVInput(
|
||||||
|
'new_password',
|
||||||
|
'password',
|
||||||
|
'密码',
|
||||||
|
'',
|
||||||
function ($password, &$vdata) {
|
function ($password, &$vdata) {
|
||||||
$vdata['password'] = $password;
|
$vdata['password'] = $password;
|
||||||
|
|
||||||
@ -276,7 +368,11 @@
|
|||||||
},
|
},
|
||||||
'validatePassword'
|
'validatePassword'
|
||||||
);
|
);
|
||||||
$register_form->addVInput('new_email', 'text', '电子邮件(选填)', '',
|
$register_form->addVInput(
|
||||||
|
'new_email',
|
||||||
|
'text',
|
||||||
|
'电子邮件(选填)',
|
||||||
|
'',
|
||||||
function ($email, &$vdata) {
|
function ($email, &$vdata) {
|
||||||
if ($email && !validateEmail($email)) {
|
if ($email && !validateEmail($email)) {
|
||||||
return '邮件地址不合法';
|
return '邮件地址不合法';
|
||||||
@ -288,7 +384,11 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$register_form->addVInput('new_realname', 'text', '真实姓名(选填)', '',
|
$register_form->addVInput(
|
||||||
|
'new_realname',
|
||||||
|
'text',
|
||||||
|
'真实姓名(选填)',
|
||||||
|
'',
|
||||||
function ($realname, &$vdata) {
|
function ($realname, &$vdata) {
|
||||||
$vdata['realname'] = $realname;
|
$vdata['realname'] = $realname;
|
||||||
|
|
||||||
@ -296,7 +396,11 @@
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$register_form->addVInput('new_school', 'text', '学校名称(选填)', '',
|
$register_form->addVInput(
|
||||||
|
'new_school',
|
||||||
|
'text',
|
||||||
|
'学校名称(选填)',
|
||||||
|
'',
|
||||||
function ($school, &$vdata) {
|
function ($school, &$vdata) {
|
||||||
$vdata['school'] = $school;
|
$vdata['school'] = $school;
|
||||||
|
|
||||||
@ -305,15 +409,15 @@
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
$register_form->handle = function (&$vdata) {
|
$register_form->handle = function (&$vdata) {
|
||||||
$username = $vdata['username'];
|
$user = [
|
||||||
$realname = DB::escape($vdata['realname']);
|
'username' => $vdata['username'],
|
||||||
$school = DB::escape($vdata['school']);
|
'realname' => $vdata['realname'],
|
||||||
$email = DB::escape($vdata['email']);
|
'school' => $vdata['school'],
|
||||||
$password = hash_hmac('md5', $vdata['password'], getPasswordClientSalt());
|
'email' => $vdata['email'],
|
||||||
$password = getPasswordToStore($password, $username);
|
'password' => hash_hmac('md5', $vdata['password'], getPasswordClientSalt()),
|
||||||
$svn_password = uojRandString(10);
|
];
|
||||||
|
|
||||||
DB::query("insert into user_info (username, realname, email, school, password, svn_password, register_time, usergroup) values ('$username', '$realname', '$email', '$school', '$password', '$svn_password', now(), 'U')");
|
UOJUser::register($user, ['check_email' => false]);
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '']);
|
dieWithJsonData(['status' => 'success', 'message' => '']);
|
||||||
};
|
};
|
||||||
@ -338,8 +442,12 @@
|
|||||||
EOD);
|
EOD);
|
||||||
$register_form->runAtServer();
|
$register_form->runAtServer();
|
||||||
|
|
||||||
$change_password_form = new UOJForm('change_password');
|
$change_password_form = new UOJBs4Form('change_password');
|
||||||
$change_password_form->addVInput('p_username', 'text', '用户名', '',
|
$change_password_form->addVInput(
|
||||||
|
'p_username',
|
||||||
|
'text',
|
||||||
|
'用户名',
|
||||||
|
'',
|
||||||
function ($username, &$vdata) {
|
function ($username, &$vdata) {
|
||||||
if (!validateUsername($username)) {
|
if (!validateUsername($username)) {
|
||||||
return '用户名不合法';
|
return '用户名不合法';
|
||||||
@ -355,7 +463,11 @@ EOD);
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$change_password_form->addVInput('p_password', 'password', '密码', '',
|
$change_password_form->addVInput(
|
||||||
|
'p_password',
|
||||||
|
'password',
|
||||||
|
'密码',
|
||||||
|
'',
|
||||||
function ($password, &$vdata) {
|
function ($password, &$vdata) {
|
||||||
$vdata['password'] = $password;
|
$vdata['password'] = $password;
|
||||||
|
|
||||||
@ -364,15 +476,21 @@ EOD);
|
|||||||
'validatePassword'
|
'validatePassword'
|
||||||
);
|
);
|
||||||
$change_password_form->handle = function (&$vdata) {
|
$change_password_form->handle = function (&$vdata) {
|
||||||
$esc_username = DB::escape($vdata['username']);
|
|
||||||
$password = hash_hmac('md5', $vdata['password'], getPasswordClientSalt());
|
$password = hash_hmac('md5', $vdata['password'], getPasswordClientSalt());
|
||||||
$esc_password = DB::escape(getPasswordToStore($password, $vdata['username']));
|
|
||||||
|
|
||||||
DB::query("update user_info set password = '$esc_password' where username = '$esc_username'");
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", [
|
||||||
|
"password" => getPasswordToStore($password, $vdata['username']),
|
||||||
|
],
|
||||||
|
"where", [
|
||||||
|
"username" => $vdata['username'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']);
|
dieWithJsonData(['status' => 'success', 'message' => '用户 ' . $vdata['username'] . ' 的密码已经被成功重置。']);
|
||||||
};
|
};
|
||||||
$change_password_form->submit_button_config['margin_class'] = 'mt-3';
|
$change_password_form->submit_button_config['class_str'] = 'btn btn-secondary mt-3';
|
||||||
$change_password_form->submit_button_config['text'] = '重置';
|
$change_password_form->submit_button_config['text'] = '重置';
|
||||||
$change_password_form->setAjaxSubmit(<<<EOD
|
$change_password_form->setAjaxSubmit(<<<EOD
|
||||||
function(res) {
|
function(res) {
|
||||||
@ -395,8 +513,12 @@ EOD);
|
|||||||
EOD);
|
EOD);
|
||||||
$change_password_form->runAtServer();
|
$change_password_form->runAtServer();
|
||||||
|
|
||||||
$change_usergroup_form = new UOJForm('change_usergroup');
|
$change_usergroup_form = new UOJBs4Form('change_usergroup');
|
||||||
$change_usergroup_form->addVInput('username', 'text', '用户名', '',
|
$change_usergroup_form->addVInput(
|
||||||
|
'username',
|
||||||
|
'text',
|
||||||
|
'用户名',
|
||||||
|
'',
|
||||||
function ($username, &$vdata) {
|
function ($username, &$vdata) {
|
||||||
if (!validateUsername($username)) {
|
if (!validateUsername($username)) {
|
||||||
return '用户名不合法';
|
return '用户名不合法';
|
||||||
@ -470,8 +592,12 @@ EOD);
|
|||||||
'page_len' => 10
|
'page_len' => 10
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$custom_test_deleter = new UOJForm('custom_test_deleter');
|
$custom_test_deleter = new UOJBs4Form('custom_test_deleter');
|
||||||
$custom_test_deleter->addInput('last', 'text', '删除末尾记录', '5',
|
$custom_test_deleter->addInput(
|
||||||
|
'last',
|
||||||
|
'text',
|
||||||
|
'删除末尾记录',
|
||||||
|
'5',
|
||||||
function ($x, &$vdata) {
|
function ($x, &$vdata) {
|
||||||
if (!validateUInt($x)) {
|
if (!validateUInt($x)) {
|
||||||
return '不合法';
|
return '不合法';
|
||||||
@ -492,8 +618,12 @@ EOD);
|
|||||||
$custom_test_deleter->submit_button_config['align'] = 'compressed';
|
$custom_test_deleter->submit_button_config['align'] = 'compressed';
|
||||||
$custom_test_deleter->runAtServer();
|
$custom_test_deleter->runAtServer();
|
||||||
} elseif ($cur_tab == 'judger') {
|
} elseif ($cur_tab == 'judger') {
|
||||||
$judger_adder = new UOJForm('judger_adder');
|
$judger_adder = new UOJBs4Form('judger_adder');
|
||||||
$judger_adder->addInput('judger_adder_name', 'text', '评测机名称', '',
|
$judger_adder->addInput(
|
||||||
|
'judger_adder_name',
|
||||||
|
'text',
|
||||||
|
'评测机名称',
|
||||||
|
'',
|
||||||
function ($x, &$vdata) {
|
function ($x, &$vdata) {
|
||||||
if (!validateUsername($x)) {
|
if (!validateUsername($x)) {
|
||||||
return '不合法';
|
return '不合法';
|
||||||
@ -513,8 +643,12 @@ EOD);
|
|||||||
$judger_adder->submit_button_config['align'] = 'compressed';
|
$judger_adder->submit_button_config['align'] = 'compressed';
|
||||||
$judger_adder->runAtServer();
|
$judger_adder->runAtServer();
|
||||||
|
|
||||||
$judger_deleter = new UOJForm('judger_deleter');
|
$judger_deleter = new UOJBs4Form('judger_deleter');
|
||||||
$judger_deleter->addInput('judger_deleter_name', 'text', '评测机名称', '',
|
$judger_deleter->addInput(
|
||||||
|
'judger_deleter_name',
|
||||||
|
'text',
|
||||||
|
'评测机名称',
|
||||||
|
'',
|
||||||
function ($x, &$vdata) {
|
function ($x, &$vdata) {
|
||||||
if (!validateUsername($x)) {
|
if (!validateUsername($x)) {
|
||||||
return '不合法';
|
return '不合法';
|
||||||
@ -552,10 +686,13 @@ EOD);
|
|||||||
dieWithAlert('删除成功!');
|
dieWithAlert('删除成功!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$change_user_image_total_size_limit_form = new UOJBs4Form('change_user_image_total_size_limit');
|
||||||
$change_user_image_total_size_limit_form = new UOJForm('change_user_image_total_size_limit');
|
|
||||||
$change_user_image_total_size_limit_form->submit_button_config['align'] = 'compressed';
|
$change_user_image_total_size_limit_form->submit_button_config['align'] = 'compressed';
|
||||||
$change_user_image_total_size_limit_form->addInput('change_user_image_total_size_limit_username', 'text', '用户名', '',
|
$change_user_image_total_size_limit_form->addInput(
|
||||||
|
'change_user_image_total_size_limit_username',
|
||||||
|
'text',
|
||||||
|
'用户名',
|
||||||
|
'',
|
||||||
function ($x, &$vdata) {
|
function ($x, &$vdata) {
|
||||||
if (!validateUsername($x)) {
|
if (!validateUsername($x)) {
|
||||||
return '用户名不合法';
|
return '用户名不合法';
|
||||||
@ -571,7 +708,11 @@ EOD);
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
$change_user_image_total_size_limit_form->addInput('change_user_image_total_size_limit_limit', 'text', '存储限制(单位:Byte)', '104857600',
|
$change_user_image_total_size_limit_form->addInput(
|
||||||
|
'change_user_image_total_size_limit_limit',
|
||||||
|
'text',
|
||||||
|
'存储限制(单位:Byte)',
|
||||||
|
'104857600',
|
||||||
function ($x, &$vdata) {
|
function ($x, &$vdata) {
|
||||||
if (!validateUInt($x, 10)) {
|
if (!validateUInt($x, 10)) {
|
||||||
return '限制不合法';
|
return '限制不合法';
|
||||||
@ -587,18 +728,25 @@ EOD);
|
|||||||
},
|
},
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
$change_user_image_total_size_limit_form->handle = function (&$vdata) {
|
$change_user_image_total_size_limit_form->handle = function (&$vdata) {
|
||||||
DB::update("UPDATE user_info SET images_size_limit = {$vdata['limit']} WHERE username = '{$vdata['username']}'");
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", [
|
||||||
|
'extra' => DB::json_set(
|
||||||
|
'extra',
|
||||||
|
'$.image_hosting.total_size_limit', $vdata['limit'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
"where", ["username" => $vdata['username']]
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
$change_user_image_total_size_limit_form->runAtServer();
|
$change_user_image_total_size_limit_form->runAtServer();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader(UOJLocale::get('system manage')) ?>
|
<?php echoUOJPageHeader(UOJLocale::get('system manage')) ?>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= UOJLocale::get('system manage') ?>
|
<?= UOJLocale::get('system manage') ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -606,9 +754,7 @@ EOD);
|
|||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
|
|
||||||
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
@ -676,8 +822,7 @@ EOD);
|
|||||||
col_tr += '</tr>';
|
col_tr += '</tr>';
|
||||||
|
|
||||||
return col_tr;
|
return col_tr;
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
div_classes: ['table-responsive'],
|
div_classes: ['table-responsive'],
|
||||||
table_classes: ['table', 'align-middle'],
|
table_classes: ['table', 'align-middle'],
|
||||||
page_len: 20,
|
page_len: 20,
|
||||||
@ -722,8 +867,7 @@ EOD);
|
|||||||
col_tr += '</tr>';
|
col_tr += '</tr>';
|
||||||
|
|
||||||
return col_tr;
|
return col_tr;
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
div_classes: ['table-responsive'],
|
div_classes: ['table-responsive'],
|
||||||
table_classes: ['table', 'align-middle'],
|
table_classes: ['table', 'align-middle'],
|
||||||
page_len: 20,
|
page_len: 20,
|
||||||
@ -770,8 +914,7 @@ EOD);
|
|||||||
col_tr += '</tr>';
|
col_tr += '</tr>';
|
||||||
|
|
||||||
return col_tr;
|
return col_tr;
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
div_classes: ['table-responsive'],
|
div_classes: ['table-responsive'],
|
||||||
table_classes: ['table', 'align-middle'],
|
table_classes: ['table', 'align-middle'],
|
||||||
page_len: 20,
|
page_len: 20,
|
||||||
@ -838,11 +981,7 @@ $(document).ready(function() {
|
|||||||
];
|
];
|
||||||
?>
|
?>
|
||||||
<?php foreach ($usergroups as $name => $group) : ?>
|
<?php foreach ($usergroups as $name => $group) : ?>
|
||||||
<option value="<?= $name ?>"
|
<option value="<?= $name ?>" <?php if ($_GET['usergroup'] == $name) : ?> selected <?php endif ?>><?= $group ?></option>
|
||||||
<?php if ($_GET['usergroup'] == $name): ?>
|
|
||||||
selected
|
|
||||||
<?php endif ?>
|
|
||||||
><?= $group ?></option>
|
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -857,15 +996,10 @@ $(document).ready(function() {
|
|||||||
'problem_uploader' => 'problem_uploader: 题目上传者',
|
'problem_uploader' => 'problem_uploader: 题目上传者',
|
||||||
'problem_manager' => 'problem_manager: 题目管理员',
|
'problem_manager' => 'problem_manager: 题目管理员',
|
||||||
'contest_judger' => 'contest_judger: 比赛评测员',
|
'contest_judger' => 'contest_judger: 比赛评测员',
|
||||||
'contest_only' => 'contest_only: 仅比赛参加者',
|
|
||||||
];
|
];
|
||||||
?>
|
?>
|
||||||
<?php foreach ($usertypes as $name => $type) : ?>
|
<?php foreach ($usertypes as $name => $type) : ?>
|
||||||
<option value="<?= $name ?>"
|
<option value="<?= $name ?>" <?php if ($_GET['usertype'] == $name) : ?> selected <?php endif ?>><?= $type ?></option>
|
||||||
<?php if ($_GET['usertype'] == $name): ?>
|
|
||||||
selected
|
|
||||||
<?php endif ?>
|
|
||||||
><?= $type ?></option>
|
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,23 +2,15 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requireLib('calendar_heatmap');
|
requireLib('calendar_heatmap');
|
||||||
|
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
($user = UOJUser::query($_GET['username'])) || UOJResponse::page404();
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
$username = $_GET['username'];
|
|
||||||
|
|
||||||
if (!validateUsername($username) || !($user = queryUser($username))) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader($user['username'] . ' - ' . UOJLocale::get('user profile')) ?>
|
<?php echoUOJPageHeader($user['username'] . ' - ' . UOJLocale::get('user profile')) ?>
|
||||||
|
|
||||||
<?php uojIncludeView('user-info', array('user' => $user, 'myUser' => $myUser)) ?>
|
<?php uojIncludeView('user-info', ['user' => $user]) ?>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -7,13 +7,9 @@
|
|||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validateUsername($_GET['username']) || !($user = queryUser($_GET['username']))) {
|
($user = UOJUser::query($_GET['username'])) || UOJResponse::page404();
|
||||||
become404Page();
|
(isSuperUser(Auth::user()) || Auth::id() == $user['username']) || UOJResponse::page403();
|
||||||
}
|
$extra = UOJUser::getExtra($user);
|
||||||
|
|
||||||
if (!isSuperUser($myUser) && $myUser['username'] != $user['username']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET['tab'])) {
|
if (isset($_GET['tab'])) {
|
||||||
$cur_tab = $_GET['tab'];
|
$cur_tab = $_GET['tab'];
|
||||||
@ -41,7 +37,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($cur_tab == 'profile') {
|
if ($cur_tab == 'profile') {
|
||||||
$update_profile_form = new UOJForm('update_profile');
|
$update_profile_form = new UOJBs4Form('update_profile');
|
||||||
$username = UOJLocale::get('username');
|
$username = UOJLocale::get('username');
|
||||||
$avatar = UOJLocale::get('avatar');
|
$avatar = UOJLocale::get('avatar');
|
||||||
$update_profile_form->appendHTML(<<<EOD
|
$update_profile_form->appendHTML(<<<EOD
|
||||||
@ -51,13 +47,19 @@
|
|||||||
<div id="help-username" class="form-text">用户名不能被修改。</div>
|
<div id="help-username" class="form-text">用户名不能被修改。</div>
|
||||||
</div>
|
</div>
|
||||||
EOD);
|
EOD);
|
||||||
if (isSuperUser($myUser)) {
|
if (isSuperUser(Auth::user())) {
|
||||||
$update_profile_form->addVInput('realname', 'text', UOJLocale::get('user::real name'), $user['realname'],
|
$update_profile_form->addVInput(
|
||||||
|
'realname',
|
||||||
|
'text',
|
||||||
|
UOJLocale::get('user::real name'),
|
||||||
|
$user['realname'],
|
||||||
function ($realname, &$vdata) {
|
function ($realname, &$vdata) {
|
||||||
$vdata['realname'] = $realname;
|
$vdata['realname'] = $realname;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$real_name = UOJLocale::get('user::real name');
|
$real_name = UOJLocale::get('user::real name');
|
||||||
$update_profile_form->appendHTML(<<<EOD
|
$update_profile_form->appendHTML(<<<EOD
|
||||||
@ -71,14 +73,18 @@ EOD);
|
|||||||
$update_profile_form->addVCheckboxes('avatar_source', [
|
$update_profile_form->addVCheckboxes('avatar_source', [
|
||||||
'gravatar' => 'Gravatar',
|
'gravatar' => 'Gravatar',
|
||||||
'qq' => 'QQ',
|
'qq' => 'QQ',
|
||||||
], UOJLocale::get('user::avatar source'), $user['avatar_source']);
|
], UOJLocale::get('user::avatar source'), $extra['avatar_source'] ?: 'gravatar');
|
||||||
$change_avatar_help = UOJLocale::get('change avatar help');
|
$change_avatar_help = UOJLocale::get('change avatar help');
|
||||||
$update_profile_form->appendHTML(<<<EOD
|
$update_profile_form->appendHTML(<<<EOD
|
||||||
<div style="margin-top: -1.25rem;" class="mb-3 small text-muted">
|
<div style="margin-top: -1.25rem;" class="mb-3 small text-muted">
|
||||||
$change_avatar_help
|
$change_avatar_help
|
||||||
</div>
|
</div>
|
||||||
EOD);
|
EOD);
|
||||||
$update_profile_form->addVInput('email', 'email', UOJLocale::get('email'), $user['email'],
|
$update_profile_form->addVInput(
|
||||||
|
'email',
|
||||||
|
'email',
|
||||||
|
UOJLocale::get('email'),
|
||||||
|
$user['email'] ?: '',
|
||||||
function ($email, &$vdata) {
|
function ($email, &$vdata) {
|
||||||
if (!validateEmail($email)) {
|
if (!validateEmail($email)) {
|
||||||
return 'Email 格式不合法。';
|
return 'Email 格式不合法。';
|
||||||
@ -87,8 +93,14 @@ EOD);
|
|||||||
$vdata['email'] = $email;
|
$vdata['email'] = $email;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
$update_profile_form->addVInput('qq', 'text', UOJLocale::get('QQ'), $user['qq'] == 0 ? '' : $user['qq'],
|
null
|
||||||
|
);
|
||||||
|
$update_profile_form->addVInput(
|
||||||
|
'qq',
|
||||||
|
'text',
|
||||||
|
UOJLocale::get('QQ'),
|
||||||
|
$user['qq'] == 0 ? '' : $user['qq'],
|
||||||
function ($qq, &$vdata) {
|
function ($qq, &$vdata) {
|
||||||
if ($qq && !validateQQ($qq)) {
|
if ($qq && !validateQQ($qq)) {
|
||||||
return 'QQ 格式不合法。';
|
return 'QQ 格式不合法。';
|
||||||
@ -97,8 +109,14 @@ EOD);
|
|||||||
$vdata['qq'] = $qq;
|
$vdata['qq'] = $qq;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
$update_profile_form->addVInput('github', 'text', 'GitHub', $user['github'],
|
null
|
||||||
|
);
|
||||||
|
$update_profile_form->addVInput(
|
||||||
|
'github',
|
||||||
|
'text',
|
||||||
|
'GitHub',
|
||||||
|
$extra['social']['github'] ?: '',
|
||||||
function ($github, &$vdata) {
|
function ($github, &$vdata) {
|
||||||
if ($github && !validateGitHubUsername($github)) {
|
if ($github && !validateGitHubUsername($github)) {
|
||||||
return 'GitHub 用户名不合法。';
|
return 'GitHub 用户名不合法。';
|
||||||
@ -107,14 +125,22 @@ EOD);
|
|||||||
$vdata['github'] = $github;
|
$vdata['github'] = $github;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
if (isSuperUser($myUser)) {
|
null
|
||||||
$update_profile_form->addVInput('school', 'text', UOJLocale::get('school'), $user['school'],
|
);
|
||||||
|
if (isSuperUser(Auth::user())) {
|
||||||
|
$update_profile_form->addVInput(
|
||||||
|
'school',
|
||||||
|
'text',
|
||||||
|
UOJLocale::get('school'),
|
||||||
|
$user['school'] ?: '',
|
||||||
function ($school, &$vdata) {
|
function ($school, &$vdata) {
|
||||||
$vdata['school'] = $school;
|
$vdata['school'] = $school;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$school = UOJLocale::get('school');
|
$school = UOJLocale::get('school');
|
||||||
$update_profile_form->appendHTML(<<<EOD
|
$update_profile_form->appendHTML(<<<EOD
|
||||||
@ -130,7 +156,11 @@ EOD);
|
|||||||
'M' => UOJLocale::get('male'),
|
'M' => UOJLocale::get('male'),
|
||||||
'F' => UOJLocale::get('female'),
|
'F' => UOJLocale::get('female'),
|
||||||
], UOJLocale::get('sex'), $user['sex']);
|
], UOJLocale::get('sex'), $user['sex']);
|
||||||
$update_profile_form->addVInput('motto', 'text', UOJLocale::get('motto'), $user['motto'],
|
$update_profile_form->addVInput(
|
||||||
|
'motto',
|
||||||
|
'text',
|
||||||
|
UOJLocale::get('motto'),
|
||||||
|
$user['motto'] ?: '',
|
||||||
function ($motto, &$vdata) {
|
function ($motto, &$vdata) {
|
||||||
if (!validateMotto($motto)) {
|
if (!validateMotto($motto)) {
|
||||||
return '格言格式不合法';
|
return '格言格式不合法';
|
||||||
@ -139,18 +169,30 @@ EOD);
|
|||||||
$vdata['motto'] = $motto;
|
$vdata['motto'] = $motto;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
$update_profile_form->addVInput('codeforces_handle', 'text', UOJLocale::get('codeforces handle'), $user['codeforces_handle'],
|
null
|
||||||
function($codeforces_handle, &$vdata) {
|
);
|
||||||
if ($codeforces_handle && !validateUsername($codeforces_handle)) {
|
$update_profile_form->addVInput(
|
||||||
|
'codeforces',
|
||||||
|
'text',
|
||||||
|
UOJLocale::get('codeforces handle'),
|
||||||
|
$extra['social']['codeforces'] ?: '',
|
||||||
|
function ($codeforces, &$vdata) {
|
||||||
|
if ($codeforces && !validateUsername($codeforces)) {
|
||||||
return 'Codeforces 用户名格式不合法。';
|
return 'Codeforces 用户名格式不合法。';
|
||||||
}
|
}
|
||||||
|
|
||||||
$vdata['codeforces_handle'] = $codeforces_handle;
|
$vdata['codeforces'] = $codeforces;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
$update_profile_form->addVInput('website', 'text', UOJLocale::get('user::website'), $user['website'],
|
null
|
||||||
|
);
|
||||||
|
$update_profile_form->addVInput(
|
||||||
|
'website',
|
||||||
|
'text',
|
||||||
|
UOJLocale::get('user::website'),
|
||||||
|
$extra['social']['website'] ?: '',
|
||||||
function ($url, &$vdata) {
|
function ($url, &$vdata) {
|
||||||
if ($url && !validateURL($url)) {
|
if ($url && !validateURL($url)) {
|
||||||
return '链接格式不合法。';
|
return '链接格式不合法。';
|
||||||
@ -159,29 +201,49 @@ EOD);
|
|||||||
$vdata['website'] = $url;
|
$vdata['website'] = $url;
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}, null);
|
},
|
||||||
$update_profile_form->handle = function(&$vdata) use ($user, $myUser) {
|
null
|
||||||
$esc_email = DB::escape($vdata['email']);
|
);
|
||||||
$esc_qq = DB::escape($vdata['qq']);
|
$update_profile_form->handle = function (&$vdata) use ($user) {
|
||||||
$esc_github = DB::escape($vdata['github']);
|
$data = [
|
||||||
$esc_sex = DB::escape($_POST['sex']);
|
'email' => $vdata['email'],
|
||||||
$esc_motto = DB::escape($vdata['motto']);
|
'qq' => $vdata['qq'],
|
||||||
$esc_codeforces_handle = DB::escape($vdata['codeforces_handle']);
|
'sex' => $_POST['sex'],
|
||||||
$esc_website = DB::escape($vdata['website']);
|
'motto' => $vdata['motto'],
|
||||||
$esc_avatar_source = DB::escape($_POST['avatar_source']);
|
];
|
||||||
|
|
||||||
if (isSuperUser($myUser)) {
|
if (isSuperUser(Auth::user())) {
|
||||||
$esc_realname = DB::escape($vdata['realname']);
|
$data['realname'] = $vdata['realname'];
|
||||||
$esc_school = DB::escape($vdata['school']);
|
$data['school'] = $vdata['school'];
|
||||||
|
|
||||||
DB::update("UPDATE user_info SET realname = '$esc_realname', school = '$esc_school' WHERE username = '{$user['username']}'");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DB::update("UPDATE user_info SET email = '$esc_email', qq = '$esc_qq', sex = '$esc_sex', motto = '$esc_motto', codeforces_handle = '$esc_codeforces_handle', github = '$esc_github', website = '$esc_website', avatar_source = '$esc_avatar_source' WHERE username = '{$user['username']}'");
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", $data,
|
||||||
|
"where", ["username" => $user['username']]
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", [
|
||||||
|
'extra' => DB::json_set(
|
||||||
|
'extra',
|
||||||
|
'$.avatar_source',
|
||||||
|
$_POST['avatar_source'],
|
||||||
|
'$.social.github',
|
||||||
|
$vdata['github'],
|
||||||
|
'$.social.codeforces',
|
||||||
|
$vdata['codeforces'],
|
||||||
|
'$.social.website',
|
||||||
|
$vdata['website']
|
||||||
|
),
|
||||||
|
],
|
||||||
|
"where", ["username" => $user['username']]
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success']);
|
dieWithJsonData(['status' => 'success']);
|
||||||
};
|
};
|
||||||
$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->submit_button_config['text'] = '更新';
|
||||||
$update_profile_form->setAjaxSubmit(<<<EOD
|
$update_profile_form->setAjaxSubmit(<<<EOD
|
||||||
function(res) {
|
function(res) {
|
||||||
@ -220,13 +282,18 @@ EOD);
|
|||||||
dieWithJsonData(['status' => 'error', 'message' => '新密码不能与旧密码相同']);
|
dieWithJsonData(['status' => 'error', 'message' => '新密码不能与旧密码相同']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$password = getPasswordToStore($new_password, $user['username']);
|
DB::update([
|
||||||
DB::update("UPDATE `user_info` SET `password` = '$password' where `username` = '{$user['username']}'");
|
"update user_info",
|
||||||
|
"set", [
|
||||||
|
'password' => getPasswordToStore($new_password, $user['username']),
|
||||||
|
],
|
||||||
|
"where", ["username" => $user['username']]
|
||||||
|
]);
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '密码修改成功']);
|
dieWithJsonData(['status' => 'success', 'message' => '密码修改成功']);
|
||||||
}
|
}
|
||||||
} elseif ($cur_tab == 'privilege') {
|
} elseif ($cur_tab == 'privilege') {
|
||||||
if (isset($_POST['submit-privilege']) && $_POST['submit-privilege'] == 'privilege' && isSuperUser($myUser)) {
|
if (isset($_POST['submit-privilege']) && $_POST['submit-privilege'] == 'privilege' && isSuperUser(Auth::user())) {
|
||||||
$user['usertype'] = 'student';
|
$user['usertype'] = 'student';
|
||||||
|
|
||||||
if ($_POST['user_type'] == 'teacher') {
|
if ($_POST['user_type'] == 'teacher') {
|
||||||
@ -248,24 +315,20 @@ EOD);
|
|||||||
addUserType($user, 'contest_judger');
|
addUserType($user, 'contest_judger');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_POST['contest_only'] == 'yes') {
|
|
||||||
addUserType($user, 'contest_only');
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::update("UPDATE `user_info` SET `usertype` = '{$user['usertype']}' where `username` = '{$user['username']}'");
|
DB::update("UPDATE `user_info` SET `usertype` = '{$user['usertype']}' where `username` = '{$user['username']}'");
|
||||||
|
|
||||||
dieWithJsonData(['status' => 'success', 'message' => '权限修改成功']);
|
dieWithJsonData(['status' => 'success', 'message' => '权限修改成功']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$pageTitle = $user['username'] == $myUser['username']
|
$pageTitle = $user['username'] == Auth::id()
|
||||||
? UOJLocale::get('modify my profile')
|
? UOJLocale::get('modify my profile')
|
||||||
: UOJLocale::get('modify his profile', $user['username'])
|
: UOJLocale::get('modify his profile', $user['username'])
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader($pageTitle) ?>
|
<?php echoUOJPageHeader($pageTitle) ?>
|
||||||
|
|
||||||
<h1 class="h2">
|
<h1>
|
||||||
<?= $pageTitle ?>
|
<?= $pageTitle ?>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -275,14 +338,11 @@ EOD);
|
|||||||
|
|
||||||
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
<?= HTML::navListGroup($tabs_info, $cur_tab) ?>
|
||||||
|
|
||||||
<a
|
<a class="btn btn-light d-block mt-2 w-100 text-start text-primary" style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;" href="<?= HTML::url("/user/{$user['username']}") ?>">
|
||||||
class="btn btn-light d-block mt-2 w-100 text-start text-primary"
|
|
||||||
style="--bs-btn-hover-bg: #d3d4d570; --bs-btn-hover-border-color: transparent;"
|
|
||||||
href="<?= HTML::url("/user/{$user['username']}") ?>">
|
|
||||||
<i class="bi bi-arrow-left"></i> 返回
|
<i class="bi bi-arrow-left"></i> 返回
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<?php if (isSuperUser($myUser) && $user['username'] != $myUser['username']): ?>
|
<?php if ($user['username'] != Auth::id()) : ?>
|
||||||
<div class="alert alert-warning mt-3 small" role="alert">
|
<div class="alert alert-warning mt-3 small" role="alert">
|
||||||
您正在使用管理特权查看并编辑其它用户的资料。
|
您正在使用管理特权查看并编辑其它用户的资料。
|
||||||
</div>
|
</div>
|
||||||
@ -326,7 +386,7 @@ EOD);
|
|||||||
<input type="password" class="form-control" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your new password') ?>" maxlength="20">
|
<input type="password" class="form-control" id="input-confirm_password" placeholder="<?= UOJLocale::get('re-enter your new password') ?>" maxlength="20">
|
||||||
<div id="help-confirm_password" class="invalid-feedback"></div>
|
<div id="help-confirm_password" class="invalid-feedback"></div>
|
||||||
</div>
|
</div>
|
||||||
<?php if (isSuperUser($myUser) && $user['username'] != $myUser['username']): ?>
|
<?php if (isSuperUser(Auth::user()) && $user['username'] != $myUser['username']) : ?>
|
||||||
<div class="alert alert-warning mb-0" role="alert">
|
<div class="alert alert-warning mb-0" role="alert">
|
||||||
如需重置其他用户的密码,请前往 <a href="/super_manage/users" class="alert-link">系统管理</a> 页面操作。
|
如需重置其他用户的密码,请前往 <a href="/super_manage/users" class="alert-link">系统管理</a> 页面操作。
|
||||||
</div>
|
</div>
|
||||||
@ -392,7 +452,7 @@ EOD);
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
<div id="result-alert" class="alert" role="alert" style="display: none"></div>
|
||||||
<form id="form-privilege" method="post">
|
<form id="form-privilege" method="post">
|
||||||
<?php if (isSuperUser($myUser)): ?>
|
<?php if (isSuperUser(Auth::user())) : ?>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<fieldset disabled>
|
<fieldset disabled>
|
||||||
@ -449,16 +509,9 @@ EOD);
|
|||||||
<?= UOJLocale::get('user::contest judger') ?>
|
<?= UOJLocale::get('user::contest judger') ?>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check form-switch">
|
|
||||||
<input class="form-check-input" type="checkbox" role="switch" name="contest_only" id="input-contest_only" <?= hasUserType($user, 'contest_only') ? 'checked' : '' ?>>
|
|
||||||
<label class="form-check-label" for="input-contest_only">
|
|
||||||
<?= UOJLocale::get('user::contest only') ?>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<?php if (isSuperUser($myUser)): ?>
|
<?php if (isSuperUser(Auth::user())) : ?>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<button type="submit" id="button-submit-privilege" name="submit-privilege" value="privilege" class="mt-3 btn btn-secondary">更新</button>
|
<button type="submit" id="button-submit-privilege" name="submit-privilege" value="privilege" class="mt-3 btn btn-secondary">更新</button>
|
||||||
</div>
|
</div>
|
||||||
@ -473,7 +526,6 @@ EOD);
|
|||||||
problem_uploader: $('input[name=problem_uploader]').prop('checked') ? 'yes' : 'no',
|
problem_uploader: $('input[name=problem_uploader]').prop('checked') ? 'yes' : 'no',
|
||||||
problem_manager: $('input[name=problem_manager]').prop('checked') ? 'yes' : 'no',
|
problem_manager: $('input[name=problem_manager]').prop('checked') ? 'yes' : 'no',
|
||||||
contest_judger: $('input[name=contest_judger]').prop('checked') ? 'yes' : 'no',
|
contest_judger: $('input[name=contest_judger]').prop('checked') ? 'yes' : 'no',
|
||||||
contest_only: $('input[name=contest_only]').prop('checked') ? 'yes' : 'no',
|
|
||||||
'submit-privilege': 'privilege',
|
'submit-privilege': 'privilege',
|
||||||
}, function(res) {
|
}, function(res) {
|
||||||
if (res && res.status === 'success') {
|
if (res && res.status === 'success') {
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!Auth::check() && UOJConfig::$data['switch']['force-login']) {
|
if (!Auth::check()) {
|
||||||
redirectToLogin();
|
redirectToLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNormalUser($myUser) && UOJConfig::$data['switch']['force-login']) {
|
|
||||||
become403Page();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMsgPost() {
|
function handleMsgPost() {
|
||||||
global $myUser;
|
global $myUser;
|
||||||
if (!isset($_POST['receiver'])) {
|
if (!isset($_POST['receiver'])) {
|
||||||
|
@ -2,20 +2,18 @@
|
|||||||
requireLib('bootstrap5');
|
requireLib('bootstrap5');
|
||||||
requirePHPLib('form');
|
requirePHPLib('form');
|
||||||
|
|
||||||
if (!Auth::check()) {
|
Auth::check() || redirectToLogin();
|
||||||
redirectToLogin();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateUsername($_GET['username']) || !($user = queryUser($_GET['username']))) {
|
if (!($user = UOJUser::query($_GET['username']))) {
|
||||||
become404Page();
|
become404Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSuperUser($myUser) && $myUser['username'] != $user['username']) {
|
if (!isSuperUser(Auth::user()) && Auth::id() != $user['username']) {
|
||||||
become403Page();
|
become403Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
function newDeleteSystemMsgForm($id) {
|
function newDeleteSystemMsgForm($id) {
|
||||||
$form = new UOJForm('remove_system_msg_' . $id);
|
$form = new UOJBs4Form('remove_system_msg_' . $id);
|
||||||
|
|
||||||
$form->addHidden("msg_id", $id, function ($msg_id) {
|
$form->addHidden("msg_id", $id, function ($msg_id) {
|
||||||
global $user;
|
global $user;
|
||||||
@ -36,8 +34,7 @@
|
|||||||
DB::delete("delete from user_system_msg where id = {$msg_id}");
|
DB::delete("delete from user_system_msg where id = {$msg_id}");
|
||||||
};
|
};
|
||||||
$form->submit_button_config['text'] = '删除';
|
$form->submit_button_config['text'] = '删除';
|
||||||
$form->submit_button_config['margin_class'] = 'mt-0';
|
$form->submit_button_config['class_str'] = 'btn btn-link text-decoration-none text-danger p-0 mt-0';
|
||||||
$form->submit_button_config['class_str'] = 'btn btn-link text-decoration-none text-danger p-0';
|
|
||||||
$form->submit_button_config['align'] = 'inline';
|
$form->submit_button_config['align'] = 'inline';
|
||||||
$form->submit_button_config['smart_confirm'] = '';
|
$form->submit_button_config['smart_confirm'] = '';
|
||||||
|
|
||||||
@ -64,10 +61,6 @@
|
|||||||
$system_msgs[$idx]['delete_form'] = $delete_form;
|
$system_msgs[$idx]['delete_form'] = $delete_form;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Auth::id() == $user['username']) {
|
|
||||||
DB::update("update user_system_msg set read_time = now() where receiver = '" . $user['username'] . "'");
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageHeader('系统消息') ?>
|
<?php echoUOJPageHeader('系统消息') ?>
|
||||||
@ -75,10 +68,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- left col -->
|
<!-- left col -->
|
||||||
<div class="col-lg-9">
|
<div class="col-lg-9">
|
||||||
|
<h1>系统消息</h1>
|
||||||
<h1 class="h2">
|
|
||||||
系统消息
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
@ -112,16 +102,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?= $pag->pagination() ?>
|
<?= $pag->pagination() ?>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- end left col -->
|
<!-- end left col -->
|
||||||
|
|
||||||
<!-- right col -->
|
<!-- right col -->
|
||||||
<aside class="col-lg-3 mt-3 mt-lg-0">
|
<aside class="col-lg-3 mt-3 mt-lg-0">
|
||||||
<?php uojIncludeView('sidebar', array()) ?>
|
<?php uojIncludeView('sidebar') ?>
|
||||||
</aside>
|
</aside>
|
||||||
<!-- end right col -->
|
<!-- end right col -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<?php
|
||||||
|
if (Auth::id() == $user['username']) {
|
||||||
|
DB::update("update user_system_msg set read_time = now() where receiver = '" . $user['username'] . "'");
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
<?php echoUOJPageFooter() ?>
|
<?php echoUOJPageFooter() ?>
|
||||||
|
@ -33,30 +33,103 @@ function genMoreContestInfo(&$contest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateContestPlayerNum($contest) {
|
function updateContestPlayerNum($contest) {
|
||||||
DB::update("update contests set player_num = (select count(*) from contests_registrants where contest_id = {$contest['id']}) where id = {$contest['id']}");
|
DB::update([
|
||||||
|
"update contests",
|
||||||
|
"set", [
|
||||||
|
"player_num" => DB::rawbracket([
|
||||||
|
"select count(*) from contests_registrants",
|
||||||
|
"where", ["contest_id" => $contest['id']]
|
||||||
|
])
|
||||||
|
], "where", ["id" => $contest['id']]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return value: ['problems' => $problems, 'data' => $data, 'people' => $people]
|
||||||
// problems: pos => id
|
// problems: pos => id
|
||||||
|
//
|
||||||
|
// for individual competition:
|
||||||
|
// people : username, realname
|
||||||
|
// for team competition:
|
||||||
|
// people : username, null, ['team_name' => team_name, 'members' => members]
|
||||||
|
//
|
||||||
|
// for OI/IOI contest:
|
||||||
// data : id, submit_time, submitter, problem_pos, score
|
// data : id, submit_time, submitter, problem_pos, score
|
||||||
// people : username
|
// for ACM contest:
|
||||||
function queryContestData($contest, $config = array(), $is_after_contest_query = false) {
|
// data : id, submit_time (plus penalty), submitter, problem_pos, score, cnt, n_failures
|
||||||
|
// if the contest is not finished, then cnt = null, n_failures = null;
|
||||||
|
// otherwise, cnt is the total number of submission of this subitter for this problem
|
||||||
|
// (by the time of getting 100, including the first submission with score 100)
|
||||||
|
// n_failures is the number of failure attempts of this submitter for this problem
|
||||||
|
function queryContestData($contest, $config = []) {
|
||||||
mergeConfig($config, [
|
mergeConfig($config, [
|
||||||
'pre_final' => false
|
'pre_final' => false,
|
||||||
|
'after_contest' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$problems = [];
|
$problems = [];
|
||||||
$prob_pos = [];
|
$prob_pos = [];
|
||||||
$n_problems = 0;
|
$n_problems = 0;
|
||||||
$result = DB::query("select problem_id from contests_problems where contest_id = {$contest['id']} order by dfn, problem_id");
|
$res = DB::selectAll([
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
"select problem_id from contests_problems",
|
||||||
|
"where", ["contest_id" => $contest['id']],
|
||||||
|
"order by level, problem_id"
|
||||||
|
], DB::NUM);
|
||||||
|
foreach ($res as $row) {
|
||||||
$prob_pos[$problems[] = (int)$row[0]] = $n_problems++;
|
$prob_pos[$problems[] = (int)$row[0]] = $n_problems++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($contest['extra_config']['basic_rule'] == 'OI' || $contest['extra_config']['basic_rule'] == 'IOI') {
|
||||||
|
$data = queryOIorIOIContestSubmissionData($contest, $problems, $prob_pos, $config);
|
||||||
|
} elseif ($contest['extra_config']['basic_rule'] == 'ACM') {
|
||||||
|
$data = queryACMContestSubmissionData($contest, $problems, $prob_pos, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
$people = [];
|
||||||
|
|
||||||
|
if ($contest['extra_config']['individual_or_team'] == 'individual') {
|
||||||
|
$people = DB::selectAll([
|
||||||
|
"select contests_registrants.username, user_info.realname from contests_registrants",
|
||||||
|
"inner join user_info on contests_registrants.username = user_info.username",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
"has_participated" => 1
|
||||||
|
]
|
||||||
|
], DB::NUM);
|
||||||
|
} elseif ($contest['extra_config']['individual_or_team'] == 'team') {
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select user_info.username, null, user_info.extra from contests_registrants, user_info",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
"has_participated" => 1,
|
||||||
|
"contests_registrants.username = user_info.username"
|
||||||
|
]
|
||||||
|
], DB::NUM);
|
||||||
|
foreach ($res as $row) {
|
||||||
|
$extra = json_decode($row[2], true);
|
||||||
|
$row[2] = [
|
||||||
|
'team_name' => $extra['acm']['team_name'],
|
||||||
|
'members' => $extra['acm']['members']
|
||||||
|
];
|
||||||
|
$people[] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['problems' => $problems, 'data' => $data, 'people' => $people];
|
||||||
|
}
|
||||||
|
function queryOIorIOIContestSubmissionData($contest, $problems, $prob_pos, $config = []) {
|
||||||
$data = [];
|
$data = [];
|
||||||
if ($config['pre_final']) {
|
|
||||||
$result = DB::query("select id, submit_time, submitter, problem_id, result from submissions"
|
$use_final_res = $config['pre_final'] && $contest['extra_config']['basic_rule'] == 'OI';
|
||||||
." where contest_id = {$contest['id']} and score is not null order by id");
|
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
if ($use_final_res) {
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select id, submit_time, submitter, problem_id, result from submissions",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
["score", "is not", null]
|
||||||
|
], "order by id"
|
||||||
|
], DB::NUM);
|
||||||
|
foreach ($res as $row) {
|
||||||
$r = json_decode($row[4], true);
|
$r = json_decode($row[4], true);
|
||||||
if (!isset($r['final_result'])) {
|
if (!isset($r['final_result'])) {
|
||||||
continue;
|
continue;
|
||||||
@ -68,71 +141,233 @@ function queryContestData($contest, $config = array(), $is_after_contest_query =
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($contest['cur_progress'] < CONTEST_FINISHED) {
|
if ($contest['cur_progress'] < CONTEST_FINISHED) {
|
||||||
$result = DB::query("select id, submit_time, submitter, problem_id, score from submissions"
|
$res = DB::selectAll([
|
||||||
." where contest_id = {$contest['id']} and score is not null order by id");
|
"select id, submit_time, submitter, problem_id, score from submissions",
|
||||||
} elseif ($is_after_contest_query == true) {
|
"where", [
|
||||||
$result = DB::query("select id, submit_time, submitter, problem_id, score from submissions order by score");
|
"contest_id" => $contest['id'],
|
||||||
|
["score", "is not", null]
|
||||||
|
], "order by id"
|
||||||
|
], DB::NUM);
|
||||||
|
} elseif ($config['after_contest']) {
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select id, submit_time, submitter, problem_id, score from submissions",
|
||||||
|
"where", [
|
||||||
|
["problem_id", "in", DB::rawtuple($problems)],
|
||||||
|
], "order by score",
|
||||||
|
], DB::NUM);
|
||||||
} else {
|
} else {
|
||||||
$result = DB::query("select submission_id, date_add('{$contest['start_time_str']}', interval penalty second),"
|
$esc_start_time_str = DB::escape($contest['start_time_str']);
|
||||||
." submitter, problem_id, score from contests_submissions where contest_id = {$contest['id']}");
|
$res = DB::selectAll([
|
||||||
|
"select submission_id, date_add('{$esc_start_time_str}', interval penalty second), submitter, problem_id, score from contests_submissions",
|
||||||
|
"where", ["contest_id" => $contest['id']],
|
||||||
|
], DB::NUM);
|
||||||
}
|
}
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
foreach ($res as $row) {
|
||||||
$row[0] = (int)$row[0];
|
$row[0] = (int)$row[0];
|
||||||
$row[3] = $prob_pos[$row[3]];
|
$row[3] = $prob_pos[$row[3]];
|
||||||
$row[4] = (int)$row[4];
|
$row[4] = (int)$row[4];
|
||||||
$data[] = $row;
|
$data[] = $row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $data;
|
||||||
$people = [];
|
|
||||||
$result = DB::query("select a.username, b.realname from contests_registrants a inner join user_info b on a.username = b.username where a.contest_id = {$contest['id']} and a.has_participated = 1");
|
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
|
||||||
$people[] = $row;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['problems' => $problems, 'data' => $data, 'people' => $people];
|
function queryACMContestSubmissionData($contest, $problems, $prob_pos, $config = []) {
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$username_or_empty = Auth::id();
|
||||||
|
if (!isset($username_or_empty)) {
|
||||||
|
$username_or_empty = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function calcStandings($contest, $contest_data, &$score, &$standings, $update_contests_submissions = false, $show_reviews = false) {
|
$actual_score = UOJSubmission::sqlForActualScore();
|
||||||
// score: username, problem_pos => score, penalty, id, ?review
|
$visible_score = 'if(' . DB::land(['hide_score_to_others' => 1, 'submitter' => $username_or_empty]) . ', hidden_score, score)';
|
||||||
$score = array();
|
|
||||||
|
if ($config['pre_final']) {
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select id, submit_time, submitter, problem_id, $actual_score as actual_score, null, null from submissions",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
[$actual_score, "is not", null]
|
||||||
|
], "order by id"
|
||||||
|
], DB::NUM);
|
||||||
|
} else {
|
||||||
|
if ($contest['cur_progress'] < CONTEST_FINISHED) {
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select id, submit_time, submitter, problem_id, $visible_score as visible_score, null, null from submissions",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
DB::lor([
|
||||||
|
[$visible_score, "is not", null],
|
||||||
|
DB::land([
|
||||||
|
"hide_score_to_others" => 1,
|
||||||
|
["submitter", "!=", $username_or_empty]
|
||||||
|
])
|
||||||
|
])
|
||||||
|
], "order by id"
|
||||||
|
], DB::NUM);
|
||||||
|
} else {
|
||||||
|
$esc_start_time_str = DB::escape($contest['start_time_str']);
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select submission_id, date_add('{$esc_start_time_str}', interval penalty second), submitter, problem_id, score, cnt, n_failures from contests_submissions",
|
||||||
|
"where", ["contest_id" => $contest['id']],
|
||||||
|
], DB::NUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($res as $row) {
|
||||||
|
$row[0] = (int)$row[0];
|
||||||
|
$row[3] = $prob_pos[$row[3]];
|
||||||
|
if (isset($row[4])) {
|
||||||
|
$row[4] = (int)$row[4];
|
||||||
|
}
|
||||||
|
if (isset($row[5])) {
|
||||||
|
$row[5] = (int)$row[5];
|
||||||
|
}
|
||||||
|
if (isset($row[6])) {
|
||||||
|
$row[6] = (int)$row[6];
|
||||||
|
}
|
||||||
|
$data[] = $row;
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// standings: rank => score, penalty, [username, realname], virtual_rank
|
||||||
|
function calcStandings($contest, $contest_data, &$score, &$standings, $cfg = []) {
|
||||||
|
$cfg += [
|
||||||
|
'update_contests_submissions' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
// score for OI: username, problem_pos => score, penalty, id
|
||||||
|
// score for ACM: username, problem_pos => score, penalty, id, cnt, n_failures, n_frozen
|
||||||
|
$score = [];
|
||||||
$n_people = count($contest_data['people']);
|
$n_people = count($contest_data['people']);
|
||||||
$n_problems = count($contest_data['problems']);
|
$n_problems = count($contest_data['problems']);
|
||||||
foreach ($contest_data['people'] as $person) {
|
foreach ($contest_data['people'] as $person) {
|
||||||
$score[$person[0]] = array();
|
$score[$person[0]] = [];
|
||||||
}
|
}
|
||||||
foreach ($contest_data['data'] as $submission) {
|
|
||||||
$penalty = (new DateTime($submission[1]))->getTimestamp() - $contest['start_time']->getTimestamp();
|
if ($contest['extra_config']['basic_rule'] === 'OI') {
|
||||||
|
foreach ($contest_data['data'] as $sub) {
|
||||||
|
$penalty = (new DateTime($sub[1]))->getTimestamp() - $contest['start_time']->getTimestamp();
|
||||||
if ($contest['extra_config']['standings_version'] >= 2) {
|
if ($contest['extra_config']['standings_version'] >= 2) {
|
||||||
if ($submission[4] == 0) {
|
if ($sub[4] == 0) {
|
||||||
$penalty = 0;
|
$penalty = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$score[$sub[2]][$sub[3]] = array($sub[4], $penalty, $sub[0]);
|
||||||
$score[$submission[2]][$submission[3]] = array($submission[4], $penalty, $submission[0]);
|
}
|
||||||
|
} else if ($contest['extra_config']['basic_rule'] === 'ACM') {
|
||||||
|
// sub: id, submit_time, submitter, problem_pos, score
|
||||||
|
// id, submit_time (plus penalty), submitter, problem_pos, score, cnt, n_failures
|
||||||
|
foreach ($contest_data['data'] as $sub) {
|
||||||
|
if (!isset($score[$sub[2]][$sub[3]])) {
|
||||||
|
$score[$sub[2]][$sub[3]] = [];
|
||||||
|
}
|
||||||
|
$score[$sub[2]][$sub[3]][] = $sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($show_reviews) {
|
|
||||||
$parsedown = HTML::parsedown();
|
|
||||||
$purifier = HTML::purifier_inline();
|
|
||||||
|
|
||||||
foreach ($contest_data['people'] as $person) {
|
foreach ($contest_data['people'] as $person) {
|
||||||
foreach ($contest_data['problems'] as $key => $problem) {
|
$uname = $person[0];
|
||||||
$review_result = DB::selectFirst("select content from contests_reviews where contest_id = {$contest['id']} and problem_id = {$problem} and poster = '{$person[0]}'");
|
for ($pr = 0; $pr < $n_problems; $pr++) {
|
||||||
|
if (isset($score[$uname][$pr])) {
|
||||||
|
// username, problem_pos => score, penalty, id, cnt, n_failures, n_frozen
|
||||||
|
$final_scr = null;
|
||||||
|
$penalty = 0;
|
||||||
|
$key_sub = null;
|
||||||
|
$cnt = 0;
|
||||||
|
$n_failures = 0;
|
||||||
|
$n_frozen = 0;
|
||||||
|
|
||||||
if (!isset($score[$person[0]][$key])) {
|
if (isset($score[$uname][$pr][0][5])) { // the stored contest data is used
|
||||||
$score[$person[0]][$key] = array(0, 0, 0);
|
$sub = $score[$uname][$pr][0];
|
||||||
|
$final_scr = $sub[4];
|
||||||
|
$penalty = (new DateTime($sub[1]))->getTimestamp() - $contest['start_time']->getTimestamp();
|
||||||
|
$key_sub = $sub;
|
||||||
|
$cnt = $sub[5];
|
||||||
|
$n_failures = $sub[6];
|
||||||
|
$n_frozen = 0;
|
||||||
|
} else {
|
||||||
|
for ($i = 0; $i < count($score[$uname][$pr]); $i++) {
|
||||||
|
$sub = $score[$uname][$pr][$i];
|
||||||
|
$cnt++;
|
||||||
|
if (!isset($sub[4])) {
|
||||||
|
$n_frozen++;
|
||||||
|
} elseif (!isset($final_scr) || $final_scr < $sub[4]) {
|
||||||
|
$final_scr = $sub[4];
|
||||||
|
if ($final_scr == 100) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($review_result['content']) {
|
if (!isset($final_scr)) {
|
||||||
$score[$person[0]][$key][] = $purifier->purify($parsedown->line($review_result['content']));
|
$key_sub = end($score[$uname][$pr]);
|
||||||
|
} else if ($final_scr == 0) {
|
||||||
|
for ($i = 0; $i < count($score[$uname][$pr]); $i++) {
|
||||||
|
$sub = $score[$uname][$pr][$i];
|
||||||
|
if (!isset($sub[4])) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
$n_failures++;
|
||||||
|
$key_sub = $sub;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list($final_scr, $penalty) = calcACMScoreAndPenaltyForOneProblem(
|
||||||
|
$contest,
|
||||||
|
$contest_data['problems'][$pr],
|
||||||
|
$key_sub,
|
||||||
|
$n_failures
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$scr_set = [];
|
||||||
|
for ($i = 0; $i < count($score[$uname][$pr]); $i++) {
|
||||||
|
$sub = $score[$uname][$pr][$i];
|
||||||
|
if ($sub[4] > 0 && $sub[4] != 97 && !isset($scr_set[$sub[4]])) {
|
||||||
|
$scr_set[$sub[4]] = true;
|
||||||
|
} else {
|
||||||
|
$n_failures++;
|
||||||
|
}
|
||||||
|
if ($sub[4] === $final_scr) {
|
||||||
|
$key_sub = $sub;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list($final_scr, $penalty) = calcACMScoreAndPenaltyForOneProblem(
|
||||||
|
$contest,
|
||||||
|
$contest_data['problems'][$pr],
|
||||||
|
$key_sub,
|
||||||
|
$n_failures
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$score[$uname][$pr] = [
|
||||||
|
$final_scr,
|
||||||
|
$penalty,
|
||||||
|
$key_sub[0],
|
||||||
|
$cnt,
|
||||||
|
$n_failures,
|
||||||
|
$n_frozen
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ($contest['extra_config']['basic_rule'] === 'IOI') {
|
||||||
|
foreach ($contest_data['data'] as $sub) {
|
||||||
|
$penalty = (new DateTime($sub[1]))->getTimestamp() - $contest['start_time']->getTimestamp();
|
||||||
|
if ($sub[4] == 0) {
|
||||||
|
$penalty = 0;
|
||||||
|
}
|
||||||
|
if (!isset($score[$sub[2]][$sub[3]]) || $score[$sub[2]][$sub[3]][0] < $sub[4]) {
|
||||||
|
$score[$sub[2]][$sub[3]] = array($sub[4], $penalty, $sub[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// standings: rank => score, penalty, [username, realname], virtual_rank, ?review
|
// standings: rank => score, penalty, [username, realname], virtual_rank, ?review
|
||||||
$standings = array();
|
$standings = [];
|
||||||
foreach ($contest_data['people'] as $person) {
|
foreach ($contest_data['people'] as $person) {
|
||||||
$cur = array(0, 0, $person);
|
$cur = array(0, 0, $person);
|
||||||
for ($i = 0; $i < $n_problems; $i++) {
|
for ($i = 0; $i < $n_problems; $i++) {
|
||||||
@ -140,20 +375,20 @@ function calcStandings($contest, $contest_data, &$score, &$standings, $update_co
|
|||||||
$cur_row = $score[$person[0]][$i];
|
$cur_row = $score[$person[0]][$i];
|
||||||
$cur[0] += $cur_row[0];
|
$cur[0] += $cur_row[0];
|
||||||
$cur[1] += $cur_row[1];
|
$cur[1] += $cur_row[1];
|
||||||
if ($update_contests_submissions) {
|
if ($cfg['update_contests_submissions']) {
|
||||||
DB::insert("replace into contests_submissions (contest_id, submitter, problem_id, submission_id, score, penalty) values ({$contest['id']}, '{$person[0]}', {$contest_data['problems'][$i]}, {$cur_row[2]}, {$cur_row[0]}, {$cur_row[1]})");
|
DB::insert([
|
||||||
|
"replace into contests_submissions",
|
||||||
|
"(contest_id, submitter, problem_id, submission_id, score, penalty, cnt, n_failures)",
|
||||||
|
"values", DB::tuple([
|
||||||
|
$contest['id'], $person[0], $contest_data['problems'][$i], $cur_row[2],
|
||||||
|
$cur_row[0], $cur_row[1],
|
||||||
|
isset($cur_row[3]) ? $cur_row[3] : null,
|
||||||
|
isset($cur_row[4]) ? $cur_row[4] : null
|
||||||
|
])
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($show_reviews) {
|
|
||||||
$review_result = DB::selectFirst("select content from contests_reviews where contest_id = {$contest['id']} and problem_id = -1 and poster = '{$person[0]}'");
|
|
||||||
|
|
||||||
if ($review_result['content']) {
|
|
||||||
$cur[] = $purifier->purify($parsedown->line($review_result['content']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$standings[] = $cur;
|
$standings[] = $cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,19 +408,38 @@ function calcStandings($contest, $contest_data, &$score, &$standings, $update_co
|
|||||||
|
|
||||||
for ($i = 0; $i < $n_people; $i++) {
|
for ($i = 0; $i < $n_people; $i++) {
|
||||||
if ($i == 0 || !$is_same_rank($standings[$i - 1], $standings[$i])) {
|
if ($i == 0 || !$is_same_rank($standings[$i - 1], $standings[$i])) {
|
||||||
if ($show_reviews && count($standings[$i]) == 4) {
|
|
||||||
$standings[$i][] = $standings[$i][3];
|
|
||||||
$standings[$i][3] = $i + 1;
|
|
||||||
} else {
|
|
||||||
$standings[$i][] = $i + 1;
|
$standings[$i][] = $i + 1;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($show_reviews && count($standings[$i]) == 4) {
|
|
||||||
$standings[$i][] = $standings[$i][3];
|
|
||||||
$standings[$i][3] = $standings[$i - 1][3];
|
|
||||||
} else {
|
} else {
|
||||||
$standings[$i][] = $standings[$i - 1][3];
|
$standings[$i][] = $standings[$i - 1][3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calcACMScoreAndPenaltyForOneProblem($contest, $problem_id, $sub, $n_failures) {
|
||||||
|
if (isset($contest['extra_config']['bonus']["problem_{$problem_id}"])) {
|
||||||
|
if ($sub[4] === 100) {
|
||||||
|
return [0, -60 * 20];
|
||||||
|
} else {
|
||||||
|
return [0, 0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$penalty = (new DateTime($sub[1]))->getTimestamp() - $contest['start_time']->getTimestamp();
|
||||||
|
$penalty += $n_failures * 60 * 20;
|
||||||
|
if ($sub[4] === 0) {
|
||||||
|
$penalty = 0;
|
||||||
|
}
|
||||||
|
return [$sub[4], $penalty];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContestBlogLink($contest, $title) {
|
||||||
|
if (!isset($contest['extra_config']['links'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
foreach ($contest['extra_config']['links'] as $link) {
|
||||||
|
if ($link[0] === $title) {
|
||||||
|
return '/blogs/' . $link[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -6,166 +6,301 @@
|
|||||||
mkdir("/var/uoj_data/upload/$id");
|
mkdir("/var/uoj_data/upload/$id");
|
||||||
mkdir("/var/uoj_data/$id");
|
mkdir("/var/uoj_data/$id");
|
||||||
|
|
||||||
exec("cd /var/uoj_data; rm $id.zip; zip $id.zip $id -r -q");
|
UOJLocalRun::execAnd([
|
||||||
}
|
['cd', '/var/uoj_data'],
|
||||||
|
['rm', "$id.zip"],
|
||||||
class UOJProblemConfException extends Exception {
|
['zip', "$id.zip", $id, '-r', '-q']
|
||||||
public function __construct($message) {
|
]);
|
||||||
parent::__construct("<strong>problem.conf</strong> : $message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class UOJFileNotFoundException extends Exception {
|
|
||||||
public function __construct($file_name) {
|
|
||||||
parent::__construct("file <strong>" . htmlspecialchars($file_name) . '</strong> not found');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataClearProblemData($problem) {
|
function dataClearProblemData($problem) {
|
||||||
$id = $problem['id'];
|
$id = $problem['id'];
|
||||||
if (!validateUInt($id)) {
|
if (!validateUInt($id)) {
|
||||||
error_log("dataClearProblemData: hacker detected");
|
UOJLog::error("dataClearProblemData: hacker detected");
|
||||||
return "invalid problem id";
|
return "invalid problem id";
|
||||||
}
|
}
|
||||||
|
|
||||||
exec("rm /var/uoj_data/upload/$id -r");
|
UOJLocalRun::exec(['rm', "/var/uoj_data/$id", '-r']);
|
||||||
exec("rm /var/uoj_data/$id -r");
|
UOJLocalRun::exec(['rm', "/var/uoj_data/upload/$id", '-r']);
|
||||||
dataNewProblem($id);
|
dataNewProblem($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SyncProblemDataHandler {
|
class SyncProblemDataHandler {
|
||||||
private $problem, $user;
|
private UOJProblem $problem;
|
||||||
private $upload_dir, $data_dir, $prepare_dir;
|
private $user;
|
||||||
|
private int $id;
|
||||||
|
private string $upload_dir, $data_dir, $prepare_dir;
|
||||||
private $requirement, $problem_extra_config;
|
private $requirement, $problem_extra_config;
|
||||||
private $problem_conf, $final_problem_conf;
|
private $problem_conf, $final_problem_conf;
|
||||||
private $allow_files;
|
private $allow_files;
|
||||||
|
|
||||||
public function __construct($problem, $user) {
|
public function retryMsg() {
|
||||||
$this->problem = $problem;
|
return '请等待上一次数据上传或同步操作结束后重试';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct($problem_info, $user = null) {
|
||||||
|
$this->problem = new UOJProblem($problem_info);
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
|
|
||||||
|
if (!validateUInt($this->problem->info['id'])) {
|
||||||
|
UOJLog::error("SyncProblemDataHandler: hacker detected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->id = (int)$this->problem->info['id'];
|
||||||
|
|
||||||
|
$this->data_dir = "/var/uoj_data/{$this->id}";
|
||||||
|
$this->prepare_dir = "/var/uoj_data/prepare_{$this->id}";
|
||||||
|
$this->upload_dir = "/var/uoj_data/upload/{$this->id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $type can be either LOCK_SH or LOCK_EX
|
||||||
|
*/
|
||||||
|
private function lock($type, $func) {
|
||||||
|
$ret = FS::lock_file("/var/uoj_data/{$this->id}_lock", $type, $func);
|
||||||
|
return $ret === false ? $this->retryMsg() : $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function check_conf_on($name) {
|
private function check_conf_on($name) {
|
||||||
return isset($this->problem_conf[$name]) && $this->problem_conf[$name] == 'on';
|
return isset($this->problem_conf[$name]) && $this->problem_conf[$name] == 'on';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function create_prepare_folder() {
|
||||||
|
return mkdir($this->prepare_dir, 0755);
|
||||||
|
}
|
||||||
|
private function remove_prepare_folder() {
|
||||||
|
return UOJLocalRun::exec(['rm', $this->prepare_dir, '-rf']);
|
||||||
|
}
|
||||||
|
|
||||||
private function copy_to_prepare($file_name) {
|
private function copy_to_prepare($file_name) {
|
||||||
global $uojMainJudgerWorkPath;
|
|
||||||
if (!isset($this->allow_files[$file_name])) {
|
if (!isset($this->allow_files[$file_name])) {
|
||||||
throw new UOJFileNotFoundException($file_name);
|
throw new UOJFileNotFoundException($file_name);
|
||||||
}
|
}
|
||||||
$src = escapeshellarg("{$this->upload_dir}/$file_name");
|
|
||||||
$dest = escapeshellarg("{$this->prepare_dir}/$file_name");
|
$src = "{$this->upload_dir}/$file_name";
|
||||||
|
$dest = "{$this->prepare_dir}/$file_name";
|
||||||
|
|
||||||
|
if (file_exists($dest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($this->problem_extra_config['dont_use_formatter']) || !is_file("{$this->upload_dir}/$file_name")) {
|
if (isset($this->problem_extra_config['dont_use_formatter']) || !is_file("{$this->upload_dir}/$file_name")) {
|
||||||
exec("cp $src $dest -r", $output, $ret);
|
exec("cp $src $dest -r", $output, $ret);
|
||||||
|
$ret = UOJLocalRun::exec(['cp', $src, $dest, '-r']);
|
||||||
} else {
|
} else {
|
||||||
exec("$uojMainJudgerWorkPath/run/formatter <$src >$dest", $output, $ret);
|
$ret = UOJLocalRun::formatter($src, $dest);
|
||||||
}
|
}
|
||||||
if ($ret) {
|
|
||||||
|
if ($ret === false) {
|
||||||
throw new UOJFileNotFoundException($file_name);
|
throw new UOJFileNotFoundException($file_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function copy_file_to_prepare($file_name) {
|
private function copy_file_to_prepare($file_name) {
|
||||||
global $uojMainJudgerWorkPath;
|
|
||||||
if (!isset($this->allow_files[$file_name]) || !is_file("{$this->upload_dir}/$file_name")) {
|
if (!isset($this->allow_files[$file_name]) || !is_file("{$this->upload_dir}/$file_name")) {
|
||||||
throw new UOJFileNotFoundException($file_name);
|
throw new UOJFileNotFoundException($file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->copy_to_prepare($file_name);
|
$this->copy_to_prepare($file_name);
|
||||||
}
|
}
|
||||||
private function compile_at_prepare($name, $config = array()) {
|
|
||||||
global $uojMainJudgerWorkPath;
|
|
||||||
$include_path = "$uojMainJudgerWorkPath/include";
|
|
||||||
|
|
||||||
if (!isset($config['src'])) {
|
private function copy_source_code_to_prepare($code_name) { // file name without suffix
|
||||||
$config['src'] = "$name.cpp";
|
$src = UOJLang::findSourceCode($code_name, $this->upload_dir);
|
||||||
|
|
||||||
|
if ($src === false) {
|
||||||
|
throw new UOJFileNotFoundException($code_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->copy_to_prepare($src['path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function compile_at_prepare($name, $config = []) {
|
||||||
|
$include_path = UOJLocalRun::$judger_include_path;
|
||||||
|
|
||||||
|
$src = UOJLang::findSourceCode($name, $this->prepare_dir);
|
||||||
|
|
||||||
if (isset($config['path'])) {
|
if (isset($config['path'])) {
|
||||||
exec("mv {$this->prepare_dir}/$name.cpp {$this->prepare_dir}/{$config['path']}/$name.cpp");
|
if (rename("{$this->prepare_dir}/{$src['path']}", "{$this->prepare_dir}/{$config['path']}/{$src['path']}") === false) {
|
||||||
|
throw new Exception("<strong>$name</strong> : move failed");
|
||||||
|
}
|
||||||
$work_path = "{$this->prepare_dir}/{$config['path']}";
|
$work_path = "{$this->prepare_dir}/{$config['path']}";
|
||||||
} else {
|
} else {
|
||||||
$work_path = $this->prepare_dir;
|
$work_path = $this->prepare_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmd_prefix = "$uojMainJudgerWorkPath/run/run_program >{$this->prepare_dir}/run_compiler_result.txt --in=/dev/null --out=stderr --err={$this->prepare_dir}/compiler_result.txt --tl=10 --ml=512 --ol=64 --type=compiler --work-path={$work_path}";
|
$compile_options = [
|
||||||
if (isset($config['need_include_header']) && $config['need_include_header']) {
|
['custom', UOJLocalRun::$judger_run_path]
|
||||||
exec("$cmd_prefix --add-readable-raw=$include_path/ /usr/bin/g++ -o $name {$config['src']} -I$include_path -lm -O2 -DONLINE_JUDGE");
|
];
|
||||||
} else {
|
$runp_options = [
|
||||||
exec("$cmd_prefix /usr/bin/g++ -o $name {$config['src']} -lm -O2 -DONLINE_JUDGE");
|
['in', '/dev/null'],
|
||||||
|
['out', 'stderr'],
|
||||||
|
['err', "{$this->prepare_dir}/compiler_result.txt"],
|
||||||
|
['tl', 60],
|
||||||
|
['ml', 512],
|
||||||
|
['ol', 64],
|
||||||
|
['type', 'compiler'],
|
||||||
|
['work-path', $work_path],
|
||||||
|
];
|
||||||
|
if (!empty($config['need_include_header'])) {
|
||||||
|
$compile_options[] = ['cinclude', $include_path];
|
||||||
|
$runp_options[] = ['add-readable-raw', "{$include_path}/"];
|
||||||
}
|
}
|
||||||
|
if (!empty($config['implementer'])) {
|
||||||
$fp = fopen("{$this->prepare_dir}/run_compiler_result.txt", "r");
|
$compile_options[] = ['impl', $config['implementer']];
|
||||||
if (fscanf($fp, '%d %d %d %d', $rs, $used_time, $used_memory, $exit_code) != 4) {
|
|
||||||
$rs = 7;
|
|
||||||
}
|
}
|
||||||
fclose($fp);
|
$res = UOJLocalRun::compile($name, $compile_options, $runp_options);
|
||||||
|
$this->final_problem_conf["{$name}_run_type"] = UOJLang::getRunTypeFromLanguage($src['lang']);
|
||||||
|
$rstype = isset($res['rstype']) ? $res['rstype'] : 7;
|
||||||
|
|
||||||
unlink("{$this->prepare_dir}/run_compiler_result.txt");
|
if ($rstype != 0 || $res['exit_code'] != 0) {
|
||||||
|
if ($rstype == 0) {
|
||||||
if ($rs != 0 || $exit_code != 0) {
|
throw new Exception("<strong>$name</strong> : compile error<pre>\n" . HTML::escape(uojFilePreview("{$this->prepare_dir}/compiler_result.txt", 10000)) . "\n</pre>");
|
||||||
if ($rs == 0) {
|
} elseif ($rstype == 7) {
|
||||||
throw new Exception("<strong>$name</strong> : compile error<pre>\n" . uojFilePreview("{$this->prepare_dir}/compiler_result.txt", 100) . "\n</pre>");
|
|
||||||
} elseif ($rs == 7) {
|
|
||||||
throw new Exception("<strong>$name</strong> : compile error. No comment");
|
throw new Exception("<strong>$name</strong> : compile error. No comment");
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("<strong>$name</strong> : compile error. Compiler " . judgerCodeStr($rs));
|
throw new Exception("<strong>$name</strong> : compile error. Compiler " . judgerCodeStr($rstype));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink("{$this->prepare_dir}/compiler_result.txt");
|
unlink("{$this->prepare_dir}/compiler_result.txt");
|
||||||
|
|
||||||
if (isset($config['path'])) {
|
if (isset($config['path'])) {
|
||||||
exec("mv {$this->prepare_dir}/{$config['path']}/$name.cpp {$this->prepare_dir}/$name.cpp");
|
rename("{$this->prepare_dir}/{$config['path']}/{$src['path']}", "{$this->prepare_dir}/{$src['path']}");
|
||||||
exec("mv {$this->prepare_dir}/{$config['path']}/$name {$this->prepare_dir}/$name");
|
rename("{$this->prepare_dir}/{$config['path']}/$name", "{$this->prepare_dir}/$name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function makefile_at_prepare() {
|
private function makefile_at_prepare() {
|
||||||
global $uojMainJudgerWorkPath;
|
$include_path = UOJLocalRun::$judger_include_path;
|
||||||
|
|
||||||
$include_path = "$uojMainJudgerWorkPath/include";
|
$res = UOJLocalRun::exec(['/usr/bin/make', "INCLUDE_PATH={$include_path}"], [
|
||||||
$cmd_prefix = "$uojMainJudgerWorkPath/run/run_program >{$this->prepare_dir}/run_makefile_result.txt --in=/dev/null --out=stderr --err={$this->prepare_dir}/makefile_result.txt --tl=10 --ml=512 --ol=64 --type=compiler --work-path={$this->prepare_dir}";
|
['in', '/dev/null'],
|
||||||
exec("$cmd_prefix --add-readable-raw=$include_path/ /usr/bin/make INCLUDE_PATH=$include_path");
|
['out', 'stderr'],
|
||||||
|
['err', "{$this->prepare_dir}/makefile_result.txt"],
|
||||||
|
['tl', 60],
|
||||||
|
['ml', 512],
|
||||||
|
['ol', 64],
|
||||||
|
['type', 'compiler'],
|
||||||
|
['work-path', $this->prepare_dir],
|
||||||
|
['add-readable-raw', "{$include_path}/"]
|
||||||
|
]);
|
||||||
|
$rstype = isset($res['rstype']) ? $res['rstype'] : 7;
|
||||||
|
|
||||||
$fp = fopen("{$this->prepare_dir}/run_makefile_result.txt", "r");
|
if ($rstype != 0 || $res['exit_code'] != 0) {
|
||||||
if (fscanf($fp, '%d %d %d %d', $rs, $used_time, $used_memory, $exit_code) != 4) {
|
if ($rstype == 0) {
|
||||||
$rs = 7;
|
throw new Exception("<strong>Makefile</strong> : compile error<pre>\n" . HTML::escape(uojFilePreview("{$this->prepare_dir}/makefile_result.txt", 10000)) . "\n</pre>");
|
||||||
}
|
} elseif ($rstype == 7) {
|
||||||
fclose($fp);
|
|
||||||
|
|
||||||
unlink("{$this->prepare_dir}/run_makefile_result.txt");
|
|
||||||
|
|
||||||
if ($rs != 0 || $exit_code != 0) {
|
|
||||||
if ($rs == 0) {
|
|
||||||
throw new Exception("<strong>Makefile</strong> : compile error<pre>\n" . uojFilePreview("{$this->prepare_dir}/makefile_result.txt", 100) . "\n</pre>");
|
|
||||||
} elseif ($rs == 7) {
|
|
||||||
throw new Exception("<strong>Makefile</strong> : compile error. No comment");
|
throw new Exception("<strong>Makefile</strong> : compile error. No comment");
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("<strong>Makefile</strong> : compile error. Compiler " . judgerCodeStr($rs));
|
throw new Exception("<strong>Makefile</strong> : compile error. Compiler " . judgerCodeStr($rstype));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink("{$this->prepare_dir}/makefile_result.txt");
|
unlink("{$this->prepare_dir}/makefile_result.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle() {
|
public function _updateProblemConf($new_problem_conf) {
|
||||||
$id = $this->problem['id'];
|
|
||||||
if (!validateUInt($id)) {
|
|
||||||
error_log("dataSyncProblemData: hacker detected");
|
|
||||||
return "invalid problem id";
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->upload_dir = "/var/uoj_data/upload/$id";
|
|
||||||
$this->data_dir = "/var/uoj_data/$id";
|
|
||||||
$this->prepare_dir = "/var/uoj_data/prepare_$id";
|
|
||||||
|
|
||||||
if (file_exists($this->prepare_dir)) {
|
|
||||||
return "please wait until the last sync finish";
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->requirement = array();
|
putUOJConf("{$this->data_dir}/problem.conf", $new_problem_conf);
|
||||||
$this->problem_extra_config = json_decode($this->problem['extra_config'], true);
|
return '';
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function updateProblemConf($new_problem_conf) {
|
||||||
|
return $this->lock(LOCK_EX, fn () => $this->_updateProblemConf($new_problem_conf));
|
||||||
|
}
|
||||||
|
|
||||||
mkdir($this->prepare_dir, 0755);
|
private function _addHackPoint($uploaded_input_file, $uploaded_output_file, $reason) {
|
||||||
|
try {
|
||||||
|
switch ($this->problem->getExtraConfig('add_hack_as')) {
|
||||||
|
case 'test':
|
||||||
|
$key_num = 'n_tests';
|
||||||
|
$msg = 'add new test';
|
||||||
|
$gen_in_name = 'getUOJProblemInputFileName';
|
||||||
|
$gen_out_name = 'getUOJProblemOutputFileName';
|
||||||
|
break;
|
||||||
|
case 'ex_test':
|
||||||
|
$key_num = 'n_ex_tests';
|
||||||
|
$msg = 'add new extra test';
|
||||||
|
$gen_in_name = 'getUOJProblemExtraInputFileName';
|
||||||
|
$gen_out_name = 'getUOJProblemExtraOutputFileName';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 'add hack to data failed: add_hack_as should be either "ex_test" or "test"';
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_problem_conf = $this->problem->getProblemConfArray();
|
||||||
|
if ($new_problem_conf == -1 || $new_problem_conf == -2) {
|
||||||
|
return $new_problem_conf;
|
||||||
|
}
|
||||||
|
$new_problem_conf[$key_num] = getUOJConfVal($new_problem_conf, $key_num, 0) + 1;
|
||||||
|
|
||||||
|
putUOJConf("{$this->upload_dir}/problem.conf", $new_problem_conf);
|
||||||
|
|
||||||
|
$new_input_name = $gen_in_name($new_problem_conf, $new_problem_conf[$key_num]);
|
||||||
|
$new_output_name = $gen_out_name($new_problem_conf, $new_problem_conf[$key_num]);
|
||||||
|
|
||||||
|
if (!copy($uploaded_input_file, "{$this->upload_dir}/$new_input_name")) {
|
||||||
|
return "input file not found";
|
||||||
|
}
|
||||||
|
if (!copy($uploaded_output_file, "{$this->upload_dir}/$new_output_name")) {
|
||||||
|
return "output file not found";
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = $this->_sync();
|
||||||
|
if ($ret !== '') {
|
||||||
|
return "hack successfully but sync failed: $ret";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($reason['hack_url'])) {
|
||||||
|
UOJSystemUpdate::updateProblem($this->problem, [
|
||||||
|
'text' => 'Hack 成功,自动添加数据',
|
||||||
|
'url' => $reason['hack_url']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
UOJSubmission::rejudgeProblemAC($this->problem, [
|
||||||
|
'reason_text' => $reason['rejudge'],
|
||||||
|
'requestor' => ''
|
||||||
|
]);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addHackPoint($uploaded_input_file, $uploaded_output_file, $reason = []) {
|
||||||
|
return $this->lock(LOCK_EX, fn () => $this->_addHackPoint($uploaded_input_file, $uploaded_output_file, $reason));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fast_hackable_check() {
|
||||||
|
if (!$this->problem->info['hackable']) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!$this->check_conf_on('use_builtin_judger')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->check_conf_on('submit_answer')) {
|
||||||
|
throw new UOJProblemConfException("提交答案题不可 Hack,请先停用本题的 Hack 功能。");
|
||||||
|
} else {
|
||||||
|
if (UOJLang::findSourceCode('std', $this->upload_dir) === false) {
|
||||||
|
throw new UOJProblemConfException("找不到本题的 std。请上传 std 代码文件,或停用本题的 Hack 功能。");
|
||||||
|
}
|
||||||
|
if (UOJLang::findSourceCode('val', $this->upload_dir) === false) {
|
||||||
|
throw new UOJProblemConfException("找不到本题的 val。请上传 val 代码文件,或停用本题的 Hack 功能。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _sync() {
|
||||||
|
try {
|
||||||
|
if (!$this->create_prepare_folder()) {
|
||||||
|
throw new UOJSyncFailedException('创建临时文件夹失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->requirement = [];
|
||||||
|
$this->problem_extra_config = $this->problem->getExtraConfig();;
|
||||||
if (!is_file("{$this->upload_dir}/problem.conf")) {
|
if (!is_file("{$this->upload_dir}/problem.conf")) {
|
||||||
throw new UOJFileNotFoundException("problem.conf");
|
throw new UOJFileNotFoundException("problem.conf");
|
||||||
}
|
}
|
||||||
@ -178,9 +313,7 @@
|
|||||||
throw new UOJProblemConfException("syntax error");
|
throw new UOJProblemConfException("syntax error");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->allow_files = array_flip(array_filter(scandir($this->upload_dir), function($x) {
|
$this->allow_files = array_flip(FS::scandir($this->upload_dir));
|
||||||
return $x !== '.' && $x !== '..';
|
|
||||||
}));
|
|
||||||
|
|
||||||
$zip_file = new ZipArchive();
|
$zip_file = new ZipArchive();
|
||||||
if ($zip_file->open("{$this->prepare_dir}/download.zip", ZipArchive::CREATE) !== true) {
|
if ($zip_file->open("{$this->prepare_dir}/download.zip", ZipArchive::CREATE) !== true) {
|
||||||
@ -191,6 +324,12 @@
|
|||||||
$this->copy_to_prepare('require');
|
$this->copy_to_prepare('require');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($this->allow_files['testlib.h']) && is_file("{$this->upload_dir}/testlib.h")) {
|
||||||
|
$this->copy_file_to_prepare('testlib.h');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fast_hackable_check();
|
||||||
|
|
||||||
if ($this->check_conf_on('use_builtin_judger')) {
|
if ($this->check_conf_on('use_builtin_judger')) {
|
||||||
$n_tests = getUOJConfVal($this->problem_conf, 'n_tests', 10);
|
$n_tests = getUOJConfVal($this->problem_conf, 'n_tests', 10);
|
||||||
if (!validateUInt($n_tests) || $n_tests <= 0) {
|
if (!validateUInt($n_tests) || $n_tests <= 0) {
|
||||||
@ -207,33 +346,38 @@
|
|||||||
if (!$this->check_conf_on('interaction_mode')) {
|
if (!$this->check_conf_on('interaction_mode')) {
|
||||||
if (isset($this->problem_conf['use_builtin_checker'])) {
|
if (isset($this->problem_conf['use_builtin_checker'])) {
|
||||||
if (!preg_match('/^[a-zA-Z0-9_]{1,20}$/', $this->problem_conf['use_builtin_checker'])) {
|
if (!preg_match('/^[a-zA-Z0-9_]{1,20}$/', $this->problem_conf['use_builtin_checker'])) {
|
||||||
throw new Exception("<strong>" . htmlspecialchars($this->problem_conf['use_builtin_checker']) . "</strong> is not a valid checker");
|
throw new Exception("<strong>" . HTML::escape($this->problem_conf['use_builtin_checker']) . "</strong> is not a valid checker");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->copy_file_to_prepare('chk.cpp');
|
$this->copy_source_code_to_prepare('chk');
|
||||||
$this->compile_at_prepare('chk', array('need_include_header' => true));
|
$this->compile_at_prepare('chk', ['need_include_header' => true]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->check_conf_on('submit_answer')) {
|
if ($this->check_conf_on('submit_answer')) {
|
||||||
if ($this->problem['hackable']) {
|
if (!isset($this->problem_extra_config['dont_download_input'])) {
|
||||||
throw new UOJProblemConfException("the problem can't be hackable if submit_answer is on");
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($num = 1; $num <= $n_tests; $num++) {
|
for ($num = 1; $num <= $n_tests; $num++) {
|
||||||
$input_file_name = getUOJProblemInputFileName($this->problem_conf, $num);
|
$input_file_name = getUOJProblemInputFileName($this->problem_conf, $num);
|
||||||
$output_file_name = getUOJProblemOutputFileName($this->problem_conf, $num);
|
|
||||||
|
|
||||||
if (!isset($this->problem_extra_config['dont_download_input'])) {
|
|
||||||
$zip_file->addFile("{$this->prepare_dir}/$input_file_name", "$input_file_name");
|
$zip_file->addFile("{$this->prepare_dir}/$input_file_name", "$input_file_name");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->requirement[] = array('name' => "output$num", 'type' => 'text', 'file_name' => $output_file_name);
|
$n_output_files = 0;
|
||||||
|
for ($num = 1; $num <= $n_tests; $num++) {
|
||||||
|
$output_file_id = getUOJConfVal($this->problem_conf, ["output_file_id_{$num}", "output_file_id"], "$num");
|
||||||
|
if (!validateUInt($output_file_id) || $output_file_id < 0 || $output_file_id > $n_tests) {
|
||||||
|
throw new UOJProblemConfException("output_file_id/output_file_id_{$num} must be in [1, n_tests]");
|
||||||
|
}
|
||||||
|
$n_output_files = max($n_output_files, $output_file_id);
|
||||||
|
}
|
||||||
|
for ($num = 1; $num <= $n_output_files; $num++) {
|
||||||
|
$output_file_name = getUOJProblemOutputFileName($this->problem_conf, $num);
|
||||||
|
$this->requirement[] = ['name' => "output$num", 'type' => 'text', 'file_name' => $output_file_name];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$n_ex_tests = getUOJConfVal($this->problem_conf, 'n_ex_tests', 0);
|
$n_ex_tests = getUOJConfVal($this->problem_conf, 'n_ex_tests', 0);
|
||||||
if (!validateUInt($n_ex_tests) || $n_ex_tests < 0) {
|
if (!validateUInt($n_ex_tests) || $n_ex_tests < 0) {
|
||||||
throw new UOJProblemConfException("n_ex_tests must be a non-negative integer");
|
throw new UOJProblemConfException('n_ex_tests must be a non-negative integer. Current value: ' . HTML::escape($n_ex_tests));
|
||||||
}
|
}
|
||||||
|
|
||||||
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
for ($num = 1; $num <= $n_ex_tests; $num++) {
|
||||||
@ -244,30 +388,28 @@
|
|||||||
$this->copy_file_to_prepare($output_file_name);
|
$this->copy_file_to_prepare($output_file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->problem['hackable']) {
|
if ($this->problem->info['hackable']) {
|
||||||
$this->copy_file_to_prepare('std.cpp');
|
$this->copy_source_code_to_prepare('std');
|
||||||
if (isset($this->problem_conf['with_implementer']) && $this->problem_conf['with_implementer'] == 'on') {
|
if (isset($this->problem_conf['with_implementer']) && $this->problem_conf['with_implementer'] == 'on') {
|
||||||
$this->compile_at_prepare('std',
|
$this->compile_at_prepare('std', [
|
||||||
array(
|
'implementer' => 'implementer',
|
||||||
'src' => 'implementer.cpp std.cpp',
|
|
||||||
'path' => 'require'
|
'path' => 'require'
|
||||||
)
|
]);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
$this->compile_at_prepare('std');
|
$this->compile_at_prepare('std');
|
||||||
}
|
}
|
||||||
$this->copy_file_to_prepare('val.cpp');
|
$this->copy_source_code_to_prepare('val');
|
||||||
$this->compile_at_prepare('val', array('need_include_header' => true));
|
$this->compile_at_prepare('val', ['need_include_header' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->check_conf_on('interaction_mode')) {
|
if ($this->check_conf_on('interaction_mode')) {
|
||||||
$this->copy_file_to_prepare('interactor.cpp');
|
$this->copy_source_code_to_prepare('interactor');
|
||||||
$this->compile_at_prepare('interactor', array('need_include_header' => true));
|
$this->compile_at_prepare('interactor', ['need_include_header' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$n_sample_tests = getUOJConfVal($this->problem_conf, 'n_sample_tests', $n_tests);
|
$n_sample_tests = getUOJConfVal($this->problem_conf, 'n_sample_tests', $n_tests);
|
||||||
if (!validateUInt($n_sample_tests) || $n_sample_tests < 0) {
|
if (!validateUInt($n_sample_tests) || $n_sample_tests < 0) {
|
||||||
throw new UOJProblemConfException("n_sample_tests must be a non-negative integer");
|
throw new UOJProblemConfException('n_sample_tests must be a non-negative integer. Current value: ' . HTML::escape($n_sample_tests));
|
||||||
}
|
}
|
||||||
if ($n_sample_tests > $n_ex_tests) {
|
if ($n_sample_tests > $n_ex_tests) {
|
||||||
throw new UOJProblemConfException("n_sample_tests can't be greater than n_ex_tests");
|
throw new UOJProblemConfException("n_sample_tests can't be greater than n_ex_tests");
|
||||||
@ -284,7 +426,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->requirement[] = array('name' => 'answer', 'type' => 'source code', 'file_name' => 'answer.code');
|
$this->requirement[] = ['name' => 'answer', 'type' => 'source code', 'file_name' => 'answer.code'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!isSuperUser($this->user)) {
|
if (!isSuperUser($this->user)) {
|
||||||
@ -295,65 +437,72 @@
|
|||||||
}
|
}
|
||||||
$this->makefile_at_prepare();
|
$this->makefile_at_prepare();
|
||||||
|
|
||||||
$this->requirement[] = array('name' => 'answer', 'type' => 'source code', 'file_name' => 'answer.code');
|
$this->requirement[] = ['name' => 'answer', 'type' => 'source code', 'file_name' => 'answer.code'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
putUOJConf("{$this->prepare_dir}/problem.conf", $this->final_problem_conf);
|
putUOJConf("{$this->prepare_dir}/problem.conf", $this->final_problem_conf);
|
||||||
|
|
||||||
if (isset($this->allow_files['download']) && is_dir("{$this->upload_dir}/download")) {
|
if (isset($this->allow_files['download']) && is_dir("{$this->upload_dir}/download")) {
|
||||||
foreach (scandir("{$this->upload_dir}/download") as $file_name) {
|
$download_dir = "{$this->upload_dir}/download";
|
||||||
if (is_file("{$this->upload_dir}/download/{$file_name}")) {
|
foreach (FS::scandir_r($download_dir) as $file_name) {
|
||||||
$zip_file->addFile("{$this->upload_dir}/download/{$file_name}", $file_name);
|
if (is_file("{$download_dir}/{$file_name}")) {
|
||||||
|
$zip_file->addFile("{$download_dir}/{$file_name}", $file_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$zip_file->close();
|
$zip_file->close();
|
||||||
|
|
||||||
$orig_requirement = json_decode($this->problem['submission_requirement'], true);
|
$orig_requirement = $this->problem->getSubmissionRequirement();
|
||||||
if (!$orig_requirement) {
|
if (!$orig_requirement) {
|
||||||
$esc_requirement = DB::escape(json_encode($this->requirement));
|
DB::update([
|
||||||
DB::update("update problems set submission_requirement = '$esc_requirement' where id = $id");
|
"update problems",
|
||||||
|
"set", ["submission_requirement" => json_encode($this->requirement)],
|
||||||
|
"where", ["id" => $this->id]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UOJSystemUpdate::updateProblemInternally($this->problem, [
|
||||||
|
'text' => 'sync',
|
||||||
|
'requestor' => Auth::check() ? Auth::id() : null
|
||||||
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
exec("rm {$this->prepare_dir} -r");
|
$this->remove_prepare_folder();
|
||||||
return $e->getMessage();
|
return $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
exec("rm {$this->data_dir} -r");
|
UOJLocalRun::exec(['rm', $this->data_dir, '-r']);
|
||||||
rename($this->prepare_dir, $this->data_dir);
|
rename($this->prepare_dir, $this->data_dir);
|
||||||
|
|
||||||
exec("cd /var/uoj_data; rm $id.zip; zip $id.zip $id -r -q");
|
UOJLocalRun::execAnd([
|
||||||
|
['cd', '/var/uoj_data'],
|
||||||
|
['zip', "{$this->id}.next.zip", $this->id, '-r', '-q'],
|
||||||
|
['mv', "{$this->id}.next.zip", "{$this->id}.zip", '-f'],
|
||||||
|
]);
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sync() {
|
||||||
|
return $this->lock(LOCK_EX, fn () => $this->_sync());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dataSyncProblemData($problem, $user = null) {
|
function dataSyncProblemData($problem, $user = null) {
|
||||||
return (new SyncProblemDataHandler($problem, $user))->handle();
|
return (new SyncProblemDataHandler($problem, $user))->sync();
|
||||||
}
|
}
|
||||||
function dataAddExtraTest($problem, $input_file_name, $output_file_name) {
|
|
||||||
$id = $problem['id'];
|
|
||||||
|
|
||||||
$cur_dir = "/var/uoj_data/upload/$id";
|
function dataAddHackPoint($problem, $uploaded_input_file, $uploaded_output_file, $reason = null, $user = null) {
|
||||||
|
if ($reason === null) {
|
||||||
$problem_conf = getUOJConf("{$cur_dir}/problem.conf");
|
if (UOJHack::cur()) {
|
||||||
if ($problem_conf == -1 || $problem_conf == -2) {
|
$reason = [
|
||||||
return $problem_conf;
|
'rejudge' => '自动重测本题所有获得 100 分的提交记录',
|
||||||
}
|
'hack_url' => HTML::url(UOJHack::cur()->getUri())
|
||||||
$problem_conf['n_ex_tests'] = getUOJConfVal($problem_conf, 'n_ex_tests', 0) + 1;
|
];
|
||||||
|
|
||||||
$new_input_name = getUOJProblemExtraInputFileName($problem_conf, $problem_conf['n_ex_tests']);
|
|
||||||
$new_output_name = getUOJProblemExtraOutputFileName($problem_conf, $problem_conf['n_ex_tests']);
|
|
||||||
|
|
||||||
putUOJConf("$cur_dir/problem.conf", $problem_conf);
|
|
||||||
move_uploaded_file($input_file_name, "$cur_dir/$new_input_name");
|
|
||||||
move_uploaded_file($output_file_name, "$cur_dir/$new_output_name");
|
|
||||||
|
|
||||||
if (dataSyncProblemData($problem) === '') {
|
|
||||||
rejudgeProblemAC($problem);
|
|
||||||
} else {
|
} else {
|
||||||
error_log('hack successfully but sync failed.');
|
$reason = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
return (new SyncProblemDataHandler($problem, $user))->addHackPoint($uploaded_input_file, $uploaded_output_file, $reason);
|
||||||
|
}
|
||||||
|
34
web/app/libs/uoj-expection-lib.php
Normal file
34
web/app/libs/uoj-expection-lib.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UOJProblemConfException extends Exception {
|
||||||
|
public function __construct($message) {
|
||||||
|
parent::__construct("<strong>problem.conf</strong> : $message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UOJFileNotFoundException extends Exception {
|
||||||
|
public function __construct($file_name) {
|
||||||
|
parent::__construct("file <strong>" . HTML::escape($file_name) . '</strong> not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UOJSyncFailedException extends Exception {
|
||||||
|
public function __construct($msg) {
|
||||||
|
parent::__construct('同步失败:'.HTML::escape($msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class UOJUploadFailedException extends Exception {
|
||||||
|
public function __construct($msg) {
|
||||||
|
parent::__construct('上传失败:'.HTML::escape($msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UOJInvalidArgumentException extends Exception {
|
||||||
|
public function __construct($msg) {
|
||||||
|
parent::__construct(HTML::escape($msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UOJNotLoginException extends Exception {
|
||||||
|
public function __construct($msg = '未登录') {
|
||||||
|
parent::__construct(HTML::escape($msg));
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
define('SCRIPT_REFRESH_AS_GET', '<script>;window.location = window.location.origin + window.location.pathname + (window.location.search.length ? window.location.search + "&" : "?") + "_refresh_" + (+new Date()) + "=" + (+new Date()) + window.location.hash;</script>');
|
define('SCRIPT_REFRESH_AS_GET', '<script>;window.location = window.location.origin + window.location.pathname + (window.location.search.length ? window.location.search + "&" : "?") + "_refresh_" + (+new Date()) + "=" + (+new Date()) + window.location.hash;</script>');
|
||||||
|
|
||||||
class UOJForm {
|
class UOJBs4Form {
|
||||||
public $form_name;
|
public $form_name;
|
||||||
public $succ_href;
|
public $succ_href;
|
||||||
|
public $back_href = null;
|
||||||
public $no_submit = false;
|
public $no_submit = false;
|
||||||
public $ctrl_enter_submit = false;
|
public $ctrl_enter_submit = false;
|
||||||
public $extra_validator = null;
|
public $extra_validator = null;
|
||||||
@ -15,14 +16,18 @@
|
|||||||
private $vdata = array();
|
private $vdata = array();
|
||||||
private $main_html = '';
|
private $main_html = '';
|
||||||
public $max_post_size = 15728640; // 15M
|
public $max_post_size = 15728640; // 15M
|
||||||
|
public $max_file_size_mb = 10; // 10M
|
||||||
|
|
||||||
public $handle;
|
public $handle;
|
||||||
|
|
||||||
public $submit_button_config = array();
|
public $submit_button_config = [];
|
||||||
|
public $control_label_config = ['class' => 'col-sm-2'];
|
||||||
|
public $input_config = ['class' => 'col-sm-3'];
|
||||||
|
public $textarea_config = ['class' => 'col-sm-10'];
|
||||||
|
|
||||||
public function __construct($form_name) {
|
public function __construct($form_name) {
|
||||||
$this->form_name = $form_name;
|
$this->form_name = $form_name;
|
||||||
$this->succ_href = $_SERVER['REQUEST_URI'];
|
$this->succ_href = UOJContext::requestURI();
|
||||||
$this->handle = function (&$vdata) {
|
$this->handle = function (&$vdata) {
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -31,20 +36,20 @@
|
|||||||
};
|
};
|
||||||
$this->run_at_server_handler["submit-{$this->form_name}"] = function () {
|
$this->run_at_server_handler["submit-{$this->form_name}"] = function () {
|
||||||
if ($this->no_submit) {
|
if ($this->no_submit) {
|
||||||
become404Page();
|
UOJResponse::page404();
|
||||||
}
|
}
|
||||||
foreach ($this->data as $field) {
|
foreach ($this->data as $field) {
|
||||||
if (!isset($field['no_val']) && !isset($_POST[$field['name']])) {
|
if (!isset($field['no_val']) && !isset($_POST[$field['name']])) {
|
||||||
becomeMsgPage('The form is incomplete.');
|
UOJResponse::message('The form is incomplete.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UOJContext::requestMethod() == 'POST') {
|
if (UOJContext::requestMethod() == 'POST') {
|
||||||
$len = UOJContext::contentLength();
|
$len = UOJContext::contentLength();
|
||||||
if ($len === null) {
|
if ($len === null) {
|
||||||
become403Page();
|
UOJResponse::page403();
|
||||||
} elseif ($len > $this->max_post_size) {
|
} elseif ($len > $this->max_post_size) {
|
||||||
becomeMsgPage('The form is too large.');
|
UOJResponse::message('The form is too large.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,13 +61,13 @@
|
|||||||
$esc_err = htmlspecialchars($err);
|
$esc_err = htmlspecialchars($err);
|
||||||
$err_str .= "$name: $esc_err<br />";
|
$err_str .= "$name: $esc_err<br />";
|
||||||
}
|
}
|
||||||
becomeMsgPage($err_str);
|
UOJResponse::message($err_str);
|
||||||
}
|
}
|
||||||
$fun = $this->handle;
|
$fun = $this->handle;
|
||||||
$fun($this->vdata);
|
$fun($this->vdata);
|
||||||
|
|
||||||
if ($this->succ_href !== 'none') {
|
if ($this->succ_href !== 'none') {
|
||||||
header("Location: {$this->succ_href}");
|
redirectTo($this->succ_href);
|
||||||
}
|
}
|
||||||
die();
|
die();
|
||||||
};
|
};
|
||||||
@ -73,18 +78,13 @@
|
|||||||
$this->ajax_submit_js = $js;
|
$this->ajax_submit_js = $js;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function add($name, $html, $validator_php, $validator_js, $no_val = false) {
|
public function add($name, $html, $validator_php, $validator_js) {
|
||||||
$this->main_html .= $html;
|
$this->main_html .= $html;
|
||||||
$data = array(
|
$this->data[] = array(
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'validator_php' => $validator_php,
|
'validator_php' => $validator_php,
|
||||||
'validator_js' => $validator_js);
|
'validator_js' => $validator_js
|
||||||
|
);
|
||||||
if ($no_val) {
|
|
||||||
$data['no_val'] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->data[] = $data;
|
|
||||||
}
|
}
|
||||||
public function appendHTML($html) {
|
public function appendHTML($html) {
|
||||||
$this->main_html .= $html;
|
$this->main_html .= $html;
|
||||||
@ -95,7 +95,8 @@
|
|||||||
$this->data[] = array(
|
$this->data[] = array(
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'validator_js' => 'always_ok',
|
'validator_js' => 'always_ok',
|
||||||
'no_val' => '');
|
'no_val' => ''
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addHidden($name, $default_value, $validator_php, $validator_js) {
|
public function addHidden($name, $default_value, $validator_php, $validator_js) {
|
||||||
@ -109,11 +110,11 @@ EOD;
|
|||||||
public function addInput($name, $type, $label_text, $default_value, $validator_php, $validator_js) {
|
public function addInput($name, $type, $label_text, $default_value, $validator_php, $validator_js) {
|
||||||
$default_value = htmlspecialchars($default_value);
|
$default_value = htmlspecialchars($default_value);
|
||||||
$html = <<<EOD
|
$html = <<<EOD
|
||||||
<div id="div-$name" class="form-group">
|
<div class="form-group" id="div-$name">
|
||||||
<label for="input-$name" class="col-sm-2 control-label">$label_text</label>
|
<label for="input-$name" class="{$this->control_label_config['class']} control-label">$label_text</label>
|
||||||
<div class="col-sm-3">
|
<div class="{$this->input_config['class']}">
|
||||||
<input type="$type" class="form-control" name="$name" id="input-$name" value="$default_value" />
|
<input class="form-control" type="$type" class="form-control" name="$name" id="input-$name" value="$default_value" />
|
||||||
<span class="help-block invalid-feedback" id="help-$name"></span>
|
<span class="help-block" id="help-$name"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
@ -122,10 +123,10 @@ EOD;
|
|||||||
public function addSelect($name, $options, $label_text, $default_value) {
|
public function addSelect($name, $options, $label_text, $default_value) {
|
||||||
$default_value = htmlspecialchars($default_value);
|
$default_value = htmlspecialchars($default_value);
|
||||||
$html = <<<EOD
|
$html = <<<EOD
|
||||||
<div id="div-$name" class="form-group">
|
<div id="div-$name">
|
||||||
<label for="input-$name" class="col-sm-2 control-label">$label_text</label>
|
<label for="input-$name" class="{$this->control_label_config['class']} control-label">$label_text</label>
|
||||||
<div class="col-sm-3">
|
<div class="{$this->input_config['class']}">
|
||||||
<select class="form-control form-select" id="input-$name" name="$name">
|
<select class="form-select" id="input-content" name="$name">
|
||||||
|
|
||||||
EOD;
|
EOD;
|
||||||
foreach ($options as $opt_name => $opt_label) {
|
foreach ($options as $opt_name => $opt_label) {
|
||||||
@ -146,7 +147,9 @@ EOD;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
$this->add($name, $html,
|
$this->add(
|
||||||
|
$name,
|
||||||
|
$html,
|
||||||
function ($opt) use ($options) {
|
function ($opt) use ($options) {
|
||||||
return isset($options[$opt]) ? '' : "无效选项";
|
return isset($options[$opt]) ? '' : "无效选项";
|
||||||
},
|
},
|
||||||
@ -161,9 +164,9 @@ EOD;
|
|||||||
public function addVSelect($name, $options, $label_text, $default_value) {
|
public function addVSelect($name, $options, $label_text, $default_value) {
|
||||||
$default_value = htmlspecialchars($default_value);
|
$default_value = htmlspecialchars($default_value);
|
||||||
$html = <<<EOD
|
$html = <<<EOD
|
||||||
<div id="div-$name" class="mb-3">
|
<div id="div-$name">
|
||||||
<label for="input-$name" class="control-label">$label_text</label>
|
<label for="input-$name" class="form-label">$label_text</label>
|
||||||
<select class="form-control form-select" id="input-{$name}" name="$name">
|
<select class="form-select" id="input-{$name}" name="$name">
|
||||||
|
|
||||||
EOD;
|
EOD;
|
||||||
foreach ($options as $opt_name => $opt_label) {
|
foreach ($options as $opt_name => $opt_label) {
|
||||||
@ -183,7 +186,9 @@ EOD;
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
$this->add($name, $html,
|
$this->add(
|
||||||
|
$name,
|
||||||
|
$html,
|
||||||
function ($opt) use ($options) {
|
function ($opt) use ($options) {
|
||||||
return isset($options[$opt]) ? '' : "无效选项";
|
return isset($options[$opt]) ? '' : "无效选项";
|
||||||
},
|
},
|
||||||
@ -191,38 +196,41 @@ EOD;
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addTextArea($name, $label_text, $default_value, $validator_php, $validator_js, $no_val = false) {
|
public function addTextArea($name, $label_text, $default_value, $validator_php, $validator_js) {
|
||||||
$default_value = htmlspecialchars($default_value);
|
$default_value = htmlspecialchars($default_value);
|
||||||
$this->is_big = true;
|
$this->is_big = true;
|
||||||
$html = <<<EOD
|
$html = <<<EOD
|
||||||
<div id="div-$name" class="form-group">
|
<div id="div-$name" class="form-group">
|
||||||
<label for="input-$name" class="col-sm-2 control-label">$label_text</label>
|
<label for="input-$name" class="{$this->control_label_config['class']} control-label">$label_text</label>
|
||||||
<div class="col-sm-10">
|
<div class="{$this->textarea_config['class']}">
|
||||||
<textarea class="form-control" name="$name" id="input-$name">$default_value</textarea>
|
<textarea class="form-control" name="$name" id="input-$name">$default_value</textarea>
|
||||||
<span class="help-block invalid-feedback" id="help-$name"></span>
|
<span class="invalid-feedback" id="help-$name"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
$this->add($name, $html, $validator_php, $validator_js, $no_val);
|
$this->add($name, $html, $validator_php, $validator_js);
|
||||||
}
|
}
|
||||||
public function addVTextArea($name, $label_text, $default_value, $validator_php, $validator_js, $no_val = false) {
|
public function addVTextArea($name, $label_text, $default_value, $validator_php, $validator_js) {
|
||||||
$default_value = htmlspecialchars($default_value);
|
$default_value = htmlspecialchars($default_value);
|
||||||
$this->is_big = true;
|
$this->is_big = true;
|
||||||
$html = <<<EOD
|
$html = <<<EOD
|
||||||
<div id="div-$name" class="form-group">
|
<div id="div-$name">
|
||||||
<label for="input-$name" class="control-label">$label_text</label>
|
<label for="input-$name" class="form-label">$label_text</label>
|
||||||
<textarea class="form-control" name="$name" id="input-$name">$default_value</textarea>
|
<textarea class="form-control" name="$name" id="input-$name">$default_value</textarea>
|
||||||
<span class="help-block invalid-feedback" id="help-$name"></span>
|
<span class="invalid-feedback" id="help-$name"></span>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
$this->add($name, $html, $validator_php, $validator_js, $no_val);
|
$this->add($name, $html, $validator_php, $validator_js);
|
||||||
}
|
}
|
||||||
public function addCheckBox($name, $label_text, $default_value) {
|
public function addCheckBox($name, $label_text, $default_value) {
|
||||||
$default_value = htmlspecialchars($default_value);
|
$default_value = htmlspecialchars($default_value);
|
||||||
$status = $default_value ? 'checked="checked" ' : '';
|
$status = $default_value ? 'checked="checked" ' : '';
|
||||||
$html = <<<EOD
|
$html = <<<EOD
|
||||||
<div class="checkbox">
|
<div class="form-checkbox">
|
||||||
<label for="input-$name"><input type="checkbox" id="input-$name" name="$name" $status/> $label_text</label>
|
<input class="form-check-input" type="checkbox" id="input-$name" name="$name" $status/>
|
||||||
|
<label class="form-check-label" for="input-$name">
|
||||||
|
$label_text
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
$this->addNoVal($name, $html);
|
$this->addNoVal($name, $html);
|
||||||
@ -254,7 +262,9 @@ EOD;
|
|||||||
$html .= <<<EOD
|
$html .= <<<EOD
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
$this->add($name, $html,
|
$this->add(
|
||||||
|
$name,
|
||||||
|
$html,
|
||||||
function ($opt) use ($options) {
|
function ($opt) use ($options) {
|
||||||
return isset($options[$opt]) ? '' : "无效选项";
|
return isset($options[$opt]) ? '' : "无效选项";
|
||||||
},
|
},
|
||||||
@ -263,7 +273,8 @@ EOD;
|
|||||||
}
|
}
|
||||||
public function addCKEditor($name, $label_text, $default_value, $validator_php, $validator_js) {
|
public function addCKEditor($name, $label_text, $default_value, $validator_php, $validator_js) {
|
||||||
$default_value = htmlspecialchars($default_value);
|
$default_value = htmlspecialchars($default_value);
|
||||||
$GLOBALS['REQUIRE_LIB']['ckeditor'] = '';
|
global $REQUIRE_LIB;
|
||||||
|
$REQUIRE_LIB['ckeditor'] = '';
|
||||||
|
|
||||||
$this->is_big = true;
|
$this->is_big = true;
|
||||||
|
|
||||||
@ -271,76 +282,12 @@ EOD;
|
|||||||
<div id="div-$name">
|
<div id="div-$name">
|
||||||
<label for="input-$name" class="control-label">$label_text</label>
|
<label for="input-$name" class="control-label">$label_text</label>
|
||||||
<textarea class="ckeditor" name="$name" id="input-$name">$default_value</textarea>
|
<textarea class="ckeditor" name="$name" id="input-$name">$default_value</textarea>
|
||||||
<span class="help-block invalid-feedback" id="help-$name"></span>
|
<span class="help-block" id="help-$name"></span>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
$this->add($name, $html, $validator_php, $validator_js);
|
$this->add($name, $html, $validator_php, $validator_js);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addBlogEditor(UOJBlogEditor $editor) {
|
|
||||||
$GLOBALS['REQUIRE_LIB']['blog-editor'] = '';
|
|
||||||
|
|
||||||
$this->is_big = true;
|
|
||||||
|
|
||||||
$name = $editor->name;
|
|
||||||
|
|
||||||
$this->addVInput("{$name}_title", 'text', '标题', $editor->cur_data['title'],
|
|
||||||
function ($title) use ($editor) {
|
|
||||||
return $editor->validateTitle();
|
|
||||||
},
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
$content_md_html = HTML::div_vtextarea("{$name}_content_md", '内容', $editor->cur_data['content_md']);
|
|
||||||
|
|
||||||
$this->add("{$name}_content_md", $content_md_html,
|
|
||||||
function ($content_md) use ($editor) {
|
|
||||||
return $editor->validateContentMd();
|
|
||||||
},
|
|
||||||
'always_ok'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->appendHTML(<<<EOD
|
|
||||||
<script type="text/javascript">blog_editor_init("$name");</script>
|
|
||||||
EOD
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->run_at_server_handler["save-{$name}"] = function() use ($name, $editor) {
|
|
||||||
if ($this->no_submit) {
|
|
||||||
become404Page();
|
|
||||||
}
|
|
||||||
foreach (array("{$name}_title", "{$name}_content_md") as $field_name) {
|
|
||||||
if (!isset($_POST[$field_name])) {
|
|
||||||
becomeMsgPage('The form is incomplete.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
crsf_defend();
|
|
||||||
$errors = $this->validateAtServer();
|
|
||||||
if (!$errors) {
|
|
||||||
$editor->handleSave();
|
|
||||||
}
|
|
||||||
die(json_encode($errors));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public function addSlideEditor($name, $label_text, $default_value, $validator_php, $validator_js) {
|
|
||||||
$GLOBALS['REQUIRE_LIB']['slide-editor'] = '';
|
|
||||||
$default_value = htmlspecialchars($default_value);
|
|
||||||
|
|
||||||
$this->is_big = true;
|
|
||||||
|
|
||||||
$html = <<<EOD
|
|
||||||
<div id="div-$name">
|
|
||||||
<label for="input-$name" class="control-label">$label_text</label>
|
|
||||||
<textarea name="$name" id="input-$name">$default_value</textarea>
|
|
||||||
<span class="help-block invalid-feedback" id="help-$name"></span>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('#input-$name').slide_editor();
|
|
||||||
</script>
|
|
||||||
EOD;
|
|
||||||
$this->add($name, $html, $validator_php, $validator_js);
|
|
||||||
}
|
|
||||||
|
|
||||||
static public function uploadedFileTmpName($name) {
|
static public function uploadedFileTmpName($name) {
|
||||||
if (isset($_FILES[$name]) && is_uploaded_file($_FILES[$name]['tmp_name'])) {
|
if (isset($_FILES[$name]) && is_uploaded_file($_FILES[$name]['tmp_name'])) {
|
||||||
return $_FILES[$name]['tmp_name'];
|
return $_FILES[$name]['tmp_name'];
|
||||||
@ -349,8 +296,10 @@ EOD;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addSourceCodeInput($name, $text, $languages) {
|
public function addSourceCodeInput($name, $text, $languages, $preferred_lang = null) {
|
||||||
$this->add("{$name}_upload_type", '',
|
$this->add(
|
||||||
|
"{$name}_upload_type",
|
||||||
|
'',
|
||||||
function ($type, &$vdata) use ($name) {
|
function ($type, &$vdata) use ($name) {
|
||||||
if ($type == 'editor') {
|
if ($type == 'editor') {
|
||||||
if (!isset($_POST["{$name}_editor"])) {
|
if (!isset($_POST["{$name}_editor"])) {
|
||||||
@ -365,9 +314,11 @@ EOD;
|
|||||||
);
|
);
|
||||||
$this->addNoVal("{$name}_editor", '');
|
$this->addNoVal("{$name}_editor", '');
|
||||||
$this->addNoVal("{$name}_file", '');
|
$this->addNoVal("{$name}_file", '');
|
||||||
$this->add("{$name}_language", '',
|
$this->add(
|
||||||
|
"{$name}_language",
|
||||||
|
'',
|
||||||
function ($lang) use ($languages) {
|
function ($lang) use ($languages) {
|
||||||
if (!in_array($lang, $languages)) {
|
if (!isset($languages[$lang])) {
|
||||||
return '该语言不被支持';
|
return '该语言不被支持';
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
@ -375,21 +326,25 @@ EOD;
|
|||||||
'always_ok'
|
'always_ok'
|
||||||
);
|
);
|
||||||
|
|
||||||
$preferred_language = Cookie::get('uoj_preferred_language');
|
if ($preferred_lang == null || !isset($languages[$preferred_lang])) {
|
||||||
if ($preferred_language == null || !in_array($preferred_language, $languages)) {
|
$preferred_lang = Cookie::get('uoj_preferred_language');
|
||||||
$preferred_language = $languages[0];
|
}
|
||||||
|
if ($preferred_lang == null || !isset($languages[$preferred_lang])) {
|
||||||
|
$preferred_lang = UOJLang::$default_preferred_language;
|
||||||
}
|
}
|
||||||
|
|
||||||
$langs_options_str = '';
|
$langs_options_str = '';
|
||||||
foreach ($languages as $lang) {
|
foreach ($languages as $lang_code => $lang_display) {
|
||||||
$langs_options_str .= "<option";
|
$langs_options_str .= '<option';
|
||||||
if ($lang == $preferred_language) {
|
$langs_options_str .= ' value="' . $lang_code . '"';
|
||||||
|
if ($lang_code == $preferred_lang) {
|
||||||
$langs_options_str .= ' selected="selected"';
|
$langs_options_str .= ' selected="selected"';
|
||||||
}
|
}
|
||||||
$langs_options_str .= ">$lang</option>";
|
$langs_options_str .= ">$lang_display</option>";
|
||||||
}
|
}
|
||||||
$langs_options_json = json_encode($langs_options_str);
|
$langs_options_json = json_encode($langs_options_str);
|
||||||
$this->appendHTML(<<<EOD
|
$this->appendHTML(
|
||||||
|
<<<EOD
|
||||||
<div class="form-group" id="form-group-$name"></div>
|
<div class="form-group" id="form-group-$name"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('#form-group-$name').source_code_form_group('$name', '$text', $langs_options_json);
|
$('#form-group-$name').source_code_form_group('$name', '$text', $langs_options_json);
|
||||||
@ -401,7 +356,9 @@ EOD
|
|||||||
$this->has_file = true;
|
$this->has_file = true;
|
||||||
}
|
}
|
||||||
public function addTextFileInput($name, $text) {
|
public function addTextFileInput($name, $text) {
|
||||||
$this->add("{$name}_upload_type", '',
|
$this->add(
|
||||||
|
"{$name}_upload_type",
|
||||||
|
'',
|
||||||
function ($type, &$vdata) use ($name) {
|
function ($type, &$vdata) use ($name) {
|
||||||
if ($type == 'editor') {
|
if ($type == 'editor') {
|
||||||
if (!isset($_POST["{$name}_editor"])) {
|
if (!isset($_POST["{$name}_editor"])) {
|
||||||
@ -417,7 +374,8 @@ EOD
|
|||||||
$this->addNoVal("{$name}_editor", '');
|
$this->addNoVal("{$name}_editor", '');
|
||||||
$this->addNoVal("{$name}_file", '');
|
$this->addNoVal("{$name}_file", '');
|
||||||
|
|
||||||
$this->appendHTML(<<<EOD
|
$this->appendHTML(
|
||||||
|
<<<EOD
|
||||||
<div class="form-group" id="form-group-$name"></div>
|
<div class="form-group" id="form-group-$name"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$('#form-group-$name').text_file_form_group('$name', '$text');
|
$('#form-group-$name').text_file_form_group('$name', '$text');
|
||||||
@ -434,16 +392,12 @@ EOD
|
|||||||
|
|
||||||
$form_class = "form-horizontal";
|
$form_class = "form-horizontal";
|
||||||
if ($this->submit_button_config['align'] == 'inline') {
|
if ($this->submit_button_config['align'] == 'inline') {
|
||||||
$form_class .= " uoj-form-inline";
|
$form_class .= " uoj-bs4-form-inline";
|
||||||
}
|
}
|
||||||
if ($this->submit_button_config['align'] == 'compressed') {
|
if ($this->submit_button_config['align'] == 'compressed') {
|
||||||
$form_class .= " uoj-form-compressed";
|
$form_class .= " uoj-bs4-form-compressed";
|
||||||
}
|
|
||||||
if (isset($this->submit_button_config['narrow']) && $this->submit_button_config['narrow']) {
|
|
||||||
$form_class .= " uoj-form-narrow";
|
|
||||||
}
|
}
|
||||||
echo '<form action="', $_SERVER['REQUEST_URI'], '" method="post" class="', $form_class, '" id="form-', $this->form_name, '"', $form_entype_str, '>';
|
echo '<form action="', $_SERVER['REQUEST_URI'], '" method="post" class="', $form_class, '" id="form-', $this->form_name, '"', $form_entype_str, '>';
|
||||||
|
|
||||||
echo HTML::hiddenToken();
|
echo HTML::hiddenToken();
|
||||||
echo $this->main_html;
|
echo $this->main_html;
|
||||||
|
|
||||||
@ -455,7 +409,7 @@ EOD
|
|||||||
$this->submit_button_config['text'] = UOJLocale::get('submit');
|
$this->submit_button_config['text'] = UOJLocale::get('submit');
|
||||||
}
|
}
|
||||||
if (!isset($this->submit_button_config['class_str'])) {
|
if (!isset($this->submit_button_config['class_str'])) {
|
||||||
$this->submit_button_config['class_str'] = 'btn btn-secondary';
|
$this->submit_button_config['class_str'] = 'btn btn-secondary mt-2';
|
||||||
}
|
}
|
||||||
if ($this->submit_button_config['align'] == 'offset') {
|
if ($this->submit_button_config['align'] == 'offset') {
|
||||||
echo '<div class="form-group">';
|
echo '<div class="form-group">';
|
||||||
@ -463,7 +417,23 @@ EOD
|
|||||||
} else {
|
} else {
|
||||||
echo '<div class="text-', $this->submit_button_config['align'], '">';
|
echo '<div class="text-', $this->submit_button_config['align'], '">';
|
||||||
}
|
}
|
||||||
echo '<button type="submit" id="button-submit-', $this->form_name, '" name="submit-', $this->form_name, '" value="', $this->form_name, '" class="', (isset($this->submit_button_config['margin_class']) ? $this->submit_button_config['margin_class'] : 'mt-2'), ' ', $this->submit_button_config['class_str'], '">', $this->submit_button_config['text'], '</button>';
|
|
||||||
|
if ($this->back_href !== null) {
|
||||||
|
echo '<div class="btn-toolbar">';
|
||||||
|
}
|
||||||
|
echo HTML::tag('button', [
|
||||||
|
'type' => 'submit', 'id' => "button-submit-{$this->form_name}", 'name' => "submit-{$this->form_name}",
|
||||||
|
'value' => $this->form_name, 'class' => $this->submit_button_config['class_str']
|
||||||
|
], $this->submit_button_config['text']);
|
||||||
|
if ($this->back_href !== null) {
|
||||||
|
echo HTML::tag('a', [
|
||||||
|
'class' => 'btn btn-secondary', 'href' => $this->back_href
|
||||||
|
], '返回');
|
||||||
|
}
|
||||||
|
if ($this->back_href !== null) {
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->submit_button_config['align'] == 'offset') {
|
if ($this->submit_button_config['align'] == 'offset') {
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
}
|
}
|
||||||
@ -504,7 +474,7 @@ EOD;
|
|||||||
if ($field['validator_js'] != null) {
|
if ($field['validator_js'] != null) {
|
||||||
if ($field['validator_js'] != 'always_ok') {
|
if ($field['validator_js'] != 'always_ok') {
|
||||||
echo <<<EOD
|
echo <<<EOD
|
||||||
var ${field['name']}_err = (${field['validator_js']})($('#input-${field['name']}').val());
|
var {$field['name']}_err = ({$field['validator_js']})($('#input-{$field['name']}').val());
|
||||||
|
|
||||||
EOD;
|
EOD;
|
||||||
}
|
}
|
||||||
@ -521,17 +491,16 @@ EOD;
|
|||||||
foreach ($this->data as $field) {
|
foreach ($this->data as $field) {
|
||||||
if ($field['validator_js'] == null) {
|
if ($field['validator_js'] == null) {
|
||||||
echo <<<EOD
|
echo <<<EOD
|
||||||
var ${field['name']}_err = 'Unknown error';
|
var {$field['name']}_err = 'Unknown error';
|
||||||
post_data.${field['name']} = $('#input-${field['name']}').val();
|
post_data.{$field['name']} = $('#input-{$field['name']}').val();
|
||||||
|
|
||||||
EOD;
|
EOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo <<<EOD
|
echo <<<EOD
|
||||||
if (post_data != {}) {
|
|
||||||
post_data['check-{$this->form_name}'] = "";
|
post_data['check-{$this->form_name}'] = "";
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url : '${_SERVER['REQUEST_URI']}',
|
url : '{$_SERVER['REQUEST_URI']}',
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
async : false,
|
async : false,
|
||||||
@ -543,7 +512,7 @@ EOD;
|
|||||||
foreach ($this->data as $field) {
|
foreach ($this->data as $field) {
|
||||||
if ($field['validator_js'] == null) {
|
if ($field['validator_js'] == null) {
|
||||||
echo <<<EOD
|
echo <<<EOD
|
||||||
${field['name']}_err = data.${field['name']};
|
{$field['name']}_err = data.${field['name']};
|
||||||
|
|
||||||
EOD;
|
EOD;
|
||||||
}
|
}
|
||||||
@ -553,12 +522,8 @@ EOD;
|
|||||||
alert(data.extra);
|
alert(data.extra);
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
EOD;
|
|
||||||
echo <<<EOD
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
EOD;
|
EOD;
|
||||||
}
|
}
|
||||||
@ -567,15 +532,18 @@ EOD;
|
|||||||
if ($field['validator_js'] != 'always_ok') {
|
if ($field['validator_js'] != 'always_ok') {
|
||||||
echo <<<EOD
|
echo <<<EOD
|
||||||
if (${field['name']}_err) {
|
if (${field['name']}_err) {
|
||||||
$('#div-${field['name']}').addClass('has-error'); // for bootstrap4
|
$('#div-${field['name']}').addClass('has-validation has-error');
|
||||||
|
$('#div-${field['name']}').addClass('is-invalid');
|
||||||
$('#input-${field['name']}').addClass('is-invalid');
|
$('#input-${field['name']}').addClass('is-invalid');
|
||||||
$('#help-${field['name']}').text(${field['name']}_err);
|
$('#help-${field['name']}').text(${field['name']}_err);
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
$('#div-${field['name']}').removeClass('has-error'); // for bootstrap4
|
$('#div-${field['name']}').removeClass('has-validation has-error');
|
||||||
|
$('#div-${field['name']}').removeClass('is-invalid');
|
||||||
$('#input-${field['name']}').removeClass('is-invalid');
|
$('#input-${field['name']}').removeClass('is-invalid');
|
||||||
$('#help-${field['name']}').text('');
|
$('#help-${field['name']}').text('');
|
||||||
}
|
}
|
||||||
|
|
||||||
EOD;
|
EOD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,14 +563,12 @@ EOD;
|
|||||||
echo <<<EOD
|
echo <<<EOD
|
||||||
$(this).find("input[type='file']").each(function() {
|
$(this).find("input[type='file']").each(function() {
|
||||||
for (var i = 0; i < this.files.length; i++) {
|
for (var i = 0; i < this.files.length; i++) {
|
||||||
if (this.files[i].size > 10 * 1024 * 1024) {
|
if (this.files[i].size > {$this->max_file_size_mb} * 1024 * 1024) {
|
||||||
$('#div-' + $(this).attr('name')).addClass('has-error'); // for bootstrap4
|
$('#div-' + $(this).attr('name')).addClass('has-error');
|
||||||
$('#input-' + $(this).attr('name')).addClass('is-invalid');
|
$('#help-' + $(this).attr('name')).text('文件大小不能超过{$this->max_file_size_mb}M');
|
||||||
$('#help-' + $(this).attr('name')).text('文件大小不能超过10M');
|
|
||||||
ok = false;
|
ok = false;
|
||||||
} else {
|
} else {
|
||||||
$('#div-' + $(this).attr('name')).removeClass('has-error'); // for bootstrap4
|
$('#div-' + $(this).attr('name')).removeClass('has-error');
|
||||||
$('#input-' + $(this).attr('name')).removeClass('is-invalid');
|
|
||||||
$('#help-' + $(this).attr('name')).text('');
|
$('#help-' + $(this).attr('name')).text('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -649,10 +615,18 @@ EOD;
|
|||||||
foreach ($this->data as $field) {
|
foreach ($this->data as $field) {
|
||||||
if (!isset($field['no_val']) && isset($_POST[$field['name']])) {
|
if (!isset($field['no_val']) && isset($_POST[$field['name']])) {
|
||||||
$fun = $field['validator_php'];
|
$fun = $field['validator_php'];
|
||||||
$err = $fun($_POST[$field['name']], $this->vdata);
|
$ret = $fun($_POST[$field['name']], $this->vdata, $field['name']);
|
||||||
|
if (is_array($ret) && isset($ret['error'])) {
|
||||||
|
$err = $ret['error'];
|
||||||
|
} else {
|
||||||
|
$err = $ret;
|
||||||
|
}
|
||||||
if ($err) {
|
if ($err) {
|
||||||
$errors[$field['name']] = $err;
|
$errors[$field['name']] = $err;
|
||||||
}
|
}
|
||||||
|
if (is_array($ret) && isset($ret['store'])) {
|
||||||
|
$this->vdata[$field['name']] = $ret['store'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $errors;
|
return $errors;
|
||||||
@ -668,9 +642,11 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
function newAddDelCmdForm($form_name, $validate, $handle, $final = null) {
|
function newAddDelCmdForm($form_name, $validate, $handle, $final = null) {
|
||||||
$form = new UOJForm($form_name);
|
$form = new UOJBs4Form($form_name);
|
||||||
$form->addVTextArea(
|
$form->addVTextArea(
|
||||||
$form_name . '_cmds', '命令', '',
|
$form_name . '_cmds',
|
||||||
|
'命令',
|
||||||
|
'',
|
||||||
function ($str, &$vdata) use ($validate) {
|
function ($str, &$vdata) use ($validate) {
|
||||||
$cmds = array();
|
$cmds = array();
|
||||||
foreach (explode("\n", $str) as $line_id => $raw_line) {
|
foreach (explode("\n", $str) as $line_id => $raw_line) {
|
||||||
@ -683,7 +659,7 @@ EOD;
|
|||||||
}
|
}
|
||||||
$obj = trim(substr($line, 1));
|
$obj = trim(substr($line, 1));
|
||||||
|
|
||||||
if ($err = $validate($obj)) {
|
if ($err = $validate($obj, $vdata)) {
|
||||||
return '第' . ($line_id + 1) . '行:' . $err;
|
return '第' . ($line_id + 1) . '行:' . $err;
|
||||||
}
|
}
|
||||||
$cmds[] = array('type' => $line[0], 'obj' => $obj);
|
$cmds[] = array('type' => $line[0], 'obj' => $obj);
|
||||||
@ -696,13 +672,13 @@ EOD;
|
|||||||
if (!isset($final)) {
|
if (!isset($final)) {
|
||||||
$form->handle = function (&$vdata) use ($handle) {
|
$form->handle = function (&$vdata) use ($handle) {
|
||||||
foreach ($vdata['cmds'] as $cmd) {
|
foreach ($vdata['cmds'] as $cmd) {
|
||||||
$handle($cmd['type'], $cmd['obj']);
|
$handle($cmd['type'], $cmd['obj'], $vdata);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
$form->handle = function (&$vdata) use ($handle, $final) {
|
$form->handle = function (&$vdata) use ($handle, $final) {
|
||||||
foreach ($vdata['cmds'] as $cmd) {
|
foreach ($vdata['cmds'] as $cmd) {
|
||||||
$handle($cmd['type'], $cmd['obj']);
|
$handle($cmd['type'], $cmd['obj'], $vdata);
|
||||||
}
|
}
|
||||||
$final();
|
$final();
|
||||||
};
|
};
|
||||||
@ -711,10 +687,10 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
function newSubmissionForm($form_name, $requirement, $zip_file_name_gen, $handle) {
|
function newSubmissionForm($form_name, $requirement, $zip_file_name_gen, $handle) {
|
||||||
$form = new UOJForm($form_name);
|
$form = new UOJBs4Form($form_name);
|
||||||
foreach ($requirement as $req) {
|
foreach ($requirement as $req) {
|
||||||
if ($req['type'] == "source code") {
|
if ($req['type'] == "source code") {
|
||||||
$languages = isset($req['languages']) ? $req['languages'] : $GLOBALS['uojSupportedLanguages'];
|
$languages = UOJLang::getAvailableLanguages(isset($req['languages']) ? $req['languages'] : null);
|
||||||
$form->addSourceCodeInput("{$form_name}_{$req['name']}", UOJLocale::get('problems::source code') . ':' . $req['name'], $languages);
|
$form->addSourceCodeInput("{$form_name}_{$req['name']}", UOJLocale::get('problems::source code') . ':' . $req['name'], $languages);
|
||||||
} elseif ($req['type'] == "text") {
|
} elseif ($req['type'] == "text") {
|
||||||
$form->addTextFileInput("{$form_name}_{$req['name']}", UOJLocale::get('problems::text file') . ':' . $req['file_name']);
|
$form->addTextFileInput("{$form_name}_{$req['name']}", UOJLocale::get('problems::text file') . ':' . $req['file_name']);
|
||||||
@ -733,7 +709,7 @@ EOD;
|
|||||||
|
|
||||||
$zip_file = new ZipArchive();
|
$zip_file = new ZipArchive();
|
||||||
if ($zip_file->open(UOJContext::storagePath() . $zip_file_name, ZipArchive::CREATE) !== true) {
|
if ($zip_file->open(UOJContext::storagePath() . $zip_file_name, ZipArchive::CREATE) !== true) {
|
||||||
becomeMsgPage('提交失败');
|
UOJResponse::message('提交失败');
|
||||||
}
|
}
|
||||||
|
|
||||||
$content = array();
|
$content = array();
|
||||||
@ -741,7 +717,7 @@ EOD;
|
|||||||
$content['config'] = array();
|
$content['config'] = array();
|
||||||
foreach ($requirement as $req) {
|
foreach ($requirement as $req) {
|
||||||
if ($req['type'] == "source code") {
|
if ($req['type'] == "source code") {
|
||||||
$content['config'][] = array("{$req['name']}_language", $_POST["{$form_name}_{$req['name']}_language"]);
|
$content['config'][] = ["{$req['name']}_language", $_POST["{$form_name}_{$req['name']}_language"]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -749,7 +725,7 @@ EOD;
|
|||||||
if ($_POST["{$form_name}_{$req['name']}_upload_type"] == 'editor') {
|
if ($_POST["{$form_name}_{$req['name']}_upload_type"] == 'editor') {
|
||||||
$zip_file->addFromString($req['file_name'], $_POST["{$form_name}_{$req['name']}_editor"]);
|
$zip_file->addFromString($req['file_name'], $_POST["{$form_name}_{$req['name']}_editor"]);
|
||||||
} else {
|
} else {
|
||||||
$tmp_name = UOJForm::uploadedFileTmpName("{$form_name}_{$req['name']}_file");
|
$tmp_name = UOJBs4Form::uploadedFileTmpName("{$form_name}_{$req['name']}_file");
|
||||||
if ($tmp_name == null) {
|
if ($tmp_name == null) {
|
||||||
$zip_file->addFromString($req['file_name'], '');
|
$zip_file->addFromString($req['file_name'], '');
|
||||||
} else {
|
} else {
|
||||||
@ -763,7 +739,7 @@ EOD;
|
|||||||
if ($stat['size'] > $max_size * 1024) {
|
if ($stat['size'] > $max_size * 1024) {
|
||||||
$zip_file->close();
|
$zip_file->close();
|
||||||
unlink(UOJContext::storagePath() . $zip_file_name);
|
unlink(UOJContext::storagePath() . $zip_file_name);
|
||||||
becomeMsgPage("源代码长度不能超过 {$max_size}KB。");
|
UOJResponse::message("源代码长度不能超过 {$max_size}KB。");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,11 +753,9 @@ EOD;
|
|||||||
return $form;
|
return $form;
|
||||||
}
|
}
|
||||||
function newZipSubmissionForm($form_name, $requirement, $zip_file_name_gen, $handle) {
|
function newZipSubmissionForm($form_name, $requirement, $zip_file_name_gen, $handle) {
|
||||||
$form = new UOJForm($form_name);
|
$form = new UOJBs4Form($form_name);
|
||||||
$name = "zip_ans_{$form_name}";
|
$name = "zip_ans_{$form_name}";
|
||||||
$text = UOJLocale::get('problems::zip file upload introduction', join(array_map(function($req) {
|
$text = UOJLocale::get('problems::zip file upload introduction', implode(', ', array_map(fn ($req) => $req['file_name'], $requirement)));
|
||||||
return $req['file_name'];
|
|
||||||
}, $requirement), ', '));
|
|
||||||
$browse_text = UOJLocale::get('browse');
|
$browse_text = UOJLocale::get('browse');
|
||||||
$html = <<<EOD
|
$html = <<<EOD
|
||||||
<div id="div-{$name}">
|
<div id="div-{$name}">
|
||||||
@ -869,4 +843,3 @@ EOD;
|
|||||||
function dieWithAlert($str) {
|
function dieWithAlert($str) {
|
||||||
die('<script>alert(decodeURIComponent("' . rawurlencode($str) . '"));</script>' . SCRIPT_REFRESH_AS_GET);
|
die('<script>alert(decodeURIComponent("' . rawurlencode($str) . '"));</script>' . SCRIPT_REFRESH_AS_GET);
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
global $uojSupportedLanguages, $uojMainJudgerWorkPath;
|
|
||||||
$uojSupportedLanguages = array('C', 'C++', 'C++98', 'C++03', 'C++11', 'C++17', 'C++20', 'Pascal', 'Python2.7', 'Python3', 'Java8', 'Java11', 'Java17');
|
|
||||||
$uojMainJudgerWorkPath = "/opt/uoj/judger/uoj_judger";
|
|
||||||
|
|
||||||
function authenticateJudger() {
|
function authenticateJudger() {
|
||||||
if (!is_string($_POST['judger_name']) || !is_string($_POST['password'])) {
|
if (!is_string($_POST['judger_name']) || !is_string($_POST['password'])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$esc_judger_name = DB::escape($_POST['judger_name']);
|
$judger = DB::selectFirst([
|
||||||
$judger = DB::selectFirst("select password from judger_info where judger_name = '$esc_judger_name'");
|
"select password from judger_info",
|
||||||
if ($judger == null) {
|
"where", [
|
||||||
return false;
|
"judger_name" => $_POST['judger_name'],
|
||||||
}
|
"enabled" => true,
|
||||||
return $judger['password'] == $_POST['password'];
|
"password" => $_POST['password']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
return $judger != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function judgerCodeStr($code) {
|
function judgerCodeStr($code) {
|
||||||
@ -38,113 +38,34 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StrictFileReader {
|
/**
|
||||||
private $f;
|
* Better to use UOJProblemConf instead
|
||||||
private $buf = '', $off = 0;
|
*
|
||||||
|
* @return array|int
|
||||||
public function __construct($file_name) {
|
*/
|
||||||
$this->f = fopen($file_name, 'r');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function failed() {
|
|
||||||
return $this->f === false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function readChar() {
|
|
||||||
if (isset($this->buf[$this->off])) {
|
|
||||||
return $this->buf[$this->off++];
|
|
||||||
}
|
|
||||||
return fgetc($this->f);
|
|
||||||
}
|
|
||||||
public function unreadChar($c) {
|
|
||||||
$this->buf .= $c;
|
|
||||||
if ($this->off > 1000) {
|
|
||||||
$this->buf = substr($this->buf, $this->off);
|
|
||||||
$this->off = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function readString() {
|
|
||||||
$str = '';
|
|
||||||
while (true) {
|
|
||||||
$c = $this->readChar();
|
|
||||||
if ($c === false) {
|
|
||||||
break;
|
|
||||||
} elseif ($c === " " || $c === "\n" || $c === "\r") {
|
|
||||||
$this->unreadChar($c);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
$str .= $c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
public function ignoreWhite() {
|
|
||||||
while (true) {
|
|
||||||
$c = $this->readChar();
|
|
||||||
if ($c === false) {
|
|
||||||
break;
|
|
||||||
} elseif ($c === " " || $c === "\n" || $c === "\r") {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
$this->unreadChar($c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function eof() {
|
|
||||||
return feof($this->f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function close() {
|
|
||||||
fclose($this->f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUOJConf($file_name) {
|
function getUOJConf($file_name) {
|
||||||
$reader = new StrictFileReader($file_name);
|
$ret = UOJProblemConf::getFromFile($file_name);
|
||||||
if ($reader->failed()) {
|
if ($ret instanceof UOJProblemConf) {
|
||||||
return -1;
|
return $ret->conf;
|
||||||
}
|
|
||||||
|
|
||||||
$conf = array();
|
|
||||||
while (!$reader->eof()) {
|
|
||||||
$reader->ignoreWhite();
|
|
||||||
$key = $reader->readString();
|
|
||||||
if ($key === '') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$reader->ignoreWhite();
|
|
||||||
$val = $reader->readString();
|
|
||||||
if ($val === '') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($conf[$key])) {
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
$conf[$key] = $val;
|
|
||||||
}
|
|
||||||
$reader->close();
|
|
||||||
return $conf;
|
|
||||||
}
|
|
||||||
function putUOJConf($file_name, $conf) {
|
|
||||||
$f = fopen($file_name, 'w');
|
|
||||||
foreach ($conf as $key => $val) {
|
|
||||||
fwrite($f, "$key $val\n");
|
|
||||||
}
|
|
||||||
fclose($f);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUOJConfVal($conf, $key, $default_val) {
|
|
||||||
if (isset($conf[$key])) {
|
|
||||||
return $conf[$key];
|
|
||||||
} else {
|
} else {
|
||||||
return $default_val;
|
return $ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Better to use UOJProblemConf instead
|
||||||
|
*/
|
||||||
|
function putUOJConf($file_name, $conf) {
|
||||||
|
(new UOJProblemConf($conf))->putToFile($file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Better to use UOJProblemConf instead
|
||||||
|
*/
|
||||||
|
function getUOJConfVal($conf, $key, $default_val) {
|
||||||
|
return (new UOJProblemConf($conf))->getVal($key, $default_val);
|
||||||
|
}
|
||||||
|
|
||||||
function getUOJProblemInputFileName($problem_conf, $num) {
|
function getUOJProblemInputFileName($problem_conf, $num) {
|
||||||
return getUOJConfVal($problem_conf, 'input_pre', 'input') . $num . '.' . getUOJConfVal($problem_conf, 'input_suf', 'txt');
|
return getUOJConfVal($problem_conf, 'input_pre', 'input') . $num . '.' . getUOJConfVal($problem_conf, 'input_suf', 'txt');
|
||||||
}
|
}
|
||||||
@ -158,29 +79,84 @@
|
|||||||
return 'ex_' . getUOJConfVal($problem_conf, 'output_pre', 'output') . $num . '.' . getUOJConfVal($problem_conf, 'output_suf', 'txt');
|
return 'ex_' . getUOJConfVal($problem_conf, 'output_pre', 'output') . $num . '.' . getUOJConfVal($problem_conf, 'output_suf', 'txt');
|
||||||
}
|
}
|
||||||
|
|
||||||
function rejudgeProblem($problem) {
|
|
||||||
DB::query("update submissions set judge_time = NULL , result = '' , score = NULL , status = 'Waiting Rejudge' where problem_id = ${problem['id']}");
|
|
||||||
}
|
|
||||||
function rejudgeProblemAC($problem) {
|
|
||||||
DB::query("update submissions set judge_time = NULL , result = '' , score = NULL , status = 'Waiting Rejudge' where problem_id = ${problem['id']} and score = 100");
|
|
||||||
}
|
|
||||||
function rejudgeProblemGe97($problem) {
|
|
||||||
DB::query("update submissions set judge_time = NULL , result = '' , score = NULL , status = 'Waiting Rejudge' where problem_id = ${problem['id']} and score >= 97");
|
|
||||||
}
|
|
||||||
function rejudgeSubmission($submission) {
|
|
||||||
DB::query("update submissions set judge_time = NULL , result = '' , score = NULL , status = 'Waiting Rejudge' where id = ${submission['id']}");
|
|
||||||
}
|
|
||||||
function updateBestACSubmissions($username, $problem_id) {
|
function updateBestACSubmissions($username, $problem_id) {
|
||||||
$best = DB::selectFirst("select id, used_time, used_memory, tot_size from submissions where submitter = '$username' and problem_id = $problem_id and score = 100 order by used_time, used_memory, tot_size asc limit 1");
|
$update_best = function() use($username, $problem_id) {
|
||||||
$shortest = DB::selectFirst("select id, used_time, used_memory, tot_size from submissions where submitter = '$username' and problem_id = $problem_id and score = 100 order by tot_size, used_time, used_memory asc limit 1");
|
$best = DB::selectFirst([
|
||||||
DB::delete("delete from best_ac_submissions where submitter = '$username' and problem_id = $problem_id");
|
"select id, used_time, used_memory, tot_size from submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => $username,
|
||||||
|
"problem_id" => $problem_id,
|
||||||
|
"score" => 100
|
||||||
|
], "order by used_time, used_memory, tot_size asc limit 1", DB::for_share()
|
||||||
|
]);
|
||||||
if ($best) {
|
if ($best) {
|
||||||
DB::insert("insert into best_ac_submissions (problem_id, submitter, submission_id, used_time, used_memory, tot_size, shortest_id, shortest_used_time, shortest_used_memory, shortest_tot_size) values ($problem_id, '$username', ${best['id']}, ${best['used_time']}, ${best['used_memory']}, ${best['tot_size']}, ${shortest['id']}, ${shortest['used_time']}, ${shortest['used_memory']}, ${shortest['tot_size']})");
|
$shortest = DB::selectFirst([
|
||||||
|
"select id, used_time, used_memory, tot_size from submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => $username,
|
||||||
|
"problem_id" => $problem_id,
|
||||||
|
"score" => 100
|
||||||
|
], "order by tot_size, used_time, used_memory asc limit 1", DB::for_share()
|
||||||
|
]);
|
||||||
|
$keys = [
|
||||||
|
'submission_id', 'used_time', 'used_memory', 'tot_size',
|
||||||
|
'shortest_id', 'shortest_used_time', 'shortest_used_memory', 'shortest_tot_size'
|
||||||
|
];
|
||||||
|
$vals = [
|
||||||
|
$best['id'], $best['used_time'], $best['used_memory'], $best['tot_size'],
|
||||||
|
$shortest['id'], $shortest['used_time'], $shortest['used_memory'], $shortest['tot_size']
|
||||||
|
];
|
||||||
|
$fields_str = '(problem_id, submitter';
|
||||||
|
for ($i = 0; $i < count($keys); $i++) {
|
||||||
|
$fields_str .= ", {$keys[$i]}";
|
||||||
}
|
}
|
||||||
|
$fields_str .= ')';
|
||||||
|
|
||||||
$cnt = DB::selectCount("select count(*) from best_ac_submissions where submitter='$username'");
|
DB::insert([
|
||||||
DB::update("update user_info set ac_num = $cnt where username='$username'");
|
"insert into best_ac_submissions",
|
||||||
|
$fields_str,
|
||||||
DB::update("update problems set ac_num = (select count(*) from submissions where problem_id = problems.id and score = 100), submit_num = (select count(*) from submissions where problem_id = problems.id) where id = $problem_id");
|
"values", DB::tuple(array_merge([$problem_id, $username], $vals)),
|
||||||
|
"on duplicate key update", array_combine($keys, $vals)
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
DB::delete([
|
||||||
|
"delete from best_ac_submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => $username,
|
||||||
|
"problem_id" => $problem_id
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DB::transaction($update_best);
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", [
|
||||||
|
"ac_num" => DB::rawbracket([
|
||||||
|
"select count(*) from best_ac_submissions",
|
||||||
|
"where", ["submitter" => $username]
|
||||||
|
])
|
||||||
|
], "where", ["username" => $username]
|
||||||
|
]);
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update problems",
|
||||||
|
"set", [
|
||||||
|
"ac_num" => DB::rawbracket([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"problem_id" => DB::raw("problems.id"),
|
||||||
|
"score" => 100
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
"submit_num" => DB::rawbracket([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"problem_id" => DB::raw("problems.id")
|
||||||
|
]
|
||||||
|
])
|
||||||
|
], "where", ["id" => $problem_id]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
?>
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
require $_SERVER['DOCUMENT_ROOT'] . '/app/libs/uoj-' . $name . '-lib.php';
|
require $_SERVER['DOCUMENT_ROOT'] . '/app/libs/uoj-' . $name . '-lib.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requirePHPLib('expection');
|
||||||
requirePHPLib('validate');
|
requirePHPLib('validate');
|
||||||
requirePHPLib('query');
|
requirePHPLib('query');
|
||||||
requirePHPLib('rand');
|
requirePHPLib('rand');
|
||||||
@ -27,10 +28,8 @@
|
|||||||
Session::init();
|
Session::init();
|
||||||
UOJTime::init();
|
UOJTime::init();
|
||||||
DB::init();
|
DB::init();
|
||||||
|
|
||||||
|
$myUser = null;
|
||||||
Auth::init();
|
Auth::init();
|
||||||
|
|
||||||
if (isset($_GET['locale'])) {
|
UOJLocale::init();
|
||||||
UOJLocale::setLocale($_GET['locale']);
|
|
||||||
}
|
|
||||||
UOJLocale::requireModule('basic');
|
|
||||||
?>
|
|
||||||
|
@ -12,31 +12,6 @@ function hasProblemPermission($user, $problem) {
|
|||||||
}
|
}
|
||||||
return DB::selectFirst("select * from problems_permissions where username = '{$user['username']}' and problem_id = {$problem['id']}") != null;
|
return DB::selectFirst("select * from problems_permissions where username = '{$user['username']}' and problem_id = {$problem['id']}") != null;
|
||||||
}
|
}
|
||||||
function hasViewPermission($str, $user, $problem, $submission) {
|
|
||||||
if ($str == 'ALL') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($str == 'ALL_AFTER_AC') {
|
|
||||||
return hasAC($user,$problem);
|
|
||||||
}
|
|
||||||
if ($str == 'SELF') {
|
|
||||||
return $submission['submitter'] == $user['username'];
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasViewSolutionPermission($str, $user, $problem) {
|
|
||||||
if (isSuperUser($user) || isProblemManager($user)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($str == 'ALL') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($str == 'ALL_AFTER_AC') {
|
|
||||||
return hasAC($user, $problem);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function hasContestPermission($user, $contest) {
|
function hasContestPermission($user, $contest) {
|
||||||
if ($user == null) {
|
if ($user == null) {
|
||||||
@ -51,14 +26,6 @@ function hasContestPermission($user, $contest) {
|
|||||||
function hasRegistered($user, $contest) {
|
function hasRegistered($user, $contest) {
|
||||||
return DB::selectFirst("select * from contests_registrants where username = '${user['username']}' and contest_id = ${contest['id']}") != null;
|
return DB::selectFirst("select * from contests_registrants where username = '${user['username']}' and contest_id = ${contest['id']}") != null;
|
||||||
}
|
}
|
||||||
function hasAC($user, $problem) {
|
|
||||||
return DB::selectFirst("select * from best_ac_submissions where submitter = '${user['username']}' and problem_id = ${problem['id']}") != null;
|
|
||||||
}
|
|
||||||
function hasParticipated($user, $contest) {
|
|
||||||
$result = DB::selectFirst("select * from contests_registrants where username = '${user['username']}' and contest_id = ${contest['id']}");
|
|
||||||
|
|
||||||
return $result != null && $result['has_participated'];
|
|
||||||
}
|
|
||||||
|
|
||||||
function queryUser($username) {
|
function queryUser($username) {
|
||||||
if (!validateUsername($username)) {
|
if (!validateUsername($username)) {
|
||||||
@ -66,9 +33,6 @@ function queryUser($username) {
|
|||||||
}
|
}
|
||||||
return DB::selectFirst("select * from user_info where username='$username'", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from user_info where username='$username'", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
function queryProblemContent($id) {
|
|
||||||
return DB::selectFirst("select * from problems_contents where id = $id", MYSQLI_ASSOC);
|
|
||||||
}
|
|
||||||
function queryProblemBrief($id) {
|
function queryProblemBrief($id) {
|
||||||
return DB::selectFirst("select * from problems where id = $id", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from problems where id = $id", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
@ -108,27 +72,15 @@ function queryContestProblemRank($contest, $problem) {
|
|||||||
if (!DB::selectFirst("select * from contests_problems where contest_id = {$contest['id']} and problem_id = {$problem['id']}")) {
|
if (!DB::selectFirst("select * from contests_problems where contest_id = {$contest['id']} and problem_id = {$problem['id']}")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$contest_problems = DB::selectAll("select problem_id from contests_problems where contest_id = {$contest['id']} order by dfn, problem_id");
|
$contest_problems = DB::selectAll("select problem_id from contests_problems where contest_id = {$contest['id']} order by level, problem_id");
|
||||||
return array_search(array('problem_id' => $problem['id']), $contest_problems) + 1;
|
return array_search(array('problem_id' => $problem['id']), $contest_problems) + 1;
|
||||||
}
|
}
|
||||||
function querySubmission($id) {
|
|
||||||
return DB::selectFirst("select * from submissions where id = $id", MYSQLI_ASSOC);
|
|
||||||
}
|
|
||||||
function queryHack($id) {
|
|
||||||
return DB::selectFirst("select * from hacks where id = $id", MYSQLI_ASSOC);
|
|
||||||
}
|
|
||||||
function queryContest($id) {
|
function queryContest($id) {
|
||||||
return DB::selectFirst("select * from contests where id = $id", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from contests where id = $id", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
function queryContestProblem($id) {
|
|
||||||
return DB::selectFirst("select * from contest_problems where contest_id = $id", MYSQLI_ASSOC);
|
|
||||||
}
|
|
||||||
function queryContestProblems($id) {
|
|
||||||
return DB::selectAll("select * from contests_problems where contest_id = $id order by dfn, problem_id", MYSQLI_ASSOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
function queryGroup($id) {
|
function queryGroup($id) {
|
||||||
return DB::selectFirst("select * from groups where id = $id", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from `groups` where id = $id", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
function queryGroupUsers($id) {
|
function queryGroupUsers($id) {
|
||||||
return DB::selectAll("SELECT * FROM groups_users WHERE group_id = $id");
|
return DB::selectAll("SELECT * FROM groups_users WHERE group_id = $id");
|
||||||
@ -137,10 +89,23 @@ function queryUserInGroup($group_id, $username) {
|
|||||||
return DB::selectFirst("select * from groups_users where username='$username' and group_id='$group_id'", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from groups_users where username='$username' and group_id='$group_id'", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
function queryGroupsOfUser($username) {
|
function queryGroupsOfUser($username) {
|
||||||
return DB::selectAll("select b.title as title, b.id as id from groups_users a inner join groups b on a.group_id = b.id where a.username = '$username' and b.is_hidden = 0 order by id", MYSQLI_ASSOC);
|
return DB::selectAll([
|
||||||
|
"select", DB::fields([
|
||||||
|
"title" => "groups.title",
|
||||||
|
"id" => "groups.id",
|
||||||
|
]),
|
||||||
|
"from groups_users",
|
||||||
|
"inner join `groups`", "on", [
|
||||||
|
"groups_users.group_id" => DB::raw("groups.id"),
|
||||||
|
],
|
||||||
|
"where", [
|
||||||
|
"groups_users.username" => $username,
|
||||||
|
"groups.is_hidden" => false,
|
||||||
|
],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
function queryGroupmateCurrentAC($username) {
|
function queryGroupmateCurrentAC($username) {
|
||||||
return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, c.group_id as group_id, c.group_name as group_name, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join (select a.username as username, any_value(a.group_id) as group_id, any_value(c.title) as group_name from groups_users a inner join (select a.group_id as group_id from groups_users a inner join groups b on a.group_id = b.id where a.username = '$username' and b.is_hidden = 0) b on a.group_id = b.group_id inner join groups c on a.group_id = c.id group by a.username) c on a.submitter = c.username inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on a.submitter = e.username where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC);
|
return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, c.group_id as group_id, c.group_name as group_name, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join (select a.username as username, any_value(a.group_id) as group_id, any_value(c.title) as group_name from groups_users a inner join (select a.group_id as group_id from groups_users a inner join `groups` b on a.group_id = b.id where a.username = '$username' and b.is_hidden = 0) b on a.group_id = b.group_id inner join `groups` c on a.group_id = c.id group by a.username) c on a.submitter = c.username inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on a.submitter = e.username where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
function queryGroupCurrentAC($group_id) {
|
function queryGroupCurrentAC($group_id) {
|
||||||
return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join groups_users c on (a.submitter = c.username and c.group_id = $group_id) inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on (a.submitter = e.username) where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC);
|
return DB::selectAll("select a.problem_id as problem_id, a.submitter as submitter, a.submission_id as submission_id, b.submit_time as submit_time, d.title as problem_title, b.submit_time as submit_time, e.realname as realname from best_ac_submissions a inner join submissions b on (a.submission_id = b.id) inner join groups_users c on (a.submitter = c.username and c.group_id = $group_id) inner join problems d on (a.problem_id = d.id and d.is_hidden = 0) inner join user_info e on (a.submitter = e.username) where b.submit_time > addtime(now(), '-360:00:00') order by b.submit_time desc limit 10", MYSQLI_ASSOC);
|
||||||
@ -154,30 +119,9 @@ function queryGroupActiveAssignments($group_id) {
|
|||||||
function queryAssignmentByGroupListID($group_id, $list_id) {
|
function queryAssignmentByGroupListID($group_id, $list_id) {
|
||||||
return DB::selectFirst("select * from groups_assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from groups_assignments where list_id='$list_id' and group_id='$group_id'", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
|
|
||||||
function queryZanVal($id, $type, $user) {
|
|
||||||
if ($user == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
$esc_type = DB::escape($type);
|
|
||||||
$row = DB::selectFirst("select val from click_zans where username='{$user['username']}' and type='$esc_type' and target_id='$id'");
|
|
||||||
if ($row == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return $row['val'];
|
|
||||||
}
|
|
||||||
|
|
||||||
function queryBlog($id) {
|
function queryBlog($id) {
|
||||||
return DB::selectFirst("select * from blogs where id='$id'", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from blogs where id='$id'", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
function queryBlogTags($id) {
|
|
||||||
$tags = array();
|
|
||||||
$result = DB::select("select tag from blogs_tags where blog_id = $id order by id");
|
|
||||||
while ($row = DB::fetch($result, MYSQLI_NUM)) {
|
|
||||||
$tags[] = $row[0];
|
|
||||||
}
|
|
||||||
return $tags;
|
|
||||||
}
|
|
||||||
function queryBlogComment($id) {
|
function queryBlogComment($id) {
|
||||||
return DB::selectFirst("select * from blogs_comments where id='$id'", MYSQLI_ASSOC);
|
return DB::selectFirst("select * from blogs_comments where id='$id'", MYSQLI_ASSOC);
|
||||||
}
|
}
|
||||||
@ -188,92 +132,21 @@ function isProblemVisibleToUser($problem, $user) {
|
|||||||
function isListVisibleToUser($list, $user) {
|
function isListVisibleToUser($list, $user) {
|
||||||
return !$list['is_hidden'] || isSuperUser($user);
|
return !$list['is_hidden'] || isSuperUser($user);
|
||||||
}
|
}
|
||||||
function isContestProblemVisibleToUser($problem, $contest, $user) {
|
|
||||||
if (isProblemVisibleToUser($problem, $user)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($contest['cur_progress'] >= CONTEST_PENDING_FINAL_TEST) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ($contest['cur_progress'] == CONTEST_NOT_STARTED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return hasRegistered($user, $contest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSubmissionVisibleToUser($submission, $problem, $user) {
|
|
||||||
if (isProblemManager($user)) {
|
|
||||||
return true;
|
|
||||||
} elseif (!$submission['is_hidden']) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return hasProblemPermission($user, $problem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function isHackVisibleToUser($hack, $problem, $user) {
|
|
||||||
if (isSuperUser($user)) {
|
|
||||||
return true;
|
|
||||||
} elseif (!$hack['is_hidden']) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return hasProblemPermission($user, $problem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSubmissionFullVisibleToUser($submission, $contest, $problem, $user) {
|
|
||||||
if (isSuperUser($user)) {
|
|
||||||
return true;
|
|
||||||
} elseif ($submission['submitter'] == $user['username']) {
|
|
||||||
return true;
|
|
||||||
} elseif (isRegisteredRunningContestProblem($user, $problem)) {
|
|
||||||
return false;
|
|
||||||
} elseif (!$contest) {
|
|
||||||
return true;
|
|
||||||
} elseif ($contest['cur_progress'] > CONTEST_IN_PROGRESS) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return hasProblemPermission($user, $problem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function isHackFullVisibleToUser($hack, $contest, $problem, $user) {
|
|
||||||
if (isSuperUser($user)) {
|
|
||||||
return true;
|
|
||||||
} elseif (!$contest) {
|
|
||||||
return true;
|
|
||||||
} elseif ($contest['cur_progress'] > CONTEST_IN_PROGRESS) {
|
|
||||||
return true;
|
|
||||||
} elseif ($hack['hacker'] == $user['username']) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return hasProblemPermission($user, $problem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRegisteredRunningContestProblem($user, $problem) {
|
function isRegisteredRunningContestProblem($user, $problem) {
|
||||||
$result = DB::query("select contest_id from contests_problems where problem_id = {$problem['id']}");
|
$result = DB::query("select contest_id from contests_problems where problem_id = {$problem['id']}");
|
||||||
while (list($contest_id) = DB::fetch($result, MYSQLI_NUM)) {
|
while (list($contest_id) = DB::fetch($result, MYSQLI_NUM)) {
|
||||||
$contest = queryContest($contest_id);
|
$contest = queryContest($contest_id);
|
||||||
genMoreContestInfo($contest);
|
genMoreContestInfo($contest);
|
||||||
if ($contest['cur_progress'] == CONTEST_IN_PROGRESS
|
if (
|
||||||
|
$contest['cur_progress'] == CONTEST_IN_PROGRESS
|
||||||
&& hasRegistered($user, $contest)
|
&& hasRegistered($user, $contest)
|
||||||
&& !hasContestPermission($user, $contest)
|
&& !hasContestPermission($user, $contest)
|
||||||
&& queryContestProblemRank($contest, $problem)) {
|
&& queryContestProblemRank($contest, $problem)
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteBlog($id) {
|
|
||||||
if (!validateUInt($id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DB::delete("delete from click_zans where type = 'B' and target_id = $id");
|
|
||||||
DB::delete("delete from click_zans where type = 'BC' and target_id in (select id from blogs_comments where blog_id = $id)");
|
|
||||||
DB::delete("delete from blogs where id = $id");
|
|
||||||
DB::delete("delete from blogs_comments where blog_id = $id");
|
|
||||||
DB::delete("delete from important_blogs where blog_id = $id");
|
|
||||||
DB::delete("delete from blogs_tags where blog_id = $id");
|
|
||||||
DB::delete("DELETE FROM problems_solutions WHERE blog_id = $id");
|
|
||||||
}
|
|
||||||
|
@ -28,6 +28,68 @@ function crsf_check() {
|
|||||||
}
|
}
|
||||||
function crsf_defend() {
|
function crsf_defend() {
|
||||||
if (!crsf_check()) {
|
if (!crsf_check()) {
|
||||||
becomeMsgPage('This page has expired.');
|
UOJResponse::page403('页面已过期(可能页面真的过期了,也可能是刚才你访问的网页没有完全加载,也可能是你的浏览器版本太老)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function submission_frequency_check() {
|
||||||
|
$recent = clone UOJTime::$time_now;
|
||||||
|
$recent->sub(new DateInterval("PT1S"));
|
||||||
|
$num = DB::selectCount([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => Auth::id(),
|
||||||
|
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if ($num >= 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the implementation below if OJ is under attack
|
||||||
|
/*
|
||||||
|
// 1
|
||||||
|
$recent = clone UOJTime::$time_now;
|
||||||
|
$recent->sub(new DateInterval("PT3S"));
|
||||||
|
$num = DB::selectCount([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => Auth::id(),
|
||||||
|
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if ($num >= 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2
|
||||||
|
$recent = clone UOJTime::$time_now;
|
||||||
|
$recent->sub(new DateInterval("PT1M"));
|
||||||
|
$num = DB::selectCount([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => Auth::id(),
|
||||||
|
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if ($num >= 6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3
|
||||||
|
$recent = clone UOJTime::$time_now;
|
||||||
|
$recent->sub(new DateInterval("PT30M"));
|
||||||
|
$num = DB::selectCount([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"submitter" => Auth::id(),
|
||||||
|
["submit_time", ">=", $recent->format('Y-m-d H:i:s')]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if ($num >= 30) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -10,6 +10,18 @@ function mergeConfig(&$config, $default_config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_assoc($arr) {
|
||||||
|
if (!is_array($arr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (array_keys($arr) as $key) {
|
||||||
|
if (!is_int($key)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function strStartWith($str, $pre) {
|
function strStartWith($str, $pre) {
|
||||||
return substr($str, 0, strlen($pre)) === $pre;
|
return substr($str, 0, strlen($pre)) === $pre;
|
||||||
}
|
}
|
||||||
@ -129,6 +141,15 @@ function blog_name_decode($name) {
|
|||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function camelize($str, $delimiters = '-_') {
|
||||||
|
$str = ucwords($str, $delimiters);
|
||||||
|
foreach (str_split($delimiters) as $c) {
|
||||||
|
$str = str_replace($c, '', $str);
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
function addUserType(&$user, $type) {
|
function addUserType(&$user, $type) {
|
||||||
$usertype = explode(',', $user['usertype']);
|
$usertype = explode(',', $user['usertype']);
|
||||||
if (!in_array($type, $usertype)) {
|
if (!in_array($type, $usertype)) {
|
||||||
@ -150,9 +171,6 @@ function hasUserType($user, $type) {
|
|||||||
return in_array($type, $usertype);
|
return in_array($type, $usertype);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNormalUser($user) {
|
|
||||||
return $user != null && !hasUserType($user, 'contest_only');
|
|
||||||
}
|
|
||||||
function isProblemUploader($user) {
|
function isProblemUploader($user) {
|
||||||
if ($user == null) {
|
if ($user == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -178,6 +196,9 @@ function isContestJudger($user) {
|
|||||||
function isSuperUser($user) {
|
function isSuperUser($user) {
|
||||||
return $user != null && $user['usergroup'] == 'S';
|
return $user != null && $user['usergroup'] == 'S';
|
||||||
}
|
}
|
||||||
|
function isTmpUser($user) {
|
||||||
|
return $user != null && $user['usergroup'] == 'T';
|
||||||
|
}
|
||||||
function getProblemExtraConfig($problem) {
|
function getProblemExtraConfig($problem) {
|
||||||
$extra_config = json_decode($problem['extra_config'], true);
|
$extra_config = json_decode($problem['extra_config'], true);
|
||||||
|
|
||||||
@ -223,7 +244,20 @@ function getProblemCustomTestRequirement($problem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendSystemMsg($username, $title, $content) {
|
function sendSystemMsg($username, $title, $content) {
|
||||||
$content = DB::escape($content);
|
DB::insert([
|
||||||
$title = DB::escape($title);
|
"insert into user_system_msg",
|
||||||
DB::insert("insert into user_system_msg (receiver, title, content, send_time) values ('$username', '$title', '$content', now())");
|
"(receiver, title, content, send_time)",
|
||||||
|
"values", DB::tuple([$username, $title, $content, DB::now()])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function retry_loop(callable $f, $retry = 5, $ms = 10) {
|
||||||
|
for ($i = 0; $i < $retry; $i++) {
|
||||||
|
$ret = $f();
|
||||||
|
if ($ret !== false) {
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
usleep($ms * 1000);
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
|
@ -59,3 +59,19 @@ function validateString($str) {
|
|||||||
function validateGitHubUsername($username) {
|
function validateGitHubUsername($username) {
|
||||||
return is_string($username) && preg_match('/^[a-zA-Z0-9_-]{1,20}$/', $username);
|
return is_string($username) && preg_match('/^[a-zA-Z0-9_-]{1,20}$/', $username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateUserAndStoreByUsername($username, &$vdata) {
|
||||||
|
if (!isset($vdata['user'])) {
|
||||||
|
$vdata['user'] = [];
|
||||||
|
}
|
||||||
|
$user = UOJUser::query($username);
|
||||||
|
if (!$user) {
|
||||||
|
return "不存在名为{$username}的用户";
|
||||||
|
}
|
||||||
|
$vdata['user'][$username] = $user;
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_short_string($str) {
|
||||||
|
return is_string($str) && strlen($str) <= 256;
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ return [
|
|||||||
'in progress' => 'in progress',
|
'in progress' => 'in progress',
|
||||||
'pending final test' => 'pending final test',
|
'pending final test' => 'pending final test',
|
||||||
'final testing' => 'final testing',
|
'final testing' => 'final testing',
|
||||||
|
'official results to be announced' => 'official results to be announced',
|
||||||
'ended' => 'ended',
|
'ended' => 'ended',
|
||||||
'total score' => 'total score',
|
'total score' => 'total score',
|
||||||
'add new contest' => 'Add new contest',
|
'add new contest' => 'Add new contest',
|
||||||
@ -23,10 +24,11 @@ return [
|
|||||||
'after contest standings' => 'After contest standings',
|
'after contest standings' => 'After contest standings',
|
||||||
'contest backstage' => 'Backstage',
|
'contest backstage' => 'Backstage',
|
||||||
'contest notice' => 'Notice',
|
'contest notice' => 'Notice',
|
||||||
'show all submissions' => 'Show all submissions',
|
'show all submissions' => "Show everyone's submissions",
|
||||||
'contest ends in' => 'Contest ends in',
|
'contest ends in' => 'Contest ends in',
|
||||||
'contest pending final test' => 'Pending final test',
|
'contest pending final test' => 'Pending final test',
|
||||||
'contest final testing' => 'Final testing',
|
'contest final testing' => 'Final testing',
|
||||||
|
'contest official results to be announced' => 'Official results to be announced',
|
||||||
'contest ended' => 'Contest Ended',
|
'contest ended' => 'Contest Ended',
|
||||||
'contest registrants' => 'Registrants',
|
'contest registrants' => 'Registrants',
|
||||||
'problem self review' => 'Problem self review',
|
'problem self review' => 'Problem self review',
|
||||||
|
@ -14,6 +14,7 @@ return [
|
|||||||
'in progress' => '正在进行',
|
'in progress' => '正在进行',
|
||||||
'pending final test' => '等待评测',
|
'pending final test' => '等待评测',
|
||||||
'final testing' => '正在评测',
|
'final testing' => '正在评测',
|
||||||
|
'official results to be announced' => '等待宣布正式成绩',
|
||||||
'ended' => '已结束',
|
'ended' => '已结束',
|
||||||
'total score' => '总分',
|
'total score' => '总分',
|
||||||
'add new contest' => '添加比赛',
|
'add new contest' => '添加比赛',
|
||||||
@ -23,10 +24,11 @@ return [
|
|||||||
'after contest standings' => '赛后排行榜',
|
'after contest standings' => '赛后排行榜',
|
||||||
'contest backstage' => '大后台',
|
'contest backstage' => '大后台',
|
||||||
'contest notice' => '比赛通知',
|
'contest notice' => '比赛通知',
|
||||||
'show all submissions' => '显示所有提交',
|
'show all submissions' => '显示所有人的提交',
|
||||||
'contest ends in' => '距离比赛结束',
|
'contest ends in' => '距离比赛结束',
|
||||||
'contest pending final test' => '等待评测',
|
'contest pending final test' => '等待评测',
|
||||||
'contest final testing' => '正在测评',
|
'contest final testing' => '正在测评',
|
||||||
|
'contest official results to be announced' => '等待宣布正式成绩',
|
||||||
'contest ended' => '比赛已结束',
|
'contest ended' => '比赛已结束',
|
||||||
'contest registrants' => '报名选手列表',
|
'contest registrants' => '报名选手列表',
|
||||||
'problem self review' => '题目总结',
|
'problem self review' => '题目总结',
|
||||||
|
@ -3,26 +3,43 @@
|
|||||||
class Auth {
|
class Auth {
|
||||||
public static function check() {
|
public static function check() {
|
||||||
global $myUser;
|
global $myUser;
|
||||||
return $myUser != null;
|
return $myUser !== null;
|
||||||
}
|
}
|
||||||
public static function id() {
|
public static function id() {
|
||||||
global $myUser;
|
global $myUser;
|
||||||
|
if ($myUser === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return $myUser['username'];
|
return $myUser['username'];
|
||||||
}
|
}
|
||||||
public static function user() {
|
public static function user() {
|
||||||
global $myUser;
|
global $myUser;
|
||||||
return $myUser;
|
return $myUser;
|
||||||
}
|
}
|
||||||
|
public static function property($name) {
|
||||||
|
global $myUser;
|
||||||
|
if (!$myUser) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $myUser[$name];
|
||||||
|
}
|
||||||
public static function login($username, $remember = true) {
|
public static function login($username, $remember = true) {
|
||||||
if (!validateUsername($username)) {
|
if (!validateUsername($username)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$_SESSION['username'] = $username;
|
$_SESSION['username'] = $username;
|
||||||
if ($remember) {
|
if ($remember) {
|
||||||
$remember_token = DB::selectFirst("select remember_token from user_info where username = '$username'")['remember_token'];
|
$remember_token = DB::selectSingle([
|
||||||
|
"select remember_token from user_info",
|
||||||
|
"where", ["username" => $username]
|
||||||
|
]);
|
||||||
if ($remember_token == '') {
|
if ($remember_token == '') {
|
||||||
$remember_token = uojRandString(60);
|
$remember_token = uojRandString(60);
|
||||||
DB::update("update user_info set remember_token = '$remember_token', last_login = now() where username = '$username'");
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", ["remember_token" => $remember_token],
|
||||||
|
"where", ["username" => $username]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$_SESSION['last_login'] = time();
|
$_SESSION['last_login'] = time();
|
||||||
@ -30,6 +47,12 @@ class Auth {
|
|||||||
Cookie::safeSet('uoj_username', $username, $expire, '/', array('httponly' => true));
|
Cookie::safeSet('uoj_username', $username, $expire, '/', array('httponly' => true));
|
||||||
Cookie::safeSet('uoj_remember_token', $remember_token, $expire, '/', array('httponly' => true));
|
Cookie::safeSet('uoj_remember_token', $remember_token, $expire, '/', array('httponly' => true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", ["last_login_time" => UOJTime::$time_now_str],
|
||||||
|
"where", ["username" => $username]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
public static function logout() {
|
public static function logout() {
|
||||||
unset($_SESSION['username']);
|
unset($_SESSION['username']);
|
||||||
@ -37,7 +60,11 @@ class Auth {
|
|||||||
unset($_SESSION['last_visited']);
|
unset($_SESSION['last_visited']);
|
||||||
Cookie::safeUnset('uoj_username', '/');
|
Cookie::safeUnset('uoj_username', '/');
|
||||||
Cookie::safeUnset('uoj_remember_token', '/');
|
Cookie::safeUnset('uoj_remember_token', '/');
|
||||||
DB::update("update user_info set remember_token = '' where username = '".Auth::id()."'");
|
DB::update([
|
||||||
|
"update user_info",
|
||||||
|
"set", ["remember_token" => ''],
|
||||||
|
"where", ["username" => Auth::id()]
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function initMyUser() {
|
private static function initMyUser() {
|
||||||
@ -51,7 +78,7 @@ class Auth {
|
|||||||
if (!validateUsername($_SESSION['username'])) {
|
if (!validateUsername($_SESSION['username'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$myUser = queryUser($_SESSION['username']);
|
$myUser = UOJUser::query($_SESSION['username']);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +88,7 @@ class Auth {
|
|||||||
if (!validateUsername($username)) {
|
if (!validateUsername($username)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$myUser = queryUser($username);
|
$myUser = UOJUser::query($username);
|
||||||
if ($myUser['remember_token'] !== $remember_token) {
|
if ($myUser['remember_token'] !== $remember_token) {
|
||||||
$myUser = null;
|
$myUser = null;
|
||||||
}
|
}
|
||||||
@ -72,24 +99,19 @@ class Auth {
|
|||||||
global $myUser;
|
global $myUser;
|
||||||
|
|
||||||
Auth::initMyUser();
|
Auth::initMyUser();
|
||||||
|
if ($myUser && UOJUser::getAccountStatus($myUser) != 'ok') {
|
||||||
if ($myUser) {
|
|
||||||
if ($myUser['usergroup'] == 'B') {
|
|
||||||
$myUser = null;
|
$myUser = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($myUser) {
|
if ($myUser) {
|
||||||
if (!isset($_SESSION['last_login'])) {
|
if (!isset($_SESSION['last_login'])) {
|
||||||
$_SESSION['last_login'] = strtotime($myUser['last_login']);
|
$_SESSION['last_login'] = strtotime($myUser['last_login_time']);
|
||||||
}
|
}
|
||||||
if ((time() - $_SESSION['last_login']) > 60 * 60 * 24 * 7) { // 1 week
|
$myUser = UOJUser::updateVisitHistory($myUser, [
|
||||||
Auth::logout();
|
'remote_addr' => UOJContext::remoteAddr(),
|
||||||
$myUser = null;
|
'http_x_forwarded_for' => UOJContext::httpXForwardedFor(),
|
||||||
}
|
'http_user_agent' => UOJContext::httpUserAgent()
|
||||||
|
]);
|
||||||
$_SESSION["last_visited"] = time();
|
$_SESSION['last_visited'] = time();
|
||||||
DB::update("update user_info set remote_addr = '".DB::escape($_SERVER['REMOTE_ADDR'])."', http_x_forwarded_for = '".DB::escape($_SERVER['HTTP_X_FORWARDED_FOR'])."', last_visited = now() where username = '".DB::escape($myUser['username'])."'");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
121
web/app/models/ClickZans.php
Normal file
121
web/app/models/ClickZans.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class ClickZans {
|
||||||
|
public static function getTable($type) {
|
||||||
|
switch ($type) {
|
||||||
|
case 'B':
|
||||||
|
return 'blogs';
|
||||||
|
case 'BC':
|
||||||
|
return 'blogs_comments';
|
||||||
|
case 'P':
|
||||||
|
return 'problems';
|
||||||
|
case 'C':
|
||||||
|
return 'contests';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function canClickZan($id, $type, $user) {
|
||||||
|
switch ($type) {
|
||||||
|
case 'P':
|
||||||
|
return UOJProblem::query($id)->userCanClickZan($user);
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function query($id, $type, $user) {
|
||||||
|
if ($user == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$row = DB::selectFirst([
|
||||||
|
"select val from click_zans",
|
||||||
|
"where", [
|
||||||
|
'username' => $user['username'],
|
||||||
|
'type' => $type,
|
||||||
|
'target_id' => $id
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
if ($row == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return $row['val'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function click($id, $type, $user, $delta, $show_text = true) {
|
||||||
|
if (!DB::$in_transaction) {
|
||||||
|
return DB::transaction(fn() => ClickZans::click($id, $type, $user, $delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
$table_name = ClickZans::getTable($type);
|
||||||
|
|
||||||
|
$cur = ClickZans::query($id, $type, $user);
|
||||||
|
|
||||||
|
$row = DB::selectFirst([
|
||||||
|
"select zan from", DB::table($table_name),
|
||||||
|
"where", ['id' => $id], DB::for_update()
|
||||||
|
]);
|
||||||
|
if (!$row) {
|
||||||
|
return '<div class="text-danger">failed</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($cur != $delta) {
|
||||||
|
$cur += $delta;
|
||||||
|
if ($cur == 0) {
|
||||||
|
DB::delete([
|
||||||
|
"delete from click_zans",
|
||||||
|
"where", [
|
||||||
|
'username' => Auth::id(),
|
||||||
|
'type' => $type,
|
||||||
|
'target_id' => $id
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} elseif ($cur != $delta) {
|
||||||
|
DB::update([
|
||||||
|
"update click_zans",
|
||||||
|
"set", ['val' => $cur],
|
||||||
|
"where", [
|
||||||
|
'username' => Auth::id(),
|
||||||
|
'type' => $type,
|
||||||
|
'target_id' => $id
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
DB::insert([
|
||||||
|
"insert into click_zans",
|
||||||
|
"(username, type, target_id, val)", "values",
|
||||||
|
DB::tuple([Auth::id(), $type, $id, $cur])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$cnt = $row['zan'] + $delta;
|
||||||
|
DB::update([
|
||||||
|
"update", DB::table($table_name),
|
||||||
|
"set", ['zan' => $cnt],
|
||||||
|
"where", ['id' => $id]
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$cnt = $row['zan'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClickZans::getBlock($type, $id, $cnt, $cur, $show_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getBlock($type, $id, $cnt, $val = null, $show_text = true) {
|
||||||
|
if ($val === null) {
|
||||||
|
$val = ClickZans::query($id, $type, Auth::user());
|
||||||
|
}
|
||||||
|
return '<div class="uoj-click-zan-block" data-id="'.$id.'" data-type="'.$type.'" data-val="'.$val.'" data-cnt="'.$cnt.'" data-show-text="'.$show_text.'"></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getCntBlock($cnt) {
|
||||||
|
$cls = 'uoj-click-zan-block-';
|
||||||
|
if ($cnt > 0) {
|
||||||
|
$cls .= 'positive';
|
||||||
|
} elseif ($cnt < 0) {
|
||||||
|
$cls .= 'negative';
|
||||||
|
} else {
|
||||||
|
$cls .= 'neutral';
|
||||||
|
}
|
||||||
|
return '<span class="'.$cls.'"><span class="uoj-click-zan-cnt">[<strong>' . ($cnt > 0 ? '+' . $cnt : $cnt) . '</strong>]</span></span>';
|
||||||
|
}
|
||||||
|
}
|
@ -1,78 +1,451 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class DB {
|
class DB {
|
||||||
|
public static mysqli $conn;
|
||||||
|
public static array $cache = [];
|
||||||
|
public static bool $in_transaction = false;
|
||||||
|
|
||||||
|
const WLOCK = "WRITE";
|
||||||
|
const RLOCK = "READ";
|
||||||
|
|
||||||
|
const ASSOC = MYSQLI_ASSOC;
|
||||||
|
const NUM = MYSQLI_NUM;
|
||||||
|
const BOTH = MYSQLI_BOTH;
|
||||||
|
|
||||||
public static function init() {
|
public static function init() {
|
||||||
global $uojMySQL;
|
$server = UOJConfig::$data['database']['host'];
|
||||||
@$uojMySQL = mysqli_connect(UOJConfig::$data['database']['host'] . ':' . UOJConfig::$data['database']['port'], UOJConfig::$data['database']['username'], UOJConfig::$data['database']['password'], UOJConfig::$data['database']['database']);
|
$username = UOJConfig::$data['database']['username'];
|
||||||
if (!$uojMySQL) {
|
$password = UOJConfig::$data['database']['password'];
|
||||||
echo 'There is something wrong with database >_<.... ' . mysqli_connect_error();
|
$dbname = UOJConfig::$data['database']['database'];
|
||||||
die();
|
DB::$conn = new mysqli($server, $username, $password, $dbname);
|
||||||
|
if (DB::$conn->connect_error) {
|
||||||
|
UOJLog::error('database initialization failed: '. DB::$conn->connect_error);
|
||||||
|
die('There is something wrong with the database >_<... Connection failed');
|
||||||
|
}
|
||||||
|
if (!DB::$conn->set_charset("utf8mb4")) {
|
||||||
|
UOJLog::error("database initialization failed: Error loading character set utf8. " . DB::$conn->error);
|
||||||
|
die('There is something wrong with the database >_<.... Charset utf8 not supported');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lc: local cache
|
||||||
|
public static function lc() {
|
||||||
|
return new DBUseLocalCache('');
|
||||||
|
}
|
||||||
|
|
||||||
public static function escape($str) {
|
public static function escape($str) {
|
||||||
global $uojMySQL;
|
return DB::$conn->real_escape_string($str);
|
||||||
return mysqli_real_escape_string($uojMySQL, $str);
|
|
||||||
}
|
}
|
||||||
public static function fetch($r, $opt = MYSQLI_ASSOC) {
|
public static function raw($str) {
|
||||||
global $uojMySQL;
|
return new DBRawString($str);
|
||||||
return mysqli_fetch_array($r, $opt);
|
}
|
||||||
|
public static function rawbracket($q) {
|
||||||
|
return DB::raw(DB::bracket($q));
|
||||||
|
}
|
||||||
|
public static function rawvalue($str) {
|
||||||
|
return DB::raw(DB::value($str));
|
||||||
|
}
|
||||||
|
public static function rawtuple(array $vals) {
|
||||||
|
return DB::raw(DB::tuple($vals));
|
||||||
|
}
|
||||||
|
public static function call($fun, ...$args) {
|
||||||
|
return DB::raw("{$fun}(".implode(',', array_map('DB::value', $args)).')');
|
||||||
|
}
|
||||||
|
public static function now() {
|
||||||
|
return DB::call('now');
|
||||||
|
}
|
||||||
|
public static function instr($str, $substr) {
|
||||||
|
return DB::call('instr', $str, $substr);
|
||||||
|
}
|
||||||
|
public static function cast_as_json($value) {
|
||||||
|
return DB::raw('cast('.DB::value($value).' as json)');
|
||||||
|
}
|
||||||
|
public static function json_set($json_doc, ...$args) {
|
||||||
|
return DB::call('json_set', DB::raw($json_doc), ...$args);
|
||||||
|
}
|
||||||
|
public static function json_insert($json_doc, ...$args) {
|
||||||
|
return DB::call('json_insert', DB::raw($json_doc), ...$args);
|
||||||
|
}
|
||||||
|
public static function json_replace($json_doc, ...$args) {
|
||||||
|
return DB::call('json_replace', DB::raw($json_doc), ...$args);
|
||||||
|
}
|
||||||
|
public static function json_remove($json_doc, ...$args) {
|
||||||
|
return DB::call('json_remove', DB::raw($json_doc), ...$args);
|
||||||
|
}
|
||||||
|
public static function json_array_append($json_doc, ...$args) {
|
||||||
|
return DB::call('json_array_append', DB::raw($json_doc), ...$args);
|
||||||
|
}
|
||||||
|
public static function json_array_insert($json_doc, ...$args) {
|
||||||
|
return DB::call('json_array_insert', DB::raw($json_doc), ...$args);
|
||||||
|
}
|
||||||
|
public static function json_unquote($json_doc) {
|
||||||
|
return DB::call('json_unquote', DB::raw($json_doc));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table($table) {
|
||||||
|
//return '`'.str_replace('`', '``', $table).'`';
|
||||||
|
return $table;
|
||||||
|
}
|
||||||
|
public static function fields($fields) {
|
||||||
|
if (is_assoc($fields)) {
|
||||||
|
$new_fields = [];
|
||||||
|
foreach ($fields as $name => $val) {
|
||||||
|
if (is_int($name)) {
|
||||||
|
$new_fields[] = $val;
|
||||||
|
} else {
|
||||||
|
$new_fields[] = DB::field_as($val, $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$fields = $new_fields;
|
||||||
|
}
|
||||||
|
return implode(',', $fields);
|
||||||
|
}
|
||||||
|
public static function bracketed_fields($fields) {
|
||||||
|
return '('.DB::fields($fields).')';
|
||||||
|
}
|
||||||
|
public static function value($str) {
|
||||||
|
if ($str === null) {
|
||||||
|
return 'NULL';
|
||||||
|
} elseif ($str === true) {
|
||||||
|
return 'true';
|
||||||
|
} elseif ($str === false) {
|
||||||
|
return 'false';
|
||||||
|
} elseif (is_int($str)) {
|
||||||
|
return $str;
|
||||||
|
} elseif (is_string($str)) {
|
||||||
|
return '\''.DB::escape($str).'\'';
|
||||||
|
} elseif ($str instanceof DBRawString) {
|
||||||
|
return $str->str;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static function field_as($field, $name) {
|
||||||
|
return "{$field} as {$name}";
|
||||||
|
}
|
||||||
|
public static function value_as($value, $name) {
|
||||||
|
return DB::value($value)."as {$name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function if_func($conds, $val1, $val2) {
|
||||||
|
return 'if('.DB::conds($conds).','.DB::value($val1).','.DB::value($val2).')';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setValue($field, $val) {
|
||||||
|
return $field.' = '.DB::value($val);
|
||||||
|
}
|
||||||
|
public static function setValues(array $arr) {
|
||||||
|
$all = [];
|
||||||
|
foreach ($arr as $key => $val) {
|
||||||
|
if (is_int($key)) {
|
||||||
|
$all[] = $val;
|
||||||
|
} else {
|
||||||
|
$all[] = DB::setValue($key, $val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return implode(', ', $all);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cond($cond) {
|
||||||
|
if (is_array($cond)) {
|
||||||
|
if (count($cond) == 3) {
|
||||||
|
$lhs = $cond[0] instanceof DBRawString ? $cond[0]->str : $cond[0];
|
||||||
|
$op = $cond[1];
|
||||||
|
$rhs = DB::value($cond[2]);
|
||||||
|
return $lhs.' '.$op.' '.$rhs;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $cond;
|
||||||
|
}
|
||||||
|
public static function conds($conds) {
|
||||||
|
return is_array($conds) ? DB::land($conds) : $conds;
|
||||||
|
}
|
||||||
|
public static function land(array $conds) {
|
||||||
|
if (is_assoc($conds)) {
|
||||||
|
$new_conds = [];
|
||||||
|
foreach ($conds as $key => $val) {
|
||||||
|
if (is_int($key)) {
|
||||||
|
$new_conds[] = $val;
|
||||||
|
} else {
|
||||||
|
if ($val !== null) {
|
||||||
|
$new_conds[] = [$key, '=', $val];
|
||||||
|
} else {
|
||||||
|
$new_conds[] = [$key, 'is', $val];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$conds = $new_conds;
|
||||||
|
}
|
||||||
|
return '('.implode(' and ', array_map('DB::cond', $conds)).')';
|
||||||
|
}
|
||||||
|
public static function lor(array $conds) {
|
||||||
|
if (is_assoc($conds)) {
|
||||||
|
$new_conds = [];
|
||||||
|
foreach ($conds as $key => $val) {
|
||||||
|
if (is_int($key)) {
|
||||||
|
$new_conds[] = $val;
|
||||||
|
} else {
|
||||||
|
if ($val !== null) {
|
||||||
|
$new_conds[] = [$key, '=', $val];
|
||||||
|
} else {
|
||||||
|
$new_conds[] = [$key, 'is', $val];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$conds = $new_conds;
|
||||||
|
}
|
||||||
|
return '('.implode(' or ', array_map('DB::cond', $conds)).')';
|
||||||
|
}
|
||||||
|
public static function tuple(array $vals) {
|
||||||
|
$str = '(';
|
||||||
|
$first = true;
|
||||||
|
foreach ($vals as $val) {
|
||||||
|
if (!$first) {
|
||||||
|
$str .= ',';
|
||||||
|
} else {
|
||||||
|
$first = false;
|
||||||
|
}
|
||||||
|
$str .= DB::value($val);
|
||||||
|
}
|
||||||
|
$str .= ')';
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
public static function tuples(array $tuples) {
|
||||||
|
$all = [];
|
||||||
|
foreach ($tuples as $vals) {
|
||||||
|
$all[] = DB::tuple($vals);
|
||||||
|
}
|
||||||
|
return implode(', ', $all);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fetch($res, $opt = DB::ASSOC) {
|
||||||
|
return $res->fetch_array($opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function bracket($q) {
|
||||||
|
return '('.DB::query_str($q).')';
|
||||||
|
}
|
||||||
|
public static function query_str($q) {
|
||||||
|
if (is_array($q)) {
|
||||||
|
$last = '';
|
||||||
|
$qn = 0;
|
||||||
|
$use_local_cache = false;
|
||||||
|
foreach ($q as $val) {
|
||||||
|
if (is_array($val)) {
|
||||||
|
if ($last !== 'set' && $last !== "on duplicate key update") {
|
||||||
|
$val = DB::land($val);
|
||||||
|
} else {
|
||||||
|
$val = DB::setValues($val);
|
||||||
|
}
|
||||||
|
} elseif ($val instanceof DBUseLocalCache) {
|
||||||
|
$use_local_cache = true;
|
||||||
|
$val = $val->str;
|
||||||
|
}
|
||||||
|
$last = $val;
|
||||||
|
if ($val !== '') {
|
||||||
|
$q[$qn++] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array_splice($q, $qn);
|
||||||
|
$q = implode(' ', $q);
|
||||||
|
if ($use_local_cache) {
|
||||||
|
$q = new DBUseLocalCache($q);
|
||||||
|
}
|
||||||
|
return $q;
|
||||||
|
}
|
||||||
|
return $q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function exists($q) {
|
||||||
|
return 'exists '.DB::bracket($q);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function query($q) {
|
public static function query($q) {
|
||||||
global $uojMySQL;
|
return DB::$conn->query(DB::query_str($q));
|
||||||
return mysqli_query($uojMySQL, $q);
|
|
||||||
}
|
}
|
||||||
public static function update($q) {
|
public static function update($q) {
|
||||||
global $uojMySQL;
|
$ret = DB::$conn->query(DB::query_str($q));
|
||||||
return mysqli_query($uojMySQL, $q);
|
if ($ret === false) {
|
||||||
|
UOJLog::error(DB::query_str($q));
|
||||||
|
UOJLog::error('update failed: '.DB::$conn->error);
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
public static function insert($q) {
|
public static function insert($q) {
|
||||||
global $uojMySQL;
|
$ret = DB::$conn->query(DB::query_str($q));
|
||||||
return mysqli_query($uojMySQL, $q);
|
if ($ret === false) {
|
||||||
|
UOJLog::error(DB::query_str($q));
|
||||||
|
UOJLog::error('insert failed: '.DB::$conn->error);
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
public static function insert_id() {
|
public static function insert_id() {
|
||||||
global $uojMySQL;
|
return DB::$conn->insert_id;
|
||||||
return mysqli_insert_id($uojMySQL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete($q) {
|
public static function delete($q) {
|
||||||
global $uojMySQL;
|
$ret = DB::$conn->query(DB::query_str($q));
|
||||||
return mysqli_query($uojMySQL, $q);
|
if ($ret === false) {
|
||||||
|
UOJLog::error(DB::query_str($q));
|
||||||
|
UOJLog::error('delete failed: '.DB::$conn->error);
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
}
|
}
|
||||||
public static function select($q) {
|
public static function select($q) {
|
||||||
global $uojMySQL;
|
$q = DB::query_str($q);
|
||||||
return mysqli_query($uojMySQL, $q);
|
if ($q instanceof DBUseLocalCache) {
|
||||||
|
$q = $q->str;
|
||||||
|
$use_local_cache = true;
|
||||||
|
} else {
|
||||||
|
$use_local_cache = false;
|
||||||
}
|
}
|
||||||
public static function selectAll($q, $opt = MYSQLI_ASSOC) {
|
if ($use_local_cache && isset(DB::$cache[$q])) {
|
||||||
global $uojMySQL;
|
$res = DB::$cache[$q];
|
||||||
$res = array();
|
$res->data_seek(0);
|
||||||
$qr = mysqli_query($uojMySQL, $q);
|
$res->field_seek(0);
|
||||||
while ($row = mysqli_fetch_array($qr, $opt)) {
|
return $res;
|
||||||
|
}
|
||||||
|
$res = DB::$conn->query($q);
|
||||||
|
if ($use_local_cache) {
|
||||||
|
DB::$cache[$q] = $res;
|
||||||
|
}
|
||||||
|
if ($res === false) {
|
||||||
|
UOJLog::error($q);
|
||||||
|
UOJLog::error(DB::$conn->error);
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
public static function selectAll($q, $opt = DB::ASSOC) {
|
||||||
|
$qres = DB::select($q);
|
||||||
|
if ($qres === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// return $qres->fetch_all($opt); not supported
|
||||||
|
|
||||||
|
$res = [];
|
||||||
|
while ($row = $qres->fetch_array($opt)) {
|
||||||
$res[] = $row;
|
$res[] = $row;
|
||||||
}
|
}
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
public static function selectFirst($q, $opt = MYSQLI_ASSOC) {
|
public static function selectFirst($q, $opt = DB::ASSOC) {
|
||||||
global $uojMySQL;
|
$res = DB::select($q);
|
||||||
return mysqli_fetch_array(mysqli_query($uojMySQL, $q), $opt);
|
if ($res === false) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return $res->fetch_array($opt);
|
||||||
|
}
|
||||||
|
public static function selectSingle($q) {
|
||||||
|
$res = DB::select($q);
|
||||||
|
if ($res === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$row = $res->fetch_row();
|
||||||
|
if (!$row) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $row[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* perform SQL query $q in the form of select count(*) from XXX where XXX;
|
||||||
|
*/
|
||||||
public static function selectCount($q) {
|
public static function selectCount($q) {
|
||||||
global $uojMySQL;
|
$res = DB::select($q);
|
||||||
list($cnt) = mysqli_fetch_array(mysqli_query($uojMySQL, $q), MYSQLI_NUM);
|
if ($res === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
list($cnt) = $res->fetch_row();
|
||||||
return $cnt;
|
return $cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function checkTableExists($name) {
|
/**
|
||||||
global $uojMySQL;
|
* perform SQL query: select exists ($q);
|
||||||
return DB::query("select 1 from $name") !== false;
|
*
|
||||||
|
* on success, returns 0 or 1
|
||||||
|
* on failure, returns false
|
||||||
|
*
|
||||||
|
* @return int|false
|
||||||
|
*/
|
||||||
|
public static function selectExists($q) {
|
||||||
|
$res = DB::select(["select", DB::exists($q)]);
|
||||||
|
if ($res === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (int)($res->fetch_row()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function num_rows() {
|
public static function limit() {
|
||||||
global $uojMySQL;
|
$num = func_get_args();
|
||||||
return mysqli_num_rows($uojMySQL);
|
if (count($num) == 1) {
|
||||||
|
return "limit ".((int)$num[0]);
|
||||||
|
} elseif (count($num) == 2) {
|
||||||
|
return "limit ".((int)$num[0]).",".((int)$num[1]);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function for_share() {
|
||||||
|
return "for share";
|
||||||
|
}
|
||||||
|
public static function for_update() {
|
||||||
|
return "for update";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function startTransaction() {
|
||||||
|
return DB::$conn->begin_transaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function rollback() {
|
||||||
|
return DB::$conn->rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function commit() {
|
||||||
|
return DB::$conn->commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function transaction($func) {
|
||||||
|
if (DB::$in_transaction) {
|
||||||
|
$ret = $func();
|
||||||
|
} else {
|
||||||
|
DB::$in_transaction = true;
|
||||||
|
DB::startTransaction();
|
||||||
|
$ret = $func();
|
||||||
|
DB::commit();
|
||||||
|
DB::$in_transaction = false;
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function lock($tables, $func) {
|
||||||
|
$q = [];
|
||||||
|
foreach ($tables as $table => $type) {
|
||||||
|
if ($type != DB::WLOCK && $type != DB::RLOCK) {
|
||||||
|
UOJLog::error('Unknown type: '.$type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$q[] = $table.' '.$type;
|
||||||
|
}
|
||||||
|
$q = 'lock tables '.implode(',', $q);
|
||||||
|
DB::query($q);
|
||||||
|
|
||||||
|
$ret = $func();
|
||||||
|
|
||||||
|
DB::query("unlock tables");
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
public static function checkTableExists($name) {
|
||||||
|
return DB::select(["select 1 from", DB::table($name)]) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function num_rows($res) {
|
||||||
|
return $res->num_rows;
|
||||||
}
|
}
|
||||||
public static function affected_rows() {
|
public static function affected_rows() {
|
||||||
global $uojMySQL;
|
return DB::$conn->affected_rows;
|
||||||
return mysqli_affected_rows($uojMySQL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
web/app/models/DBRawString.php
Normal file
9
web/app/models/DBRawString.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class DBRawString {
|
||||||
|
public $str = '';
|
||||||
|
|
||||||
|
function __construct($str) {
|
||||||
|
$this->str = $str;
|
||||||
|
}
|
||||||
|
}
|
9
web/app/models/DBUseLocalCache.php
Normal file
9
web/app/models/DBUseLocalCache.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class DBUseLocalCache {
|
||||||
|
public $str;
|
||||||
|
|
||||||
|
function __construct($str) {
|
||||||
|
$this->str = $str;
|
||||||
|
}
|
||||||
|
}
|
64
web/app/models/FS.php
Normal file
64
web/app/models/FS.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class FS {
|
||||||
|
public static function scandir(string $directory, $cfg = []) {
|
||||||
|
$cfg += [
|
||||||
|
'exclude_dots' => true
|
||||||
|
];
|
||||||
|
$entries = scandir($directory);
|
||||||
|
if ($cfg['exclude_dots']) {
|
||||||
|
$entries = array_filter($entries, fn($name) => $name !== '.' && $name !== '..');
|
||||||
|
}
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function scandir_r(string $directory, $cfg = []) {
|
||||||
|
foreach (FS::scandir($directory, $cfg) as $name) {
|
||||||
|
$cur = "{$directory}/{$name}";
|
||||||
|
if (is_dir($cur)) {
|
||||||
|
foreach (FS::scandir_r($cur, $cfg) as $sub) {
|
||||||
|
yield "{$name}/{$sub}";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
yield $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $type lock type. can be either LOCK_SH or LOCK_EX
|
||||||
|
*/
|
||||||
|
public static function lock_file(string $path, int $type, callable $func) {
|
||||||
|
$lock_fp = fopen($path, 'c');
|
||||||
|
|
||||||
|
if (!flock($lock_fp, $type | LOCK_NB)) {
|
||||||
|
UOJLog::error("lock failed: {$path}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = $func();
|
||||||
|
|
||||||
|
flock($lock_fp, LOCK_UN | LOCK_NB);
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function randomAvailableFileName($dir, $suffix = '') {
|
||||||
|
do {
|
||||||
|
$name = $dir . uojRandString(20) . $suffix;
|
||||||
|
} while (file_exists(UOJContext::storagePath().$name));
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function randomAvailableTmpFileName() {
|
||||||
|
return static::randomAvailableFileName('/tmp/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function randomAvailableSubmissionFileName() {
|
||||||
|
$num = uojRand(1, 10000);
|
||||||
|
if (!file_exists(UOJContext::storagePath()."/submission/$num")) {
|
||||||
|
system("mkdir ".UOJContext::storagePath()."/submission/$num");
|
||||||
|
}
|
||||||
|
return static::randomAvailableFileName("/submission/$num/");
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,74 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class HTML {
|
class HTML {
|
||||||
public static function escape($str) {
|
public static function escape(?string $str, $cfg = []) {
|
||||||
|
if ($str === null) {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
if (!empty($cfg['single_line'])) {
|
||||||
|
$str = str_replace(["\n", "\r"], '', $str);
|
||||||
|
}
|
||||||
return htmlspecialchars($str);
|
return htmlspecialchars($str);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public static function stripTags($str) {
|
public static function stripTags($str) {
|
||||||
return strip_tags($str);
|
return strip_tags($str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function protocol(string $loc = 'main') {
|
||||||
|
if (UOJConfig::$data['web'][$loc]['protocol'] === 'http/https') {
|
||||||
|
if (UOJContext::isUsingHttps()) {
|
||||||
|
return 'https';
|
||||||
|
} else {
|
||||||
|
return 'http';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return UOJConfig::$data['web'][$loc]['protocol'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static function port(string $loc = 'main') {
|
||||||
|
if (UOJConfig::$data['web'][$loc]['port'] === '80/443') {
|
||||||
|
return HTML::standard_port(HTML::protocol($loc));
|
||||||
|
} else {
|
||||||
|
return UOJConfig::$data['web'][$loc]['port'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static function standard_port(string $protocol) {
|
||||||
|
if ($protocol === 'http') {
|
||||||
|
return 80;
|
||||||
|
} elseif ($protocol === 'https') {
|
||||||
|
return 443;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function attr($attr) {
|
||||||
|
$html = '';
|
||||||
|
foreach ($attr as $key => $val) {
|
||||||
|
$html .= ' ' . $key . '="';
|
||||||
|
$html .= HTML::escape(is_array($val) ? implode(' ', $val) : $val);
|
||||||
|
$html .= '"';
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tag_begin(string $name, array $attr = []) {
|
||||||
|
return '<' . $name . HTML::attr($attr) . '>';
|
||||||
|
}
|
||||||
|
public static function tag_end(string $name) {
|
||||||
|
return '</' . $name . '>';
|
||||||
|
}
|
||||||
|
public static function tag(string $name, array $attr, $content) {
|
||||||
|
return HTML::tag_begin($name, $attr) . $content . HTML::tag_end($name);
|
||||||
|
}
|
||||||
|
public static function empty_tag(string $name, array $attr) {
|
||||||
|
return '<' . $name . HTML::attr($attr) . ' />';
|
||||||
|
}
|
||||||
|
|
||||||
public static function avatar_addr($user, $size) {
|
public static function avatar_addr($user, $size) {
|
||||||
if ($user['avatar_source'] == 'qq' && $user['qq']) {
|
$extra = UOJUser::getExtra($user);
|
||||||
|
if ($extra['avatar_source'] == 'qq' && $user['qq']) {
|
||||||
$s = '5';
|
$s = '5';
|
||||||
|
|
||||||
if ($size <= 40) {
|
if ($size <= 40) {
|
||||||
@ -62,10 +122,23 @@ class HTML {
|
|||||||
}
|
}
|
||||||
public static function checkbox($name, $default_value) {
|
public static function checkbox($name, $default_value) {
|
||||||
$status = $default_value ? 'checked="checked" ' : '';
|
$status = $default_value ? 'checked="checked" ' : '';
|
||||||
return '<input type="checkbox" id="'."input-$name".'" name="'.$name.'" '.$status.'/>';
|
return '<input class="form-check-input" type="checkbox" id="' . "input-$name" . '" name="' . $name . '" ' . $status . '/>';
|
||||||
|
}
|
||||||
|
public static function option($value, $text, $selected) {
|
||||||
|
return '<option value="' . HTML::escape($value) . '"'
|
||||||
|
. ($selected ? ' selected="selected"' : '') . '>'
|
||||||
|
. HTML::escape($text)
|
||||||
|
. '</option>';
|
||||||
|
}
|
||||||
|
public static function tr_none() {
|
||||||
|
return '<tr class="text-center"><td colspan="233">' . UOJLocale::get('none') . '</td></tr>';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function blog_url($username, $uri) {
|
public static function blog_url($username, $uri, array $cfg = []) {
|
||||||
|
$cfg += [
|
||||||
|
'escape' => true
|
||||||
|
];
|
||||||
|
|
||||||
switch (UOJConfig::$data['switch']['blog-domain-mode']) {
|
switch (UOJConfig::$data['switch']['blog-domain-mode']) {
|
||||||
case 1:
|
case 1:
|
||||||
$port = ((UOJConfig::$data['web']['blog']['protocol'] === "http" && UOJConfig::$data['web']['blog']['port'] == 80) || (UOJConfig::$data['web']['blog']['protocol'] === "https" && UOJConfig::$data['web']['blog']['port'] == 443)) ? '' : (':' . UOJConfig::$data['web']['blog']['port']);
|
$port = ((UOJConfig::$data['web']['blog']['protocol'] === "http" && UOJConfig::$data['web']['blog']['port'] == 80) || (UOJConfig::$data['web']['blog']['protocol'] === "https" && UOJConfig::$data['web']['blog']['port'] == 443)) ? '' : (':' . UOJConfig::$data['web']['blog']['port']);
|
||||||
@ -81,7 +154,12 @@ class HTML {
|
|||||||
}
|
}
|
||||||
$url .= $uri;
|
$url .= $uri;
|
||||||
$url = rtrim($url, '/');
|
$url = rtrim($url, '/');
|
||||||
return HTML::escape($url);
|
|
||||||
|
if ($cfg['escape']) {
|
||||||
|
$url = HTML::escape($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
}
|
}
|
||||||
public static function blog_list_url() {
|
public static function blog_list_url() {
|
||||||
switch (UOJConfig::$data['switch']['blog-domain-mode']) {
|
switch (UOJConfig::$data['switch']['blog-domain-mode']) {
|
||||||
@ -97,21 +175,44 @@ class HTML {
|
|||||||
return HTML::escape(rtrim($url, '/'));
|
return HTML::escape(rtrim($url, '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function url($uri, $config = array()) {
|
public static function url($uri, array $cfg = []) {
|
||||||
$config = array_merge(array(
|
$cfg += [
|
||||||
'location' => 'main',
|
'location' => 'main',
|
||||||
'params' => null
|
'params' => null,
|
||||||
), $config);
|
'remove_all_params' => false,
|
||||||
|
'with_token' => false,
|
||||||
|
'escape' => true
|
||||||
|
];
|
||||||
|
|
||||||
$path = strtok($uri, '?');
|
if ($cfg['location'] == 'cdn' && !UOJContext::hasCDN()) {
|
||||||
$qs = strtok('?');
|
$cfg['location'] = 'main';
|
||||||
parse_str($qs, $param);
|
|
||||||
|
|
||||||
if ($config['params'] != null) {
|
|
||||||
$param = array_merge($param, $config['params']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = ''; // '//'.UOJConfig::$data['web'][$config['location']]['host'];
|
if (strStartWith($uri, '?')) {
|
||||||
|
$path = strtok(UOJContext::requestURI(), '?');
|
||||||
|
$qs = strtok($uri, '?');
|
||||||
|
} else {
|
||||||
|
$path = strtok($uri, '?');
|
||||||
|
$qs = strtok('?');
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_str($qs, $param);
|
||||||
|
|
||||||
|
|
||||||
|
if ($cfg['remove_all_params']) {
|
||||||
|
$param = [];
|
||||||
|
} elseif ($cfg['params'] != null) {
|
||||||
|
$param = array_merge($param, $cfg['params']);
|
||||||
|
}
|
||||||
|
if ($cfg['with_token']) {
|
||||||
|
$param['_token'] = crsf_token();
|
||||||
|
}
|
||||||
|
|
||||||
|
// $url = '//'.UOJConfig::$data['web'][$config['location']]['host'];
|
||||||
|
// if (HTML::port($cfg['location']) != HTML::standard_port($protocol)) {
|
||||||
|
// $url .= ':'.HTML::port($cfg['location']);
|
||||||
|
// }
|
||||||
|
$url = '';
|
||||||
if ($param) {
|
if ($param) {
|
||||||
$url .= $path . '?' . HTML::query_string_encode($param);
|
$url .= $path . '?' . HTML::query_string_encode($param);
|
||||||
} elseif ($path != '/') {
|
} elseif ($path != '/') {
|
||||||
@ -119,28 +220,169 @@ class HTML {
|
|||||||
} else {
|
} else {
|
||||||
$url .= $path;
|
$url .= $path;
|
||||||
}
|
}
|
||||||
return HTML::escape($url);
|
|
||||||
|
if ($cfg['escape']) {
|
||||||
|
$url = HTML::escape($url);
|
||||||
}
|
}
|
||||||
public static function timeanddate_url($time, $config = array()) {
|
return $url;
|
||||||
$url = UOJConfig::$data['web']['blog']['protocol'].'://';
|
}
|
||||||
|
public static function timeanddate_url(DateTime $time, array $cfg = []) {
|
||||||
|
$url = HTML::protocol() . '://';
|
||||||
$url .= 'www.timeanddate.com/worldclock/fixedtime.html';
|
$url .= 'www.timeanddate.com/worldclock/fixedtime.html';
|
||||||
$url .= '?' . 'iso=' . $time->format('Ymd\THi');
|
$url .= '?' . 'iso=' . $time->format('Ymd\THi');
|
||||||
$url .= '&' . 'p1=33';
|
$url .= '&' . 'p1=33';
|
||||||
if (isset($config['duration']) && $config['duration'] < 3600) {
|
if (isset($cfg['duration']) && $cfg['duration'] < 3600) {
|
||||||
$url .= '&'.'ah='.floor($config['duration'] / 60);
|
$url .= '&' . 'ah=' . floor($cfg['duration'] / 60);
|
||||||
if ($config['duration'] % 60 != 0) {
|
if ($cfg['duration'] % 60 != 0) {
|
||||||
$url .= '&'.'am='.($config['duration'] % 60);
|
$url .= '&' . 'am=' . ($cfg['duration'] % 60);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$url = HTML::escape($url);
|
return HTML::escape($url);
|
||||||
return $url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function js_src($uri, $config = array('location' => 'main')) {
|
public static function relative_time_str($time, $gran = -1) {
|
||||||
return '<script src="'.HTML::url($uri, $config).'"></script>';
|
$d = [
|
||||||
|
[1, 'seconds'],
|
||||||
|
[60, 'minutes'],
|
||||||
|
[3600, 'hours'],
|
||||||
|
[86400, 'days'],
|
||||||
|
[604800, 'weeks'],
|
||||||
|
[2592000, 'months'],
|
||||||
|
[31536000, 'years'],
|
||||||
|
];
|
||||||
|
$w = [];
|
||||||
|
|
||||||
|
$res = "";
|
||||||
|
$diff = time() - $time;
|
||||||
|
$secondsLeft = $diff;
|
||||||
|
$stopat = 0;
|
||||||
|
for ($i = 6; $i > $gran; $i--) {
|
||||||
|
$w[$i] = intval($secondsLeft / $d[$i][0]);
|
||||||
|
$secondsLeft -= ($w[$i] * $d[$i][0]);
|
||||||
|
if ($w[$i] != 0) {
|
||||||
|
$res .= UOJLocale::get('time::x ' . $d[$i][1], abs($w[$i])) . " ";
|
||||||
|
switch ($i) {
|
||||||
|
case 6: // shows years and months
|
||||||
|
if ($stopat == 0) {
|
||||||
|
$stopat = 5;
|
||||||
}
|
}
|
||||||
public static function css_link($uri, $config = array('location' => 'main')) {
|
break;
|
||||||
return '<link type="text/css" rel="stylesheet" href="'.HTML::url($uri, $config).'" />';
|
case 5: // shows months and weeks
|
||||||
|
if ($stopat == 0) {
|
||||||
|
$stopat = 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4: // shows weeks and days
|
||||||
|
if ($stopat == 0) {
|
||||||
|
$stopat = 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: // shows days and hours
|
||||||
|
if ($stopat == 0) {
|
||||||
|
$stopat = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: // shows hours and minutes
|
||||||
|
if ($stopat == 0) {
|
||||||
|
$stopat = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: // shows minutes and seconds if granularity is not set higher
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($i === $stopat) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$res .= ($diff > 0) ? UOJLocale::get('time::ago') : UOJLocale::get('time::left');
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function link(?string $uri, $text, $cfg = ['location' => 'main']) {
|
||||||
|
if ($uri === null) {
|
||||||
|
return '<a>' . HTML::escape($text) . '</a>';
|
||||||
|
}
|
||||||
|
return '<a class="text-decoration-none" href="' . HTML::url($uri, $cfg) . '">' . HTML::escape($text) . '</a>';
|
||||||
|
}
|
||||||
|
public static function autolink(string $url, array $attr = []) {
|
||||||
|
return '<a class="text-decoration-none" href="' . $url . '"' . HTML::attr($attr) . '>' . $url . '</a>';
|
||||||
|
}
|
||||||
|
public static function js_src(string $uri, array $cfg = []) {
|
||||||
|
$cfg += [
|
||||||
|
'location' => 'cdn',
|
||||||
|
'async' => false
|
||||||
|
];
|
||||||
|
$async = empty($cfg['async']) ? '' : 'async ';
|
||||||
|
return '<script ' . $async . 'src="' . HTML::url($uri, $cfg) . '"></script>';
|
||||||
|
}
|
||||||
|
public static function css_link(string $uri, $cfg = []) {
|
||||||
|
$cfg += ['location' => 'cdn'];
|
||||||
|
return '<link rel="stylesheet" href="' . HTML::url($uri, $cfg) . '" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table($header, iterable $data, $cfg = []) {
|
||||||
|
mergeConfig($cfg, [
|
||||||
|
'th' => function ($c) {
|
||||||
|
return "<th>{$c}</th>";
|
||||||
|
},
|
||||||
|
'td' => function ($d) {
|
||||||
|
return "<td>{$d}</td>";
|
||||||
|
},
|
||||||
|
'tr' => false, // if tr is a function, then td and tr_attr is disabled
|
||||||
|
'empty' => 'HTML::tr_none',
|
||||||
|
'table_attr' => [
|
||||||
|
'class' => ['table'],
|
||||||
|
],
|
||||||
|
'thead_attr' => [],
|
||||||
|
'tbody_attr' => [],
|
||||||
|
'tr_attr' => function ($row, $idx) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
$html = HTML::tag_begin('table', $cfg['table_attr']);
|
||||||
|
$html .= HTML::tag_begin('thead', $cfg['thead_attr']);
|
||||||
|
if (is_array($header)) {
|
||||||
|
$html .= '<tr>' . implode(' ', array_map($cfg['th'], array_values($header), array_keys($header))) . '</tr>';
|
||||||
|
} else {
|
||||||
|
$html .= $header;
|
||||||
|
}
|
||||||
|
$html .= HTML::tag_end('thead');
|
||||||
|
$html .= HTML::tag_begin('tbody', $cfg['tbody_attr']);
|
||||||
|
if (is_iterable($data)) {
|
||||||
|
$data_html = [];
|
||||||
|
if (is_callable($cfg['tr'])) {
|
||||||
|
foreach ($data as $idx => $row) {
|
||||||
|
$data_html[] = $cfg['tr']($row, $idx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($data as $idx => $row) {
|
||||||
|
$data_html[] = HTML::tag_begin('tr', $cfg['tr_attr']($row, $idx));
|
||||||
|
if (is_array($row)) {
|
||||||
|
foreach ($row as $cidx => $c) {
|
||||||
|
$data_html[] = $cfg['td']($c, $cidx);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data_html[] = $row;
|
||||||
|
}
|
||||||
|
$data_html[] = HTML::tag_end('tr');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data_html = implode($data_html);
|
||||||
|
} else {
|
||||||
|
$data_html = $data;
|
||||||
|
}
|
||||||
|
$html .= $data_html !== '' ? $data_html : $cfg['empty']();
|
||||||
|
$html .= HTML::tag_end('tbody');
|
||||||
|
$html .= HTML::tag_end('table');
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function responsive_table($header, $data, $cfg = []) {
|
||||||
|
return HTML::tag_begin('div', ['class' => 'table-responsive']) . HTML::table($header, $data, $cfg) . HTML::tag_end('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function query_string_encode($q, $array_name = null) {
|
public static function query_string_encode($q, $array_name = null) {
|
||||||
@ -239,4 +481,35 @@ class HTML {
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function echoPanel($cls = [], $title, $body, $other = null) {
|
||||||
|
if (is_string($cls)) {
|
||||||
|
$cls = ['card' => $cls];
|
||||||
|
}
|
||||||
|
|
||||||
|
$cls += [
|
||||||
|
'card' => '',
|
||||||
|
'header' => '',
|
||||||
|
'body' => '',
|
||||||
|
];
|
||||||
|
echo '<div class="card ', $cls['card'], '">';
|
||||||
|
echo '<div class="card-header fw-bold ', $cls['header'], '">', $title, '</div>';
|
||||||
|
if ($body !== null) {
|
||||||
|
echo '<div class="card-body ', $cls['body'], '">';
|
||||||
|
if (is_string($body)) {
|
||||||
|
echo $body;
|
||||||
|
} else {
|
||||||
|
$body();
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
|
if ($other !== null) {
|
||||||
|
if (is_string($other)) {
|
||||||
|
echo $other;
|
||||||
|
} else {
|
||||||
|
$other();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,44 +7,113 @@ class Paginator {
|
|||||||
public $cur_page;
|
public $cur_page;
|
||||||
public $cur_start;
|
public $cur_start;
|
||||||
public $max_extend;
|
public $max_extend;
|
||||||
|
|
||||||
|
public $table_name;
|
||||||
|
public $cond;
|
||||||
|
public $col_names;
|
||||||
|
public $tail;
|
||||||
|
public $post_filter;
|
||||||
|
|
||||||
public $table;
|
public $table;
|
||||||
|
|
||||||
|
public function getPage($page) {
|
||||||
|
$cur_start = ($page - 1) * $this->page_len;
|
||||||
|
$table = DB::selectAll([
|
||||||
|
"select", DB::fields($this->col_names), "from", DB::query_str($this->table_name),
|
||||||
|
"where", $this->cond,
|
||||||
|
$this->tail, DB::limit($cur_start, $this->page_len)
|
||||||
|
]);
|
||||||
|
if ($this->post_filter === null) {
|
||||||
|
return $table;
|
||||||
|
} else {
|
||||||
|
return array_filter($table, $this->post_filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkPageExists($page) {
|
||||||
|
if ($page < 1 || $page > $this->n_pages) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($this->post_filter === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$post_filter = $this->post_filter;
|
||||||
|
$cur_start = ($page - 1) * $this->page_len;
|
||||||
|
for ($bg = 0; $bg < $this->page_len; $bg += 10) {
|
||||||
|
$table = DB::selectAll([
|
||||||
|
"select", DB::fields($this->col_names), "from", DB::query_str($this->table_name),
|
||||||
|
"where", $this->cond,
|
||||||
|
$this->tail, DB::limit($cur_start + $bg, min(10, $this->page_len - $bg))
|
||||||
|
]);
|
||||||
|
foreach ($table as $entry) {
|
||||||
|
if ($post_filter($entry)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function __construct($config) {
|
public function __construct($config) {
|
||||||
|
$this->max_extend = isset($config['max_extend']) ? (int)$config['max_extend'] : 5;
|
||||||
|
$this->post_filter = isset($config['post_filter']) ? $config['post_filter'] : null;
|
||||||
|
|
||||||
if (isset($config['data'])) {
|
if (isset($config['data'])) {
|
||||||
$this->n_pages = 1;
|
$this->n_pages = 1;
|
||||||
$this->cur_page = 1;
|
$this->cur_page = 1;
|
||||||
$this->cur_start = 0;
|
$this->cur_start = 0;
|
||||||
$this->table = $config['data'];
|
$this->table = $config['data'];
|
||||||
} elseif (!isset($config['echo_full'])) {
|
if ($this->post_filter !== null) {
|
||||||
$table = $config['table_name'];
|
$this->table = array_filter($this->table, $this->post_filter);
|
||||||
$cond = isset($config['cond']) ? $config['cond'] : '1';
|
|
||||||
if (isset($config['pagination_table'])) {
|
|
||||||
$table = $config['pagination_table'];
|
|
||||||
$cond = isset($config['pagination_cond']) ? $config['pagination_cond'] : $cond;
|
|
||||||
}
|
}
|
||||||
$this->n_rows = DB::selectCount("select count(*) from {$table} where {$cond}");
|
} elseif (!isset($config['echo_full'])) {
|
||||||
|
$this->cur_page = UOJRequest::get('page', 'validateUInt', 1);
|
||||||
$this->page_len = isset($config['page_len']) ? $config['page_len'] : 10;
|
|
||||||
|
|
||||||
$this->n_pages = max((int)ceil($this->n_rows / $this->page_len), 1);
|
|
||||||
|
|
||||||
$this->cur_page = validateUInt($_GET['page']) ? (int)$_GET['page'] : 1;
|
|
||||||
if ($this->cur_page < 1) {
|
if ($this->cur_page < 1) {
|
||||||
$this->cur_page = 1;
|
$this->cur_page = 1;
|
||||||
} elseif ($this->cur_page > $this->n_pages) {
|
}
|
||||||
|
$this->page_len = isset($config['page_len']) ? $config['page_len'] : 10;
|
||||||
|
|
||||||
|
$this->table_name = $config['table_name'];
|
||||||
|
$this->cond = $config['cond'];
|
||||||
|
$this->col_names = $config['col_names'];
|
||||||
|
$this->tail = $config['tail'];
|
||||||
|
|
||||||
|
$this->n_rows = DB::selectCount([
|
||||||
|
"select", "count(*)",
|
||||||
|
"from", DB::query_str($this->table_name),
|
||||||
|
"where", $this->cond,
|
||||||
|
$this->tail,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->n_pages = max((int)ceil($this->n_rows / $this->page_len), 1);
|
||||||
|
while ($this->n_pages > 1 && !$this->checkPageExists($this->n_pages)) {
|
||||||
|
$this->n_pages--;
|
||||||
|
}
|
||||||
|
if ($this->cur_page > $this->n_pages) {
|
||||||
$this->cur_page = $this->n_pages;
|
$this->cur_page = $this->n_pages;
|
||||||
}
|
}
|
||||||
|
while (true) {
|
||||||
|
$this->table = $this->getPage($this->cur_page);
|
||||||
|
if ($this->table || $this->cur_page == 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$this->cur_page--;
|
||||||
|
}
|
||||||
$this->cur_start = ($this->cur_page - 1) * $this->page_len;
|
$this->cur_start = ($this->cur_page - 1) * $this->page_len;
|
||||||
|
|
||||||
$this->table = DB::selectAll("select ".join($config['col_names'], ',')." from {$config['table_name']} where {$config['cond']} {$config['tail']} limit {$this->cur_start}, {$this->page_len}");
|
|
||||||
} else {
|
} else {
|
||||||
$this->n_pages = 1;
|
$this->n_pages = 1;
|
||||||
$this->cur_page = 1;
|
$this->cur_page = 1;
|
||||||
$this->cur_start = ($this->cur_page - 1) * $this->page_len;
|
$this->cur_start = 0;
|
||||||
$this->table = DB::selectAll("select ".join($config['col_names'], ',')." from {$config['table_name']} where {$config['cond']} {$config['tail']}");
|
$this->table = DB::selectAll([
|
||||||
|
"select", DB::fields($config['col_names']), "from", DB::query_str($config['table_name']),
|
||||||
|
"where", $config['cond'],
|
||||||
|
$config['tail']
|
||||||
|
]);
|
||||||
|
if ($this->post_filter !== null) {
|
||||||
|
$this->table = array_filter($this->table, $this->post_filter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->max_extend = isset($config['max_extend']) ? (int)$config['max_extend'] : 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPageRawUri($page) {
|
public function getPageRawUri($page) {
|
||||||
@ -67,101 +136,73 @@ class Paginator {
|
|||||||
return HTML::escape($this->getPageRawUri($page));
|
return HTML::escape($this->getPageRawUri($page));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get() {
|
public function get($limit = -1) {
|
||||||
$cur_idx = $this->cur_start + 1;
|
$cur_idx = $this->cur_start + 1;
|
||||||
foreach ($this->table as $idx => $row) {
|
foreach ($this->table as $row) {
|
||||||
|
if ($limit != -1 && $cur_idx - $this->cur_start > $limit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
yield $cur_idx++ => $row;
|
yield $cur_idx++ => $row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function isEmpty() {
|
public function isEmpty() {
|
||||||
return empty($this->table);
|
return empty($this->table);
|
||||||
}
|
}
|
||||||
|
public function countInCurPage() {
|
||||||
|
return count($this->table);
|
||||||
|
}
|
||||||
|
|
||||||
public function pagination() {
|
public function pagination() {
|
||||||
global $REQUIRE_LIB;
|
|
||||||
|
|
||||||
if ($this->n_pages == 1) {
|
if ($this->n_pages == 1) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
$prev_page = false;
|
||||||
$html = '<ul class="pagination my-0 justify-content-center">';
|
$next_page = false;
|
||||||
} else {
|
$main_lis = '';
|
||||||
$html = '<ul class="pagination top-buffer-no bot-buffer-sm justify-content-center">';
|
|
||||||
}
|
|
||||||
if ($this->cur_page > 1) {
|
|
||||||
$html .= '<li class="page-item">'
|
|
||||||
. '<a class="page-link" href="'.$this->getPageUri(1).'">';
|
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
|
||||||
$html .= '<i class="bi bi-chevron-double-left"></i>';
|
|
||||||
} else {
|
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-fast-backward"></span>';
|
|
||||||
}
|
|
||||||
$html .= '</a></li>';
|
|
||||||
$html .= '<li class="page-item">'
|
|
||||||
. '<a class="page-link" href="'.$this->getPageUri($this->cur_page - 1).'">';
|
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
|
||||||
$html .= '<i class="bi bi-chevron-left"></i>';
|
|
||||||
} else {
|
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-backward"></span>';
|
|
||||||
}
|
|
||||||
$html .= '</a></li>';
|
|
||||||
} else {
|
|
||||||
$html .= '<li class="page-item disabled"><a class="page-link">';
|
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
|
||||||
$html .= '<i class="bi bi-chevron-double-left"></i>';
|
|
||||||
} else {
|
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-fast-backward"></span>';
|
|
||||||
}
|
|
||||||
$html .= '</a></li>';
|
|
||||||
$html .= '<li class="page-item disabled"><a class="page-link">';
|
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
|
||||||
$html .= '<i class="bi bi-chevron-left"></i>';
|
|
||||||
} else {
|
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-backward"></span>';
|
|
||||||
}
|
|
||||||
$html .= '</a></li>';
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($i = max($this->cur_page - $this->max_extend, 1); $i <= min($this->cur_page + $this->max_extend, $this->n_pages); $i++) {
|
$page_st = $this->cur_page - $this->max_extend;
|
||||||
|
$page_ed = $this->cur_page + $this->max_extend;
|
||||||
|
if ($this->n_pages <= $this->max_extend * 2 + 1) {
|
||||||
|
$page_st = 1;
|
||||||
|
$page_ed = $this->n_pages;
|
||||||
|
} elseif ($page_st < 1) {
|
||||||
|
$page_st = 1;
|
||||||
|
$page_ed = $this->max_extend * 2 + 1;
|
||||||
|
} elseif ($page_ed > $this->n_pages) {
|
||||||
|
$page_st = $this->n_pages - $this->max_extend * 2;
|
||||||
|
$page_ed = $this->n_pages;
|
||||||
|
}
|
||||||
|
for ($i = $page_st; $i <= $page_ed; $i++) {
|
||||||
if ($i == $this->cur_page) {
|
if ($i == $this->cur_page) {
|
||||||
$html .= '<li class="page-item active"><a class="page-link" href="'.$this->getPageUri($i).'">'.$i.'</a></li>';
|
$main_lis .= '<li class="page-item active"><a class="page-link" href="' . $this->getPageUri($i) . '">' . $i . '</a></li>';
|
||||||
} else {
|
} else {
|
||||||
$html .= '<li class="page-item"><a class="page-link" href="'.$this->getPageUri($i).'">'.$i.'</a></li>';
|
if ($this->checkPageExists($i)) {
|
||||||
|
$main_lis .= '<li class="page-item"><a class="page-link" href="' . $this->getPageUri($i) . '">' . $i . '</a></li>';
|
||||||
|
if ($i < $this->cur_page) {
|
||||||
|
$prev_page = $i;
|
||||||
|
} elseif ($next_page === false) {
|
||||||
|
$next_page = $i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->cur_page < $this->n_pages) {
|
|
||||||
$html .= '<li class="page-item">'
|
|
||||||
. '<a class="page-link" href="'.$this->getPageUri($this->cur_page + 1).'">';
|
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
|
||||||
$html .= '<i class="bi bi-chevron-right"></i>';
|
|
||||||
} else {
|
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-forward"></span>';
|
|
||||||
}
|
}
|
||||||
$html .= '</a></li>';
|
|
||||||
|
|
||||||
$html .= '<li class="page-item">'
|
$html = '';
|
||||||
. '<a class="page-link" href="'.$this->getPageUri($this->n_pages).'">';
|
$html .= '<ul class="pagination my-0 justify-content-center">';
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
if ($prev_page !== false) {
|
||||||
$html .= '<i class="bi bi-chevron-double-right"></i>';
|
$html .= '<li class="page-item"><a class="page-link" href="' . $this->getPageUri(1) . '""><i class="bi bi-chevron-double-left"></i></a></li>';
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . $this->getPageUri($prev_page) . '"><i class="bi bi-chevron-left"></i></a></li>';
|
||||||
} else {
|
} else {
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-fast-forward"></span>';
|
$html .= '<li class="page-item disabled"><a class="page-link"><i class="bi bi-chevron-double-left"></i></a></li>';
|
||||||
|
$html .= '<li class="page-item disabled"><a class="page-link"><i class="bi bi-chevron-left"></i></a></li>';
|
||||||
}
|
}
|
||||||
$html .= '</a></li>';
|
$html .= $main_lis;
|
||||||
|
if ($next_page !== false) {
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . $this->getPageUri($next_page) . '"><i class="bi bi-chevron-right"></i></a></li>';
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . $this->getPageUri($this->n_pages) . '"><i class="bi bi-chevron-double-right"></i></a></li>';
|
||||||
} else {
|
} else {
|
||||||
$html .= '<li class="page-item disabled"><a class="page-link">';
|
$html .= '<li class="page-item disabled"><a class="page-link"><i class="bi bi-chevron-right"></i></a></li>';
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
$html .= '<li class="page-item disabled"><a class="page-link"><i class="bi bi-chevron-double-right"></i></a></li>';
|
||||||
$html .= '<i class="bi bi-chevron-right"></i>';
|
|
||||||
} else {
|
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-forward"></span>';
|
|
||||||
}
|
|
||||||
$html .= '</a></li>';
|
|
||||||
$html .= '<li class="page-item disabled"><a class="page-link">';
|
|
||||||
if (isset($REQUIRE_LIB['bootstrap5'])) {
|
|
||||||
$html .= '<i class="bi bi-chevron-double-right"></i>';
|
|
||||||
} else {
|
|
||||||
$html .= '<span class="glyphicon glyphicon glyphicon-fast-forward"></span>';
|
|
||||||
}
|
|
||||||
$html .= '</a></li>';
|
|
||||||
}
|
}
|
||||||
$html .= '</ul>';
|
$html .= '</ul>';
|
||||||
return $html;
|
return $html;
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class Route {
|
class Route {
|
||||||
protected static $routes = array();
|
protected static $routes = [];
|
||||||
protected static $patterns = array();
|
protected static $patterns = [];
|
||||||
protected static $groupStack = array(array());
|
protected static $groupStack = [[]];
|
||||||
|
|
||||||
public static function match($methods, $uri, $action) {
|
public static function match($methods, $uri, $action) {
|
||||||
return self::addRoute(array_map('strtoupper', (array)$methods), $uri, $action);
|
return self::addRoute(array_map('strtoupper', (array)$methods), $uri, $action);
|
||||||
}
|
}
|
||||||
public static function any($uri, $action) {
|
public static function any($uri, $action) {
|
||||||
return self::addRoute(array('GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'), $uri, $action);
|
return self::addRoute(['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'], $uri, $action);
|
||||||
}
|
}
|
||||||
public static function get($uri, $action) {
|
public static function get($uri, $action) {
|
||||||
return self::addRoute(['GET', 'HEAD'], $uri, $action);
|
return self::addRoute(['GET', 'HEAD'], $uri, $action);
|
||||||
@ -46,7 +46,7 @@ class Route {
|
|||||||
return $route;
|
return $route;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
become404Page();
|
UOJResponse::page404();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static function addRoute($methods, $uri, $action) {
|
protected static function addRoute($methods, $uri, $action) {
|
||||||
@ -54,7 +54,7 @@ class Route {
|
|||||||
$methods = [$methods];
|
$methods = [$methods];
|
||||||
}
|
}
|
||||||
|
|
||||||
$cur = array();
|
$cur = [];
|
||||||
$cur['methods'] = $methods;
|
$cur['methods'] = $methods;
|
||||||
$cur['uri'] = rtrim($uri, '/');
|
$cur['uri'] = rtrim($uri, '/');
|
||||||
$cur['action'] = $action;
|
$cur['action'] = $action;
|
||||||
@ -67,21 +67,27 @@ class Route {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$rep_arr = array();
|
$rep_arr = [];
|
||||||
foreach (self::$patterns as $name => $pat) {
|
foreach (self::$patterns as $name => $pat) {
|
||||||
$rep_arr['{'.$name.'}'] = "(?P<$name>$pat)";
|
$rep_arr['{'.$name.'}'] = "(?P<$name>$pat)";
|
||||||
}
|
}
|
||||||
$rep_arr['/'] = '\/';
|
$rep_arr['/'] = '\/';
|
||||||
$rep_arr['.'] = '\.';
|
$rep_arr['.'] = '\.';
|
||||||
|
|
||||||
$matches = array();
|
$matches = [];
|
||||||
if (isset($route['domain'])) {
|
if (isset($route['domain'])) {
|
||||||
$domain_pat = strtr($route['domain'], $rep_arr);
|
$domain_pat = strtr($route['domain'], $rep_arr);
|
||||||
if (!preg_match('/^'.$domain_pat.'$/', UOJContext::httpHost(), $domain_matches)) {
|
if (!preg_match('/^'.$domain_pat.'$/', UOJContext::requestDomain(), $domain_matches)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$matches = array_merge($matches, $domain_matches);
|
$matches = array_merge($matches, $domain_matches);
|
||||||
}
|
}
|
||||||
|
if (isset($route['port'])) {
|
||||||
|
$ports = explode('/', $route['port']);
|
||||||
|
if (!in_array(UOJContext::requestPort(), $ports)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$uri_pat = strtr($route['uri'], $rep_arr);
|
$uri_pat = strtr($route['uri'], $rep_arr);
|
||||||
if (!preg_match('/^'.$uri_pat.'$/', rtrim(UOJContext::requestPath(), '/'), $uri_matches)) {
|
if (!preg_match('/^'.$uri_pat.'$/', rtrim(UOJContext::requestPath(), '/'), $uri_matches)) {
|
||||||
@ -95,6 +101,21 @@ class Route {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($route['protocol'])) {
|
||||||
|
switch ($route['protocol']) {
|
||||||
|
case 'http':
|
||||||
|
if (UOJContext::isUsingHttps()) {
|
||||||
|
permanentlyRedirectToHTTP();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'https':
|
||||||
|
if (!UOJContext::isUsingHttps()) {
|
||||||
|
permanentlyRedirectToHTTPS();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
65
web/app/models/StrictFileReader.php
Normal file
65
web/app/models/StrictFileReader.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class StrictFileReader {
|
||||||
|
private $f;
|
||||||
|
private $buf = '', $off = 0;
|
||||||
|
|
||||||
|
public function __construct($file_name) {
|
||||||
|
$this->f = fopen($file_name, 'r');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function failed() {
|
||||||
|
return $this->f === false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readChar() {
|
||||||
|
if (isset($this->buf[$this->off])) {
|
||||||
|
return $this->buf[$this->off++];
|
||||||
|
}
|
||||||
|
return fgetc($this->f);
|
||||||
|
}
|
||||||
|
public function unreadChar($c) {
|
||||||
|
$this->buf .= $c;
|
||||||
|
if ($this->off > 1000) {
|
||||||
|
$this->buf = substr($this->buf, $this->off);
|
||||||
|
$this->off = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readString() {
|
||||||
|
$str = '';
|
||||||
|
while (true) {
|
||||||
|
$c = $this->readChar();
|
||||||
|
if ($c === false) {
|
||||||
|
break;
|
||||||
|
} elseif ($c === " " || $c === "\n" || $c === "\r") {
|
||||||
|
$this->unreadChar($c);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
$str .= $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
public function ignoreWhite() {
|
||||||
|
while (true) {
|
||||||
|
$c = $this->readChar();
|
||||||
|
if ($c === false) {
|
||||||
|
break;
|
||||||
|
} elseif ($c === " " || $c === "\n" || $c === "\r") {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
$this->unreadChar($c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eof() {
|
||||||
|
return feof($this->f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function close() {
|
||||||
|
fclose($this->f);
|
||||||
|
}
|
||||||
|
}
|
55
web/app/models/UOJArticleTrait.php
Normal file
55
web/app/models/UOJArticleTrait.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
trait UOJArticleTrait {
|
||||||
|
static string $table_for_content;
|
||||||
|
static string $key_for_content;
|
||||||
|
static array $fields_for_content;
|
||||||
|
static string $table_for_tags;
|
||||||
|
static string $key_for_tags;
|
||||||
|
|
||||||
|
public ?array $tags = null;
|
||||||
|
public ?array $content = null;
|
||||||
|
|
||||||
|
public function queryContent() {
|
||||||
|
if ($this->content === null) {
|
||||||
|
$this->content = DB::selectFirst([
|
||||||
|
"select", DB::fields(static::$fields_for_content), "from", static::$table_for_content,
|
||||||
|
"where", [static::$key_for_content => $this->info['id']]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
public function queryTags() {
|
||||||
|
if ($this->tags === null) {
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select tag from", static::$table_for_tags,
|
||||||
|
"where", [static::$key_for_tags => $this->info['id']],
|
||||||
|
"order by id"
|
||||||
|
]);
|
||||||
|
$this->tags = [];
|
||||||
|
foreach ($res as $row) {
|
||||||
|
$this->tags[] = $row['tag'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->tags;
|
||||||
|
}
|
||||||
|
public function updateTags(array $tags) {
|
||||||
|
if ($tags !== $this->queryTags()) {
|
||||||
|
DB::delete([
|
||||||
|
"delete from", static::$table_for_tags,
|
||||||
|
"where", [static::$key_for_tags => $this->info['id']],
|
||||||
|
]);
|
||||||
|
if ($tags) {
|
||||||
|
$tuples = [];
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$tuples[] = [$this->info['id'], $tag];
|
||||||
|
}
|
||||||
|
DB::insert([
|
||||||
|
"insert into", static::$table_for_tags,
|
||||||
|
DB::bracketed_fields([static::$key_for_tags, 'tag']),
|
||||||
|
"values", DB::tuples($tuples)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
200
web/app/models/UOJBlog.php
Normal file
200
web/app/models/UOJBlog.php
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UOJBlog {
|
||||||
|
use UOJDataTrait;
|
||||||
|
use UOJArticleTrait;
|
||||||
|
|
||||||
|
public static function query($id) {
|
||||||
|
if (!isset($id) || !validateUInt($id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$info = DB::selectFirst([
|
||||||
|
"select id, title, post_time, active_time, poster, zan, is_hidden, type from blogs",
|
||||||
|
"where", ['id' => $id]
|
||||||
|
]);
|
||||||
|
if (!$info) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new UOJBlog($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct($info) {
|
||||||
|
$this->info = $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the blog belongs to the current user blog
|
||||||
|
*/
|
||||||
|
public function belongsToUserBlog() {
|
||||||
|
return UOJContext::type() == 'blog' && UOJUserBlog::id() === $this->info['poster'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanView(array $user = null) {
|
||||||
|
return !$this->info['is_hidden'] || $this->userCanManage($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanManage(array $user = null) {
|
||||||
|
return UOJUserBlog::userCanManage($user, $this->info['poster']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isTypeB() {
|
||||||
|
return $this->info['type'] === 'B';
|
||||||
|
}
|
||||||
|
public function isTypeS() {
|
||||||
|
return $this->info['type'] === 'S';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(array $cfg = []) {
|
||||||
|
$title = $this->info['title'];
|
||||||
|
return $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBlogUri($where = '') {
|
||||||
|
return HTML::blog_url($this->info['poster'], "/post/{$this->info['id']}{$where}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSlideUri($where = '') {
|
||||||
|
return HTML::blog_url($this->info['poster'], "/slide/{$this->info['id']}{$where}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUriForWrite() {
|
||||||
|
return $this->isTypeB() ? $this->getBlogUri('/write') : $this->getSlideUri('/write');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLink(array $cfg = []) {
|
||||||
|
// title has been escaped by the blog editor
|
||||||
|
$link = '';
|
||||||
|
if (!empty($cfg['show_level'])) {
|
||||||
|
$level_str = $this->getLevelString();
|
||||||
|
if ($level_str !== '') {
|
||||||
|
$link .= "{$level_str} ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$link .= '<a href="'. $this->getBlogUri() .'">'.$this->getTitle($cfg).'</a>';
|
||||||
|
if (!empty($cfg['show_new_tag'])) {
|
||||||
|
if ($this->isNew()) {
|
||||||
|
$link .= '<sup style="color:red"> new</sup>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the blog is marked as "new".
|
||||||
|
* Call this function only if info['is_new'] has been filled by the corresponding value in the table important_blogs.
|
||||||
|
*/
|
||||||
|
public function isNew() {
|
||||||
|
return (time() - strtotime($this->info['post_time'])) / 3600 / 24 <= 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the string that shows the importance level of this blog.
|
||||||
|
* Call this function only if info['level'] has been filled by the corresponding value in the table important_blogs.
|
||||||
|
*/
|
||||||
|
public function getLevelString() {
|
||||||
|
$level = $this->info['level'];
|
||||||
|
switch ($level) {
|
||||||
|
case 1:
|
||||||
|
return '<span style="color:red">[三级置顶]</span>';
|
||||||
|
case 2:
|
||||||
|
return '<span style="color:red">[二级置顶]</span>';
|
||||||
|
case 3:
|
||||||
|
return '<span style="color:red">[一级置顶]</span>';
|
||||||
|
default: // such as 0
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queryNewestComment() {
|
||||||
|
return DB::selectFirst([
|
||||||
|
"select * from blogs_comments",
|
||||||
|
"where", [
|
||||||
|
'blog_id' => $this->info['id'],
|
||||||
|
'is_hidden' => false
|
||||||
|
],
|
||||||
|
"order by post_time desc",
|
||||||
|
DB::limit(1)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateActiveTime() {
|
||||||
|
$active_time = $this->info['post_time'];
|
||||||
|
|
||||||
|
$newest = $this->queryNewestComment();
|
||||||
|
if ($newest) {
|
||||||
|
$active_time = $newest['post_time'];
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update blogs",
|
||||||
|
"set", ['active_time' => $active_time],
|
||||||
|
"where", ['id' => $this->info['id']]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function deleteByID($id) {
|
||||||
|
$id = (int)$id;
|
||||||
|
DB::delete([
|
||||||
|
"delete from click_zans",
|
||||||
|
"where", [
|
||||||
|
'type' => 'B',
|
||||||
|
'target_id' => $id
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
DB::delete([
|
||||||
|
"delete from click_zans",
|
||||||
|
"where", [
|
||||||
|
'type' => 'BC',
|
||||||
|
[
|
||||||
|
"target_id", "in", DB::rawbracket([
|
||||||
|
"select id from blogs_comments",
|
||||||
|
"where", ["blog_id" => $id]
|
||||||
|
])
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
DB::delete([
|
||||||
|
"delete from blogs",
|
||||||
|
"where", ['id' => $id]
|
||||||
|
]);
|
||||||
|
DB::delete([
|
||||||
|
"delete from blogs_comments",
|
||||||
|
"where", ['blog_id' => $id]
|
||||||
|
]);
|
||||||
|
DB::delete([
|
||||||
|
"delete from important_blogs",
|
||||||
|
"where", ['blog_id' => $id]
|
||||||
|
]);
|
||||||
|
DB::delete([
|
||||||
|
"delete from blogs_tags",
|
||||||
|
"where", ['blog_id' => $id]
|
||||||
|
]);
|
||||||
|
DB::delete([
|
||||||
|
"delete from problems_solutions",
|
||||||
|
"where", ['blog_id' => $id]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete() {
|
||||||
|
self::deleteByID($this->info['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function echoView(array $cfg = []) {
|
||||||
|
// load tags and content into cache
|
||||||
|
$this->queryContent();
|
||||||
|
$this->queryTags();
|
||||||
|
|
||||||
|
$cfg += [
|
||||||
|
'blog' => $this,
|
||||||
|
'show_title_only' => false,
|
||||||
|
'is_preview' => false
|
||||||
|
];
|
||||||
|
uojIncludeView('blog-preview', $cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UOJBlog::$table_for_content = 'blogs';
|
||||||
|
UOJBlog::$key_for_content = 'id';
|
||||||
|
UOJBlog::$fields_for_content = ['content', 'content_md'];
|
||||||
|
UOJBlog::$table_for_tags = 'blogs_tags';
|
||||||
|
UOJBlog::$key_for_tags = 'blog_id';
|
39
web/app/models/UOJBlogComment.php
Normal file
39
web/app/models/UOJBlogComment.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UOJBlogComment {
|
||||||
|
use UOJDataTrait;
|
||||||
|
|
||||||
|
public static function query($id) {
|
||||||
|
if (!isset($id) || !validateUInt($id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$info = DB::selectFirst([
|
||||||
|
"select * from blogs_comments",
|
||||||
|
"where", ['id' => $id]
|
||||||
|
]);
|
||||||
|
if (!$info) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new UOJBlogComment($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct($info) {
|
||||||
|
$this->info = $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hide($reason) {
|
||||||
|
DB::update([
|
||||||
|
"update blogs_comments",
|
||||||
|
"set", [
|
||||||
|
'is_hidden' => ($reason !== ''),
|
||||||
|
'reason_to_hide' => $reason
|
||||||
|
],
|
||||||
|
"where", ['id' => $this->info['id']]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$blog = UOJBlog::query($this->info['blog_id']);
|
||||||
|
if ($blog) {
|
||||||
|
$blog->updateActiveTime($blog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,12 +5,12 @@ class UOJBlogEditor {
|
|||||||
public $name;
|
public $name;
|
||||||
public $blog_url;
|
public $blog_url;
|
||||||
public $save;
|
public $save;
|
||||||
public $cur_data = array();
|
public $cur_data = [];
|
||||||
public $post_data = array();
|
public $post_data = [];
|
||||||
public $show_editor = true;
|
public $show_editor = true;
|
||||||
public $show_tags = true;
|
public $show_tags = true;
|
||||||
|
|
||||||
public $label_text = array(
|
public $label_text = [
|
||||||
'title' => '标题',
|
'title' => '标题',
|
||||||
'tags' => '标签(多个标签用逗号隔开)',
|
'tags' => '标签(多个标签用逗号隔开)',
|
||||||
'content' => '内容',
|
'content' => '内容',
|
||||||
@ -18,7 +18,7 @@ class UOJBlogEditor {
|
|||||||
'blog visibility' => '博客可见性',
|
'blog visibility' => '博客可见性',
|
||||||
'private' => '未公开',
|
'private' => '未公开',
|
||||||
'public' => '公开'
|
'public' => '公开'
|
||||||
);
|
];
|
||||||
|
|
||||||
public $validator = array();
|
public $validator = array();
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ class UOJBlogEditor {
|
|||||||
global $REQUIRE_LIB;
|
global $REQUIRE_LIB;
|
||||||
$REQUIRE_LIB['blog-editor'] = '';
|
$REQUIRE_LIB['blog-editor'] = '';
|
||||||
|
|
||||||
$this->validator = array(
|
$this->validator = [
|
||||||
'title' => function(&$title) {
|
'title' => function(&$title) {
|
||||||
if ($title == '') {
|
if ($title == '') {
|
||||||
return '标题不能为空';
|
return '标题不能为空';
|
||||||
@ -67,7 +67,7 @@ class UOJBlogEditor {
|
|||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate($name) {
|
public function validate($name) {
|
||||||
@ -201,10 +201,10 @@ class UOJBlogEditor {
|
|||||||
} elseif ($this->type == 'slide') {
|
} elseif ($this->type == 'slide') {
|
||||||
uojIncludeView('slide', array_merge(
|
uojIncludeView('slide', array_merge(
|
||||||
UOJContext::pageConfig(),
|
UOJContext::pageConfig(),
|
||||||
array(
|
[
|
||||||
'PageTitle' => '幻灯片预览',
|
'PageTitle' => '幻灯片预览',
|
||||||
'content' => $this->post_data['content']
|
'content' => $this->post_data['content']
|
||||||
)
|
]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
$ret['html'] = ob_get_contents();
|
$ret['html'] = ob_get_contents();
|
||||||
@ -222,6 +222,6 @@ class UOJBlogEditor {
|
|||||||
public function printHTML() {
|
public function printHTML() {
|
||||||
global $REQUIRE_LIB;
|
global $REQUIRE_LIB;
|
||||||
|
|
||||||
uojIncludeView('blog-editor', array('editor' => $this, 'REQUIRE_LIB' => $REQUIRE_LIB));
|
uojIncludeView('blog-editor', ['editor' => $this, 'REQUIRE_LIB' => $REQUIRE_LIB]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
470
web/app/models/UOJContest.php
Normal file
470
web/app/models/UOJContest.php
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UOJContest {
|
||||||
|
use UOJDataTrait;
|
||||||
|
|
||||||
|
public static function query($id) {
|
||||||
|
if (!isset($id) || !validateUInt($id)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$info = DB::selectFirst([
|
||||||
|
"select * from contests",
|
||||||
|
"where", ['id' => $id]
|
||||||
|
]);
|
||||||
|
if (!$info) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new UOJContest($info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function finalTest() {
|
||||||
|
$contest = self::info();
|
||||||
|
|
||||||
|
$res = DB::selectAll([
|
||||||
|
"select id, problem_id, content, submitter, hide_score_to_others from submissions",
|
||||||
|
"where", ["contest_id" => $contest['id']]
|
||||||
|
]);
|
||||||
|
foreach ($res as $submission) {
|
||||||
|
$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']);
|
||||||
|
}
|
||||||
|
UOJSubmission::rejudgeById($submission['id'], [
|
||||||
|
'reason_text' => HTML::stripTags($contest['name']) . ' 最终测试',
|
||||||
|
'reason_url' => HTML::url(UOJContest::cur()->getUri()),
|
||||||
|
'set_q' => [
|
||||||
|
"content" => json_encode($content)
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// warning: check if this command works well when the database is not MySQL
|
||||||
|
DB::update([
|
||||||
|
"update submissions",
|
||||||
|
"set", [
|
||||||
|
"score = hidden_score",
|
||||||
|
"hidden_score = NULL",
|
||||||
|
"hide_score_to_others = 0"
|
||||||
|
], "where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
"hide_score_to_others" => 1
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$updated = [];
|
||||||
|
foreach ($res as $submission) {
|
||||||
|
$submitter = $submission['submitter'];
|
||||||
|
$pid = $submission['problem_id'];
|
||||||
|
if (isset($updated[$submitter]) && isset($updated[$submitter][$pid])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
updateBestACSubmissions($submitter, $pid);
|
||||||
|
if (!isset($updated[$submitter])) {
|
||||||
|
$updated[$submitter] = [];
|
||||||
|
}
|
||||||
|
$updated[$submitter][$pid] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::update([
|
||||||
|
"update contests",
|
||||||
|
"set", ["status" => 'testing'],
|
||||||
|
"where", ["id" => $contest['id']]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function announceOfficialResults() {
|
||||||
|
// time config
|
||||||
|
set_time_limit(0);
|
||||||
|
ignore_user_abort(true);
|
||||||
|
|
||||||
|
$contest = self::info();
|
||||||
|
|
||||||
|
$data = queryContestData($contest);
|
||||||
|
$n_problems = count($data['problems']);
|
||||||
|
$total_score = $n_problems * 100;
|
||||||
|
calcStandings($contest, $data, $score, $standings, ['update_contests_submissions' => true]);
|
||||||
|
|
||||||
|
for ($i = 0; $i < count($standings); $i++) {
|
||||||
|
$user_link = getUserLink($standings[$i][2][0]);
|
||||||
|
$tail = $standings[$i][0] == $total_score ? ',请继续保持。' : ',请继续努力!';
|
||||||
|
|
||||||
|
$content = '<p>' . $user_link . ' 您好:</p>';
|
||||||
|
$content .= '<p>' . '您参与的比赛 <a href="/contest/' . $contest['id'] . '">' . $contest['name'] . '</a> 现已公布成绩,您的成绩为 <a class="uoj-score" data-max="' . $total_score . '">' . $standings[$i][0] . '</a>' . $tail . '</p>';
|
||||||
|
sendSystemMsg($standings[$i][2][0], '比赛成绩公布通知', $content);
|
||||||
|
DB::update([
|
||||||
|
"update contests_registrants",
|
||||||
|
"set", ["final_rank" => $standings[$i][3]],
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $contest['id'],
|
||||||
|
"username" => $standings[$i][2][0]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
DB::update([
|
||||||
|
"update contests",
|
||||||
|
"set", ["status" => 'finished'],
|
||||||
|
"where", ["id" => $contest['id']]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct($info) {
|
||||||
|
$this->info = $info;
|
||||||
|
$this->completeInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function completeInfo() {
|
||||||
|
if (isset($this->info['cur_progress'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->info['start_time_str'] = $this->info['start_time'];
|
||||||
|
$this->info['start_time'] = new DateTime($this->info['start_time']);
|
||||||
|
$this->info['end_time_str'] = $this->info['end_time'];
|
||||||
|
$this->info['end_time'] = new DateTime($this->info['end_time']);
|
||||||
|
|
||||||
|
$this->info['extra_config'] = json_decode($this->info['extra_config'], true);
|
||||||
|
|
||||||
|
if (!isset($this->info['extra_config']['standings_version'])) {
|
||||||
|
$this->info['extra_config']['standings_version'] = 2;
|
||||||
|
}
|
||||||
|
if (!isset($this->info['extra_config']['basic_rule'])) {
|
||||||
|
$this->info['extra_config']['basic_rule'] = 'OI';
|
||||||
|
}
|
||||||
|
if (!isset($this->info['extra_config']['free_registration'])) {
|
||||||
|
$this->info['extra_config']['free_registration'] = 1;
|
||||||
|
}
|
||||||
|
if (!isset($this->info['extra_config']['extra_registration'])) {
|
||||||
|
$this->info['extra_config']['extra_registration'] = 1;
|
||||||
|
}
|
||||||
|
if (!isset($this->info['extra_config']['individual_or_team'])) {
|
||||||
|
$this->info['extra_config']['individual_or_team'] = 'individual';
|
||||||
|
}
|
||||||
|
if (!isset($this->info['extra_config']['bonus'])) {
|
||||||
|
$this->info['extra_config']['bonus'] = [];
|
||||||
|
}
|
||||||
|
if (!isset($this->info['extra_config']['submit_time_limit'])) {
|
||||||
|
$this->info['extra_config']['submit_time_limit'] = [];
|
||||||
|
}
|
||||||
|
if (!isset($this->info['extra_config']['max_n_submissions_per_problem'])) {
|
||||||
|
$this->info['extra_config']['max_n_submissions_per_problem'] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->info['status'] == 'unfinished') {
|
||||||
|
if (UOJTime::$time_now < $this->info['start_time']) {
|
||||||
|
$this->info['cur_progress'] = CONTEST_NOT_STARTED;
|
||||||
|
} elseif (UOJTime::$time_now < $this->info['end_time']) {
|
||||||
|
$this->info['cur_progress'] = CONTEST_IN_PROGRESS;
|
||||||
|
} else {
|
||||||
|
if ($this->info['extra_config']['basic_rule'] == 'IOI') {
|
||||||
|
$this->info['cur_progress'] = CONTEST_TESTING;
|
||||||
|
} else {
|
||||||
|
$this->info['cur_progress'] = CONTEST_PENDING_FINAL_TEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($this->info['status'] == 'testing') {
|
||||||
|
$this->info['cur_progress'] = CONTEST_TESTING;
|
||||||
|
} elseif ($this->info['status'] == 'finished') {
|
||||||
|
$this->info['cur_progress'] = CONTEST_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info['frozen_time'] = false;
|
||||||
|
$this->info['frozen'] = false;
|
||||||
|
|
||||||
|
if ($this->info['extra_config']['basic_rule'] == 'ACM') {
|
||||||
|
$this->info['frozen_time'] = clone $this->info['end_time'];
|
||||||
|
|
||||||
|
$frozen_min = min($this->info['last_min'] / 5, 60);
|
||||||
|
|
||||||
|
$this->info['frozen_time']->sub(new DateInterval("PT{$frozen_min}M"));
|
||||||
|
$this->info['frozen'] = $this->info['cur_progress'] < CONTEST_TESTING && UOJTime::$time_now > $this->info['frozen_time'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function basicRule() {
|
||||||
|
return $this->info['extra_config']['basic_rule'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function progress() {
|
||||||
|
return $this->info['cur_progress'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function maxSubmissionCountPerProblem() {
|
||||||
|
return $this->info['extra_config']['max_n_submissions_per_problem'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function freeRegistration() {
|
||||||
|
return $this->info['extra_config']['free_registration'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function allowExtraRegistration() {
|
||||||
|
return $this->info['extra_config']['extra_registration'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function labelForFinalTest() {
|
||||||
|
if ($this->basicRule() === 'ACM') {
|
||||||
|
$label = '揭榜';
|
||||||
|
} else {
|
||||||
|
$label = '开始最终测试';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->progress() >= CONTEST_TESTING) {
|
||||||
|
$label = '重新' . $label;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queryJudgeProgress() {
|
||||||
|
if ($this->basicRule() == 'OI' && $this->progress() < CONTEST_TESTING) {
|
||||||
|
$rop = 0;
|
||||||
|
$title = UOJLocale::get('contests::contest pending final test');
|
||||||
|
} else {
|
||||||
|
$total = DB::selectCount([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", ["contest_id" => $this->info['id']]
|
||||||
|
]);
|
||||||
|
$n_judged = DB::selectCount([
|
||||||
|
"select count(*) from submissions",
|
||||||
|
"where", [
|
||||||
|
"contest_id" => $this->info['id'],
|
||||||
|
"status" => 'Judged'
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$rop = $total == 0 ? 100 : (int)($n_judged / $total * 100);
|
||||||
|
|
||||||
|
$title = UOJLocale::get('contests::contest final testing');
|
||||||
|
if ($this->basicRule() != 'OI' && $n_judged == $total) {
|
||||||
|
$title = UOJLocale::get('contests::contest official results to be announced');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'rop' => $rop,
|
||||||
|
'title' => $title
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queryResult($cfg = []) {
|
||||||
|
$contest_data = queryContestData($this->info, $cfg);
|
||||||
|
calcStandings($this->info, $contest_data, $score, $standings, $cfg);
|
||||||
|
return [
|
||||||
|
'standings' => $standings,
|
||||||
|
'score' => $score,
|
||||||
|
'contest_data' => $contest_data
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function managerCanSeeFinalStandingsTab(array $user = null) {
|
||||||
|
if ($this->basicRule() == 'IOI') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $this->progress() < CONTEST_TESTING;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanSeeProblemStatistics($user) {
|
||||||
|
return $this->userCanManage($user) || $this->progress() > CONTEST_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanRegister(array $user = null, $cfg = []) {
|
||||||
|
$cfg += ['ensure' => false];
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
$cfg['ensure'] && redirectToLogin();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!$this->freeRegistration()) {
|
||||||
|
$cfg['ensure'] && $this->redirectToAnnouncementBlog();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($this->progress() == CONTEST_IN_PROGRESS && !$this->allowExtraRegistration()) {
|
||||||
|
$cfg['ensure'] && redirectTo('/contests');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
/* $this->userCanManage($user) || */ // 在 S2OJ 中,具有管理员权限的用户也可报名参赛。
|
||||||
|
$this->userHasRegistered($user) || $this->progress() > CONTEST_IN_PROGRESS
|
||||||
|
) {
|
||||||
|
$cfg['ensure'] && redirectTo('/contests');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isTmpUser($user)) {
|
||||||
|
$cfg['ensure'] && UOJResponse::message("<h1>临时账号无法报名该比赛</h1><p>换个自己注册的账号试试吧~</p>");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanView(array $user = null, $cfg = []) {
|
||||||
|
$cfg += [
|
||||||
|
'ensure' => false,
|
||||||
|
'check-register' => false
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($this->userCanManage($user) && !$this->userHasRegistered($user)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ($this->progress() == CONTEST_NOT_STARTED) {
|
||||||
|
$cfg['ensure'] && redirectTo($this->getUri('/register'));
|
||||||
|
return false;
|
||||||
|
} elseif ($this->progress() <= CONTEST_IN_PROGRESS) {
|
||||||
|
if ($cfg['check-register']) {
|
||||||
|
if ($user && $this->userHasRegistered($user)) {
|
||||||
|
if (!$this->userHasMarkedParticipated($user)) {
|
||||||
|
$cfg['ensure'] && redirectTo($this->getUri('/confirm'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ($cfg['ensure']) {
|
||||||
|
if ($this->info['extra_config']['extra_registration']) {
|
||||||
|
redirectTo($this->getUri('/register'));
|
||||||
|
} else {
|
||||||
|
UOJResponse::message("<h1>比赛正在进行中</h1><p>很遗憾,您尚未报名。比赛结束后再来看吧~</p>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanParticipateNow(array $user = null) {
|
||||||
|
// 在 S2OJ 中,具有管理员权限的用户在报名后也可参赛。
|
||||||
|
//
|
||||||
|
// if ($this->userCanManage($user)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return $this->progress() == CONTEST_IN_PROGRESS && $user && $this->userHasRegistered($user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userCanManage(array $user = null) {
|
||||||
|
if (!$user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isSuperUser($user)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return DB::selectFirst([
|
||||||
|
DB::lc(), "select 1 from contests_permissions",
|
||||||
|
"where", [
|
||||||
|
'username' => $user['username'],
|
||||||
|
'contest_id' => $this->info['id']
|
||||||
|
]
|
||||||
|
]) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userHasRegistered(array $user = null) {
|
||||||
|
if (!$user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return DB::selectFirst([
|
||||||
|
DB::lc(), "select 1 from contests_registrants",
|
||||||
|
"where", [
|
||||||
|
'username' => $user['username'],
|
||||||
|
'contest_id' => $this->info['id']
|
||||||
|
]
|
||||||
|
]) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function defaultProblemJudgeType() {
|
||||||
|
if ($this->basicRule() == 'OI') {
|
||||||
|
return 'sample';
|
||||||
|
} else {
|
||||||
|
return 'no-details';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProblemIDs() {
|
||||||
|
return array_map(fn ($x) => $x['problem_id'], DB::selectAll([
|
||||||
|
DB::lc(), "select problem_id from contests_problems",
|
||||||
|
"where", ['contest_id' => $this->info['id']],
|
||||||
|
"order by level, problem_id"
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasProblem(UOJProblem $problem) {
|
||||||
|
return DB::selectFirst([
|
||||||
|
DB::lc(), "select 1 from contests_problems",
|
||||||
|
"where", [
|
||||||
|
'contest_id' => $this->info['id'],
|
||||||
|
'problem_id' => $problem->info['id']
|
||||||
|
]
|
||||||
|
]) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userHasMarkedParticipated(array $user = null) {
|
||||||
|
if (!$user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return DB::selectExists([
|
||||||
|
"select 1 from contests_registrants",
|
||||||
|
"where", [
|
||||||
|
"username" => $user['username'],
|
||||||
|
"contest_id" => $this->info['id'],
|
||||||
|
"has_participated" => 1
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function markUserAsParticipated(array $user = null) {
|
||||||
|
if (!$user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return DB::update([
|
||||||
|
"update contests_registrants",
|
||||||
|
"set", ["has_participated" => 1],
|
||||||
|
"where", [
|
||||||
|
"username" => $user['username'],
|
||||||
|
"contest_id" => $this->info['id']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUri($where = '') {
|
||||||
|
return "/contest/{$this->info['id']}{$where}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function redirectToAnnouncementBlog() {
|
||||||
|
$url = getContestBlogLink($this->info, '公告');
|
||||||
|
if ($url !== null) {
|
||||||
|
redirectTo($url);
|
||||||
|
} else {
|
||||||
|
redirectTo('/contests');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userRegister(array $user = null) {
|
||||||
|
if (!$user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DB::insert([
|
||||||
|
"replace into contests_registrants",
|
||||||
|
"(username, contest_id, has_participated)",
|
||||||
|
"values", DB::tuple([$user['username'], $this->info['id'], 0])
|
||||||
|
]);
|
||||||
|
updateContestPlayerNum($this->info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userUnregister(array $user = null) {
|
||||||
|
if (!$user) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DB::delete([
|
||||||
|
"delete from contests_registrants",
|
||||||
|
"where", [
|
||||||
|
"username" => $user['username'],
|
||||||
|
"contest_id" => $this->info['id']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
updateContestPlayerNum($this->info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user