├── .gitignore ├── .travis.yml ├── Android ├── .gitignore ├── README.md ├── build.gradle ├── gradlew ├── gradlew.bat ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lzc │ │ └── lpoj │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── lzc │ │ │ └── lpoj │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── lzc │ └── lpoj │ └── ExampleUnitTest.java ├── Backend ├── Backend │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── Dockerfile ├── ProblemData │ └── README.md ├── README.md ├── blog │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── board │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── classes │ ├── __init__.py │ ├── admin.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── contest │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── item │ ├── __init__.py │ ├── admin.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── judgestatus │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── manage.py ├── problem │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── requirements.txt ├── user │ ├── __init__.py │ ├── admin.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py └── wiki │ ├── __init__.py │ ├── migrations │ └── __init__.py │ ├── models.py │ ├── permission.py │ ├── serializers.py │ ├── urls.py │ └── views.py ├── CrawlingServer ├── CodeForceContestCounter.py ├── Codeforces.py ├── CodeforcesRate.py ├── Dockerfile ├── HDU.py ├── LPOJ.py ├── README.md ├── Vjudge.py ├── main.py ├── requirements.txt └── setting.json ├── Database ├── Dockerfile ├── README.md ├── conf │ ├── mysqld.cnf │ └── mysqld_safe_syslog.cnf └── init_database.sql ├── Docs ├── .gitignore ├── README.md ├── docs │ ├── .vuepress │ │ ├── config.js │ │ └── public │ │ │ └── img │ │ │ ├── donate.jpg │ │ │ ├── faq │ │ │ ├── db.png │ │ │ ├── db2.png │ │ │ ├── db3.png │ │ │ └── db4.png │ │ │ ├── favicon.ico │ │ │ └── logo.jpg │ ├── README.md │ ├── deploy │ │ ├── README.md │ │ ├── backend.md │ │ ├── crawlingserver.md │ │ ├── frontend.md │ │ ├── judger.md │ │ └── judgeserver.md │ ├── dev │ │ ├── README.md │ │ ├── backend.md │ │ ├── frontend.md │ │ ├── judger.md │ │ └── judgerserver.md │ ├── doc │ │ ├── README.md │ │ ├── faq.md │ │ ├── judger.md │ │ ├── oj.md │ │ └── utils.md │ └── faq │ │ ├── README.md │ │ ├── intro.md │ │ ├── systemstruct.md │ │ └── whatisoj.md ├── package-lock.json └── package.json ├── Frontend ├── .babelrc ├── .dockerignore ├── .editorconfig ├── .gitignore ├── .postcssrc.js ├── Dockerfile ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── logo.png │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── nginx.conf ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── components │ │ ├── admin │ │ │ ├── adminaddchoiceproblem.vue │ │ │ ├── adminaddcontest.vue │ │ │ ├── adminaddproblem.vue │ │ │ ├── adminboard.vue │ │ │ ├── adminchangechoiceproblem.vue │ │ │ ├── adminchangecontest.vue │ │ │ ├── adminchangepro.vue │ │ │ ├── adminclassmanage.vue │ │ │ ├── adminmanageuser.vue │ │ │ ├── adminrejudge.vue │ │ │ ├── adminsetting.vue │ │ │ ├── admintrainning.vue │ │ │ └── givechoiceproblemscore.vue │ │ ├── chart │ │ │ ├── echarts.js │ │ │ ├── rankchart.vue │ │ │ ├── ratingchart.vue │ │ │ └── teamchart.vue │ │ ├── contest │ │ │ ├── contestannounce.vue │ │ │ ├── contestchoiceproblem.vue │ │ │ ├── contestcomment.vue │ │ │ ├── contestdetail.vue │ │ │ ├── contestoverview.vue │ │ │ ├── contestproblem.vue │ │ │ ├── contestrank.vue │ │ │ ├── contestsubmit.vue │ │ │ └── contesttutorial.vue │ │ ├── main.vue │ │ ├── mainpage │ │ │ ├── admin.vue │ │ │ ├── billboard.vue │ │ │ ├── blog.vue │ │ │ ├── classdetail.vue │ │ │ ├── classes.vue │ │ │ ├── contest.vue │ │ │ ├── homework.vue │ │ │ ├── problem.vue │ │ │ ├── rank.vue │ │ │ ├── setting.vue │ │ │ ├── statue.vue │ │ │ ├── user.vue │ │ │ └── wiki.vue │ │ ├── problem │ │ │ └── problemdetail.vue │ │ ├── utils │ │ │ ├── acrank.vue │ │ │ ├── algorithmselect.vue │ │ │ ├── blogmini.vue │ │ │ ├── cfrate.vue │ │ │ ├── contestmini.vue │ │ │ ├── description.vue │ │ │ ├── languageselect.vue │ │ │ ├── ojmessage.vue │ │ │ ├── prostatistice.vue │ │ │ ├── ratingrule.vue │ │ │ ├── soulrow.vue │ │ │ ├── statusmini.vue │ │ │ ├── todolist.vue │ │ │ ├── topuser.vue │ │ │ ├── welcomemessage.vue │ │ │ └── wikidetail.vue │ │ └── wiki │ │ │ ├── algorithm.vue │ │ │ ├── algorithmpages │ │ │ ├── basic.vue │ │ │ ├── dp.vue │ │ │ ├── ds.vue │ │ │ ├── editalgorithm.vue │ │ │ ├── geometry.vue │ │ │ ├── graph.vue │ │ │ ├── intro.vue │ │ │ ├── math.vue │ │ │ ├── misc.vue │ │ │ ├── search.vue │ │ │ └── string.vue │ │ │ ├── code.vue │ │ │ ├── mbcode │ │ │ ├── codeedit.vue │ │ │ ├── viewcode.vue │ │ │ └── viewcodedetail.vue │ │ │ ├── newalgorithm.vue │ │ │ ├── trainning.vue │ │ │ └── trainning │ │ │ └── trainningdetail.vue │ ├── login.vue │ ├── main.js │ ├── register.vue │ └── router │ │ └── index.js └── static │ ├── .gitkeep │ └── js │ ├── MathJax.js │ ├── config │ └── TeX-AMS-MML_HTMLorMML.js │ ├── fonts │ └── HTML-CSS │ │ └── TeX │ │ └── woff │ │ ├── MathJax_AMS-Regular.woff │ │ ├── MathJax_Caligraphic-Bold.woff │ │ ├── MathJax_Caligraphic-Regular.woff │ │ ├── MathJax_Fraktur-Bold.woff │ │ ├── MathJax_Fraktur-Regular.woff │ │ ├── MathJax_Main-Bold.woff │ │ ├── MathJax_Main-Italic.woff │ │ ├── MathJax_Main-Regular.woff │ │ ├── MathJax_Math-BoldItalic.woff │ │ ├── MathJax_Math-Italic.woff │ │ ├── MathJax_Math-Regular.woff │ │ ├── MathJax_SansSerif-Bold.woff │ │ ├── MathJax_SansSerif-Italic.woff │ │ ├── MathJax_SansSerif-Regular.woff │ │ ├── MathJax_Script-Regular.woff │ │ ├── MathJax_Size1-Regular.woff │ │ ├── MathJax_Size2-Regular.woff │ │ ├── MathJax_Size3-Regular.woff │ │ ├── MathJax_Size4-Regular.woff │ │ └── MathJax_Typewriter-Regular.woff │ └── jax │ └── output │ └── HTML-CSS │ ├── fonts │ └── TeX │ │ └── fontdata.js │ └── jax.js ├── FrontendMobile ├── .babelrc ├── .dockerignore ├── .editorconfig ├── .gitignore ├── .postcssrc.js ├── Dockerfile ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── logo.png │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── nginx.conf ├── package-lock.json ├── package.json ├── src │ ├── App.vue │ ├── components │ │ ├── contest │ │ │ ├── contestdetail.vue │ │ │ ├── contestoverview.vue │ │ │ ├── contestrank.vue │ │ │ └── contestsubmit.vue │ │ ├── main.vue │ │ ├── mainpage │ │ │ ├── billboard.vue │ │ │ ├── blog.vue │ │ │ ├── contest.vue │ │ │ ├── problem.vue │ │ │ ├── rank.vue │ │ │ ├── statue.vue │ │ │ ├── user.vue │ │ │ └── wiki.vue │ │ ├── problem │ │ │ └── problemdetail.vue │ │ ├── utils │ │ │ ├── acrank.vue │ │ │ ├── algorithmselect.vue │ │ │ ├── contestmini.vue │ │ │ ├── topuser.vue │ │ │ ├── welcomemessage.vue │ │ │ └── wikidetail.vue │ │ └── wiki │ │ │ ├── newalgorithm.vue │ │ │ ├── trainning.vue │ │ │ └── trainning │ │ │ └── trainningdetail.vue │ ├── login.vue │ ├── main.js │ ├── register.vue │ └── router │ │ └── index.js └── static │ └── .gitkeep ├── HomePage ├── assets │ ├── css │ │ ├── animate.min.css │ │ ├── bootstrap.min.css │ │ ├── default.css │ │ ├── fontawesome-all.min.css │ │ ├── magnific-popup.css │ │ ├── meanmenu.css │ │ ├── owl.carousel.min.css │ │ ├── owl.theme.default.min.css │ │ ├── responsive.css │ │ └── scrolltop.css │ ├── fonts │ │ └── fontawesome-webfont.woff2 │ ├── img │ │ ├── about │ │ │ ├── about-1.png │ │ │ ├── shape-1.png │ │ │ ├── shape-2.png │ │ │ ├── shape-3.png │ │ │ └── shape-4.png │ │ ├── breadcrumb │ │ │ └── breadcrumb.png │ │ ├── cta │ │ │ ├── 2.jpg │ │ │ ├── 5.png │ │ │ ├── cta-bg.jpg │ │ │ └── cta-bg.png │ │ ├── faqs │ │ │ └── faqs-1.png │ │ ├── footer │ │ │ └── foot-bg.png │ │ ├── hero │ │ │ └── hero-bg-1.png │ │ ├── logo-1.png │ │ ├── logo-2.png │ │ ├── screen │ │ │ ├── screen-1.jpg │ │ │ ├── screen-2.jpg │ │ │ ├── screen-3.jpg │ │ │ └── screen-4.jpg │ │ ├── services │ │ │ ├── icon-1-1.png │ │ │ ├── icon-1-2.png │ │ │ ├── icon-1-3.png │ │ │ ├── icon-1.png │ │ │ ├── icon-2.png │ │ │ ├── icon-3.png │ │ │ ├── shape-1.png │ │ │ ├── shape-2.png │ │ │ └── shape-3.png │ │ └── top-arrow.svg │ └── js │ │ ├── ajax-form.js │ │ ├── bootstrap.min.js │ │ ├── counterup.min.js │ │ ├── jquery-1.12.4.min.js │ │ ├── magnific-popup.min.js │ │ ├── main.js │ │ ├── maps.active.js │ │ ├── meanmenu.min.js │ │ ├── modernizr-3.5.0.min.js │ │ ├── owl.carousel.min.js │ │ ├── plugins.js │ │ ├── popper.min.js │ │ ├── scrolltop.js │ │ ├── waypoints.min.js │ │ └── wow.min.js ├── index.html └── style.css ├── Judger ├── CMakeLists.txt ├── Dockerfile ├── JudgeHDU │ └── JudgeHDU.py ├── JudgerCore │ ├── _judger │ │ ├── __init__.py │ │ └── __init__.pyc │ ├── build │ │ ├── lib.linux-x86_64-2.7 │ │ │ └── _judger │ │ │ │ └── __init__.py │ │ └── lib │ │ │ └── _judger │ │ │ └── __init__.py │ └── setup.py ├── ProblemData │ └── README.md ├── README.md ├── datatime.json ├── main.py ├── output │ └── libjudger.so ├── requirements.txt ├── setting.json └── src │ ├── argtable3.c │ ├── argtable3.h │ ├── child.c │ ├── child.h │ ├── killer.c │ ├── killer.h │ ├── logger.c │ ├── logger.h │ ├── main.c │ ├── rules │ ├── c_cpp.c │ ├── general.c │ └── seccomp_rules.h │ ├── runner.c │ └── runner.h ├── JudgerServer ├── Dockerfile ├── README.md ├── main.py ├── requirements.txt └── setting.json ├── LICENSE ├── README.md ├── Tools ├── HDUSpider.py ├── README.md ├── RaiseCheck.py ├── RatingCalculator.py ├── RecoverBoard.py ├── SubmitExport.py ├── UserImporter.py ├── duplication_checking.py └── setting.json ├── docker-compose-build.yml └── docker-compose.yml /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | Judger/build 3 | Judger/test 4 | *.pyc 5 | Judger/*.cpp 6 | Judger/*.c 7 | Judger/*out 8 | Judger/*.log 9 | Judger/*.out 10 | *.in 11 | *.out 12 | *.log 13 | Judger/output/libjudger.so 14 | *.zip 15 | *.exe 16 | .vscode 17 | *.class 18 | # GDUFSTeamScore.py 19 | # GDUFSTeamExport.py 20 | CrawlingServer/contest.json 21 | Database/data 22 | 数据 23 | 24 | CrawlingServer/NowCoderSpider.py 25 | CrawlingServer/CFSpider.py 26 | CrawlingServer/HDUSpider.py 27 | 00* 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | services: 2 | - docker 3 | 4 | env: 5 | DOCKER_COMPOSE_VERSION: 1.24.0 6 | 7 | before_install: 8 | - sudo rm /usr/local/bin/docker-compose 9 | - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose 10 | - chmod +x docker-compose 11 | - sudo mv docker-compose /usr/local/bin 12 | 13 | script: 14 | - docker-compose -f docker-compose-build.yml build -------------------------------------------------------------------------------- /Android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | .gradle 4 | *.jks 5 | /local.properties 6 | .DS_Store 7 | /build 8 | /release 9 | /gradle 10 | /push/build 11 | /captures 12 | .externalNativeBuild -------------------------------------------------------------------------------- /Android/README.md: -------------------------------------------------------------------------------- 1 | # LPOJ的安卓版 2 | 3 | 其实就是一个浏览器,访问手机版…… -------------------------------------------------------------------------------- /Android/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.2" 6 | defaultConfig { 7 | applicationId "com.lzc.lpoj" 8 | minSdkVersion 15 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(dir: 'libs', include: ['*.jar']) 24 | implementation 'androidx.appcompat:appcompat:1.1.0' 25 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 26 | testImplementation 'junit:junit:4.12' 27 | androidTestImplementation 'androidx.test:runner:1.2.0' 28 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 29 | } 30 | buildscript { 31 | repositories { 32 | google() 33 | jcenter() 34 | 35 | } 36 | dependencies { 37 | classpath 'com.android.tools.build:gradle:3.4.2' 38 | 39 | // NOTE: Do not place your application dependencies here; they belong 40 | // in the individual module build.gradle files 41 | } 42 | } 43 | 44 | allprojects { 45 | repositories { 46 | google() 47 | jcenter() 48 | 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /Android/src/androidTest/java/com/lzc/lpoj/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.lzc.lpoj; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.InstrumentationRegistry; 6 | import androidx.test.runner.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.lzc.lpoj", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Android/src/main/java/com/lzc/lpoj/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lzc.lpoj; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.os.Bundle; 6 | 7 | import android.os.Bundle; 8 | import android.app.Activity; 9 | import android.view.Menu; 10 | import android.view.Window; 11 | import android.webkit.WebChromeClient; 12 | import android.webkit.WebSettings; 13 | import android.webkit.WebView; 14 | import android.webkit.WebViewClient; 15 | import android.view.KeyEvent; 16 | 17 | 18 | public class MainActivity extends Activity { 19 | 20 | private WebView webView; 21 | 22 | @Override 23 | public boolean onKeyDown(int keyCode, KeyEvent event) { 24 | if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { 25 | webView.goBack(); // goBack()表示返回WebView的上一页面 26 | return true; 27 | } 28 | return super.onKeyDown(keyCode,event); 29 | } 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | requestWindowFeature(Window.FEATURE_NO_TITLE); 35 | setContentView(R.layout.activity_main); 36 | 37 | webView = (WebView) findViewById(R.id.webView); 38 | 39 | webView.loadUrl("https://m.lpoj.cn"); 40 | 41 | webView.setWebViewClient(new WebViewClient() { 42 | // 当点击链接时,覆盖窗口 43 | @Override 44 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 45 | // TODO Auto-generated method stub 46 | view.loadUrl(url);// 加载url 47 | return super.shouldOverrideUrlLoading(view, url); 48 | } 49 | }); 50 | 51 | WebSettings webSettings = webView.getSettings(); 52 | webSettings.setJavaScriptEnabled(true);// 启用JS脚本 53 | // 这里可以有很多设置 54 | // webSettings.setSupportZoom(true); // 支持缩放 55 | // webSettings.setBuiltInZoomControls(true); // 启用内置缩放装置 56 | 57 | webView.setWebChromeClient(new WebChromeClient() { 58 | // 当WebView进度改变时更新窗口进度 59 | @Override 60 | public void onProgressChanged(WebView view, int newProgress) { 61 | // TODO Auto-generated method stub 62 | // 自己实现 63 | super.onProgressChanged(view, newProgress); 64 | } 65 | }); 66 | 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Android/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /Android/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /Android/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /Android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LPOJ 3 | 4 | -------------------------------------------------------------------------------- /Android/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Android/src/test/java/com/lzc/lpoj/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.lzc.lpoj; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /Backend/Backend/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/Backend/__init__.py -------------------------------------------------------------------------------- /Backend/Backend/urls.py: -------------------------------------------------------------------------------- 1 | """Backend URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | from django.urls import path 19 | 20 | urlpatterns = [ 21 | url(r'^admin/', admin.site.urls), 22 | url(r'', include('problem.urls')), 23 | url(r'', include('judgestatus.urls')), 24 | url(r'', include('user.urls')), 25 | url(r'', include('contest.urls')), 26 | url(r'', include('board.urls')), 27 | url(r'', include('blog.urls')), 28 | url(r'', include('wiki.urls')), 29 | url(r'', include('item.urls')), 30 | url(r'', include('classes.urls')), 31 | 32 | ] 33 | -------------------------------------------------------------------------------- /Backend/Backend/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for Backend project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Backend.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /Backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.2 2 | MAINTAINER linzecong 3 | ADD . ./Backend 4 | WORKDIR /Backend 5 | ENV DB_HOST "lpojdatabase" 6 | ENV DB_PASSWORD "lpojdatabase" 7 | ENV DB_USER 'root' 8 | ENV DB_PORT 3306 9 | RUN apt-get update && apt-get install python-django -y 10 | RUN pip install -r requirements.txt 11 | EXPOSE 8000 12 | CMD python manage.py makemigrations && python manage.py makemigrations judgestatus item problem user contest board blog wiki classes && python manage.py migrate && echo "from django.contrib.auth.models import User; User.objects.filter(email=\"admin@example.com\").delete(); User.objects.create_superuser(\"admin\", \"admin@example.com\", \"admin\")" | python manage.py shell && gunicorn -w 5 --bind 0.0.0.0:8000 -k 'gevent' Backend.wsgi:application 13 | 14 | -------------------------------------------------------------------------------- /Backend/ProblemData/README.md: -------------------------------------------------------------------------------- 1 | # 数据文件夹 2 | 3 | 所有数据将由后端保存在ProblemData中,因此目录结构不要改变!即 4 | 5 | Backend 6 | 7 | ----Backend 8 | 9 | ----ProblemData 10 | 11 | ----manage.py 12 | 13 | ...... 14 | 15 | 16 | 前端会通过后端将数据压缩包上传到这个文件夹,当然,你也可以手动上传。务必是zip文件,且zip内没有文件夹 -------------------------------------------------------------------------------- /Backend/README.md: -------------------------------------------------------------------------------- 1 | # 后端与数据库部署 2 | 3 | ## Docker部署 4 | 非专业用户不推荐使用Docker单独部署 5 | 修改Dockerfile中的ENV为你的数据库地址和密码等 6 | ``` 7 | docker build -t lpojbackend . 8 | docker run -d -p 8000:8000 lpojbackend 9 | ``` 10 | 11 | ## 一般部署 12 | 13 | 1. 首先安装Django 14 | ``` 15 | pip install django 16 | 17 | pip install djangorestframework 18 | 19 | pip install django-filter 20 | 21 | sudo apt-get install python-django 22 | 23 | pip install django-cors-headers 24 | 25 | pip install mysqlclient 26 | ``` 27 | 2. 安装数据库,已安装的可跳过 28 | ``` 29 | sudo apt-get install mysql-server 30 | 31 | mysql -uroot -p 32 | mysql > CREATE DATABASE LPOJ DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 33 | mysql > USE mysql 34 | mysql > GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION; 35 | mysql > ALTER user 'root'@'%' IDENTIFIED WITH mysql_native_password by 'your_password'; 36 | mysql > flush privileges; 37 | 38 | sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf 39 | 40 | #修改bind-address 为 0.0.0.0 41 | ``` 42 | 3. 部署后端 43 | ``` 44 | cd Backend 45 | 46 | cd Backend 47 | 48 | sudo nano setting.py 49 | # 修改数据库配置为你自己的数据库IP和用户名密码 50 | 51 | cd .. 52 | 53 | python manage.py makemigrations 54 | 55 | python manage.py migrate 56 | 57 | echo "from django.contrib.auth.models import User; User.objects.filter(email=\"admin@example.com\").delete(); User.objects.create_superuser(\"admin\", \"admin@example.com\", \"admin\")" | python manage.py shell 58 | 59 | python manage.py runserver 0.0.0.0:8000 60 | ``` 61 | 62 | 1. 添加管理员 63 | > 安装成功后,先通过IP:80访问OJ,注册一个用户 64 | > 65 | > 然后进入 IP:8000/admin 以用户名admin 密码admin 登录后台(请及时修改后台密码) 66 | > 67 | > 修改User表中,你注册的超级用户的type为3,使得你注册的用户变为超级管理员 -------------------------------------------------------------------------------- /Backend/blog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/blog/__init__.py -------------------------------------------------------------------------------- /Backend/blog/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/blog/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/blog/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Banner(models.Model): 4 | 5 | msg = models.CharField(max_length=500) 6 | time = models.DateField(auto_now=True) 7 | 8 | objects = models.Manager() 9 | 10 | def __str__(self): 11 | return self.username 12 | 13 | class OJMessage(models.Model): 14 | 15 | username = models.CharField(max_length=50) 16 | msg = models.CharField(max_length=500) 17 | time = models.DateField(auto_now=True) 18 | rating = models.IntegerField(default=1500) 19 | 20 | objects = models.Manager() 21 | 22 | def __str__(self): 23 | return self.username 24 | 25 | 26 | class Blog(models.Model): 27 | 28 | username = models.CharField(max_length=50) 29 | title = models.CharField(max_length=500) 30 | url = models.CharField(max_length=500) 31 | summary = models.CharField(max_length=1000) 32 | time = models.CharField(max_length=50) 33 | 34 | objects = models.Manager() 35 | 36 | def __str__(self): 37 | return self.username 38 | -------------------------------------------------------------------------------- /Backend/blog/permission.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from rest_framework import permissions 3 | from board.models import SettingBoard 4 | 5 | def getVisitorPermission(request): 6 | setting = SettingBoard.objects.filter(id=1) 7 | if len(setting) != 0: 8 | if setting[0].openvisitor is False: 9 | userid = request.session.get('user_id', None) 10 | if userid: 11 | return True 12 | else: 13 | return False 14 | else: 15 | return True 16 | else: 17 | return True 18 | 19 | class UserRatingOnly(permissions.BasePermission): 20 | def has_permission(self, request, view): 21 | if getVisitorPermission(request) == False: 22 | return False 23 | 24 | if request.method in permissions.SAFE_METHODS: 25 | return True 26 | data = request.data 27 | username = data.get('username') 28 | userid = request.session.get('user_id', None) 29 | r1 = data.get('rating') 30 | r2 = request.session.get('rating', None) 31 | if r1 != r2: 32 | return False 33 | if userid == username or request.session.get('type', 1) != 1: 34 | return True 35 | else: 36 | return False 37 | 38 | def has_object_permission(self, request, view, blog): 39 | if getVisitorPermission(request) == False: 40 | return False 41 | if request.method in permissions.SAFE_METHODS: 42 | return True 43 | data = request.data 44 | username = blog.username 45 | userid = request.session.get('user_id', None) 46 | r1 = blog.rating 47 | r2 = request.session.get('rating', None) 48 | if r1 != r2: 49 | return False 50 | if userid == username or request.session.get('type', 1) != 1: 51 | return True 52 | else: 53 | return False 54 | 55 | 56 | class ManagerOnly(permissions.BasePermission): 57 | def has_permission(self, request, view): 58 | if getVisitorPermission(request) == False: 59 | return False 60 | if request.method in permissions.SAFE_METHODS: 61 | return True 62 | 63 | type = request.session.get('type', 1) 64 | if type == 2 or type == 3: 65 | return True 66 | else: 67 | return False 68 | -------------------------------------------------------------------------------- /Backend/blog/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import OJMessage, Blog,Banner 4 | 5 | class BannerSerializer(serializers.ModelSerializer): 6 | class Meta: 7 | model = Banner 8 | fields = '__all__' 9 | 10 | class OJMessageSerializer(serializers.ModelSerializer): 11 | class Meta: 12 | model = OJMessage 13 | fields = '__all__' 14 | 15 | 16 | class BlogSerializer(serializers.ModelSerializer): 17 | class Meta: 18 | model = Blog 19 | fields = '__all__' 20 | -------------------------------------------------------------------------------- /Backend/blog/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('ojmessage', views.OJMessageView) 8 | routers.register('blog', views.BlogView) 9 | routers.register('banner', views.BannerView) 10 | 11 | urlpatterns = [ 12 | url('', include(routers.urls)), 13 | ] 14 | -------------------------------------------------------------------------------- /Backend/blog/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from rest_framework import viewsets 3 | from rest_framework.pagination import LimitOffsetPagination 4 | from rest_framework.throttling import ScopedRateThrottle 5 | from .models import OJMessage, Blog,Banner 6 | from .serializers import OJMessageSerializer, BlogSerializer,BannerSerializer 7 | from .permission import ManagerOnly, UserRatingOnly 8 | 9 | class BannerView(viewsets.ModelViewSet): 10 | queryset = Banner.objects.all().order_by("-id") 11 | serializer_class = BannerSerializer 12 | filter_fields = ('time',) 13 | permission_classes = (ManagerOnly,) 14 | pagination_class = LimitOffsetPagination 15 | throttle_scope = "post" 16 | throttle_classes = [ScopedRateThrottle, ] 17 | 18 | 19 | class OJMessageView(viewsets.ModelViewSet): 20 | queryset = OJMessage.objects.all().order_by("-id") 21 | serializer_class = OJMessageSerializer 22 | filter_fields = ('username', 'time') 23 | permission_classes = (UserRatingOnly,) 24 | pagination_class = LimitOffsetPagination 25 | throttle_scope = "post" 26 | throttle_classes = [ScopedRateThrottle, ] 27 | 28 | 29 | class BlogView(viewsets.ModelViewSet): 30 | queryset = Blog.objects.all().order_by("-id") 31 | serializer_class = BlogSerializer 32 | filter_fields = ('username', 'time') 33 | pagination_class = LimitOffsetPagination 34 | permission_classes = (ManagerOnly,) 35 | throttle_scope = "post" 36 | throttle_classes = [ScopedRateThrottle, ] 37 | -------------------------------------------------------------------------------- /Backend/board/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/board/__init__.py -------------------------------------------------------------------------------- /Backend/board/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/board/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/board/permission.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from rest_framework import permissions 3 | from board.models import SettingBoard 4 | 5 | def getVisitorPermission(request): 6 | setting = SettingBoard.objects.filter(id=1) 7 | if len(setting) != 0: 8 | if setting[0].openvisitor is False: 9 | userid = request.session.get('user_id', None) 10 | if userid: 11 | return True 12 | else: 13 | return False 14 | else: 15 | return True 16 | else: 17 | return True 18 | 19 | class ManagerOnly(permissions.BasePermission): 20 | def has_permission(self, request, view): 21 | if getVisitorPermission(request) == False: 22 | return False 23 | if request.method in permissions.SAFE_METHODS: 24 | return True 25 | 26 | type = request.session.get('type', 1) 27 | if type == 2 or type == 3: 28 | return True 29 | else: 30 | return False 31 | -------------------------------------------------------------------------------- /Backend/board/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import Board, DailyBoard, TeamBoard, DailyContestBoard,SettingBoard 4 | 5 | 6 | class SettingBoardSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = SettingBoard 9 | fields = '__all__' 10 | 11 | 12 | class BoardSerializer(serializers.ModelSerializer): 13 | class Meta: 14 | model = Board 15 | fields = '__all__' 16 | 17 | 18 | class DailyBoardSerializer(serializers.ModelSerializer): 19 | class Meta: 20 | model = DailyBoard 21 | fields = '__all__' 22 | 23 | 24 | class TeamBoardSerializer(serializers.ModelSerializer): 25 | class Meta: 26 | model = TeamBoard 27 | fields = '__all__' 28 | 29 | 30 | class DailyContestBoardSerializer(serializers.ModelSerializer): 31 | class Meta: 32 | model = DailyContestBoard 33 | fields = '__all__' 34 | -------------------------------------------------------------------------------- /Backend/board/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('board', views.BoardView) 8 | routers.register('dailyboard', views.DailyBoardView) 9 | routers.register('teamboard', views.TeamBoardView) 10 | routers.register('dailycontestboard', views.DailyContestBoardView) 11 | routers.register('settingboard', views.SettingBoardView) 12 | 13 | urlpatterns = [ 14 | url('', include(routers.urls)), 15 | ] 16 | -------------------------------------------------------------------------------- /Backend/board/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from rest_framework import viewsets 3 | from rest_framework.throttling import ScopedRateThrottle 4 | from rest_framework.pagination import LimitOffsetPagination 5 | from .serializers import BoardSerializer,SettingBoardSerializer, DailyBoardSerializer, TeamBoardSerializer, DailyContestBoardSerializer 6 | from .permission import ManagerOnly 7 | from .models import Board, DailyBoard, TeamBoard, DailyContestBoard,SettingBoard 8 | import datetime 9 | 10 | class SettingBoardView(viewsets.ModelViewSet): 11 | queryset = SettingBoard.objects.all() 12 | serializer_class = SettingBoardSerializer 13 | permission_classes = (ManagerOnly,) 14 | throttle_scope = "post" 15 | throttle_classes = [ScopedRateThrottle, ] 16 | 17 | 18 | class BoardView(viewsets.ModelViewSet): 19 | queryset = Board.objects.all() 20 | serializer_class = BoardSerializer 21 | filter_fields = ('username',) 22 | pagination_class = LimitOffsetPagination 23 | permission_classes = (ManagerOnly,) 24 | throttle_scope = "post" 25 | throttle_classes = [ScopedRateThrottle, ] 26 | 27 | 28 | 29 | class DailyBoardView(viewsets.ModelViewSet): 30 | queryset = DailyBoard.objects.filter(collecttime__gte=datetime.datetime.now( 31 | )-datetime.timedelta(days=10)).order_by('collecttime') # 这里有bug,不应该在queryset里写filter。时间会提前算好,导致不准确 32 | serializer_class = DailyBoardSerializer 33 | filter_fields = ('username', 'collecttime') 34 | pagination_class = LimitOffsetPagination 35 | permission_classes = (ManagerOnly,) 36 | throttle_scope = "post" 37 | throttle_classes = [ScopedRateThrottle, ] 38 | 39 | 40 | class TeamBoardView(viewsets.ModelViewSet): 41 | queryset = TeamBoard.objects.all() 42 | serializer_class = TeamBoardSerializer 43 | filter_fields = ('teammember', 'collecttime') 44 | pagination_class = LimitOffsetPagination 45 | permission_classes = (ManagerOnly,) 46 | throttle_scope = "post" 47 | throttle_classes = [ScopedRateThrottle, ] 48 | 49 | 50 | class DailyContestBoardView(viewsets.ModelViewSet): 51 | queryset = DailyContestBoard.objects.all() 52 | serializer_class = DailyContestBoardSerializer 53 | filter_fields = ('contestdate', 'teammember') 54 | pagination_class = LimitOffsetPagination 55 | permission_classes = (ManagerOnly,) 56 | throttle_scope = "post" 57 | throttle_classes = [ScopedRateThrottle, ] 58 | -------------------------------------------------------------------------------- /Backend/classes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/classes/__init__.py -------------------------------------------------------------------------------- /Backend/classes/admin.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | 4 | from django.contrib import admin 5 | # Register your models here. 6 | 7 | -------------------------------------------------------------------------------- /Backend/classes/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/classes/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/classes/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db import models 3 | # Create your models here. 4 | class ClassStudentData(models.Model): 5 | studentUserName = models.CharField(max_length=50, null=False,default="") 6 | studentNumber = models.CharField(max_length=50, null=False) 7 | className = models.CharField(max_length=50, null=False) 8 | studentRealName = models.CharField(max_length=50, null=False) 9 | 10 | objects = models.Manager() 11 | 12 | def __str__(self): 13 | return self.studentUserName 14 | 15 | class theClasses(models.Model): 16 | className = models.CharField(max_length=50,default="None") 17 | classSize = models.CharField(max_length=50, default="None") 18 | canjoinclass = models.CharField(max_length=50, default="open") 19 | 20 | objects = models.Manager() 21 | 22 | def __str__(self): 23 | return self.className 24 | -------------------------------------------------------------------------------- /Backend/classes/permission.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from rest_framework import permissions 3 | from .models import ClassStudentData, theClasses 4 | 5 | from board.models import SettingBoard 6 | import datetime 7 | 8 | def getVisitorPermission(request): 9 | setting = SettingBoard.objects.filter(id=1) 10 | if len(setting) != 0: 11 | if setting[0].openvisitor is False: 12 | userid = request.session.get('user_id', None) 13 | if userid: 14 | return True 15 | else: 16 | return False 17 | else: 18 | return True 19 | else: 20 | return True 21 | 22 | class ManagerOnly(permissions.BasePermission): 23 | def has_permission(self, request, view): 24 | if getVisitorPermission(request) == False: 25 | return False 26 | type = request.session.get('type', 1) 27 | if type == 2 or type == 3: 28 | return True 29 | 30 | if request.method in permissions.SAFE_METHODS: 31 | return True 32 | 33 | return False 34 | -------------------------------------------------------------------------------- /Backend/classes/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import theClasses,ClassStudentData 4 | class ClassDataSerializer(serializers.ModelSerializer): 5 | class Meta: 6 | model = theClasses 7 | fields = '__all__' 8 | 9 | class ClassStudentDataSerializer(serializers.ModelSerializer): 10 | class Meta: 11 | model = ClassStudentData 12 | fields = '__all__' 13 | 14 | 15 | -------------------------------------------------------------------------------- /Backend/classes/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('classes', views.ClassDataView) 8 | routers.register('classStudent', views.ClassStudentDataView) 9 | 10 | urlpatterns = [ 11 | url('', include(routers.urls)), 12 | url(r'^ADDclasses', views.ClassDataAPIView.as_view()), 13 | url(r'^AddClass', views.ClassStudentDataAPIView.as_view()), 14 | url(r'^DeleteClass', views.DeleteClassDataAPIView.as_view()), 15 | ] 16 | -------------------------------------------------------------------------------- /Backend/contest/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/contest/__init__.py -------------------------------------------------------------------------------- /Backend/contest/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/contest/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/contest/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import ContestAnnouncement,ContestTutorial, ContestComingInfo, ContestRatingChange, ContestBoard, ContestComment, ContestInfo, ContestProblem, ContestRegister, ContestBoardTotal, StudentChoiceAnswer,ContestChoiceProblem 4 | 5 | 6 | class ContestAnnouncementSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = ContestAnnouncement 9 | fields = '__all__' 10 | 11 | class ContestTutorialSerializer(serializers.ModelSerializer): 12 | class Meta: 13 | model = ContestTutorial 14 | fields = '__all__' 15 | 16 | 17 | class ContestBoardSerializer(serializers.ModelSerializer): 18 | class Meta: 19 | model = ContestBoard 20 | fields = '__all__' 21 | 22 | 23 | class ContestCommentSerializer(serializers.ModelSerializer): 24 | class Meta: 25 | model = ContestComment 26 | fields = '__all__' 27 | 28 | 29 | class ContestInfoSerializer(serializers.ModelSerializer): 30 | class Meta: 31 | model = ContestInfo 32 | fields = '__all__' 33 | 34 | 35 | class ContestProblemSerializer(serializers.ModelSerializer): 36 | class Meta: 37 | model = ContestProblem 38 | fields = '__all__' 39 | 40 | 41 | class ContestRegisterSerializer(serializers.ModelSerializer): 42 | class Meta: 43 | model = ContestRegister 44 | fields = '__all__' 45 | 46 | 47 | class ContestRatingChangeSerializer(serializers.ModelSerializer): 48 | class Meta: 49 | model = ContestRatingChange 50 | fields = '__all__' 51 | 52 | 53 | class ContestComingInfoSerializer(serializers.ModelSerializer): 54 | class Meta: 55 | model = ContestComingInfo 56 | fields = '__all__' 57 | 58 | class ContestBoardTotalSerializer(serializers.ModelSerializer): 59 | class Meta: 60 | model = ContestBoardTotal 61 | fields = '__all__' 62 | 63 | class StudentChoiceAnswerSerializer(serializers.ModelSerializer): 64 | class Meta: 65 | model = StudentChoiceAnswer 66 | fields = '__all__' 67 | 68 | class ContestChoiceProblemSerializer(serializers.ModelSerializer): 69 | class Meta: 70 | model = ContestChoiceProblem 71 | fields = '__all__' 72 | -------------------------------------------------------------------------------- /Backend/contest/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('contestannouncement', views.ContestAnnouncementView) 8 | routers.register('contestcomment', views.ContestCommentView) 9 | routers.register('contestinfo', views.ContestInfoView) 10 | routers.register('contestcominginfo', views.ContestComingInfoView) 11 | routers.register('contestproblem', views.ContestProblemView) 12 | routers.register('contestboard', views.ContestBoardView) 13 | routers.register('contestregister', views.ContestRegisterView) 14 | routers.register('contestratingchange', views.ContestRatingChangeView) 15 | routers.register('contesttutorial', views.ContestTutorialView) 16 | routers.register('contesttotalboard', views.ContestBoardTotalView) 17 | routers.register('conteststudentchoiceanswer', views.StudentChoiceAnswerView) 18 | routers.register('contestchoiceproblem', views.ContestChoiceProblemView) 19 | 20 | urlpatterns = [ 21 | url('', include(routers.urls)), 22 | url(r'^currenttime', views.CurrentTimeView.as_view()), 23 | url(r'^contestfilterboard', views.ContestBoardFilterAPIView.as_view()), 24 | url(r'^getcontestchoiceproblems', views.GetContestChoiceProblems.as_view()), 25 | url(r'^scorecontestchoiceproblems', views.ScoreContestChoiceProblems.as_view()), 26 | url(r'^isboardlock', views.ContestIsBoardLockAPIView.as_view()), 27 | 28 | ] 29 | -------------------------------------------------------------------------------- /Backend/item/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/item/__init__.py -------------------------------------------------------------------------------- /Backend/item/admin.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.contrib import admin 4 | from .models import Item 5 | 6 | admin.site.register(Item) -------------------------------------------------------------------------------- /Backend/item/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/item/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/item/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db import models 3 | from user.models import User 4 | import datetime 5 | 6 | class Item(models.Model): 7 | user = models.ForeignKey(User, on_delete=models.CASCADE) 8 | title = models.TextField(default="待补题",null=False) 9 | detail = models.TextField(null=True,blank=True) 10 | createtime = models.DateTimeField(null=False,default=datetime.datetime.now) 11 | deadtime = models.DateTimeField(null=True,default=datetime.datetime.now) 12 | status = models.IntegerField(default=1) # 1 新建 0 已完成 13 | tag = models.IntegerField(default=1) # 1 便签 # 2 待办事项 # 3 待补题 14 | 15 | objects = models.Manager() 16 | 17 | def __str__(self): 18 | 19 | return self.title 20 | 21 | -------------------------------------------------------------------------------- /Backend/item/permission.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from rest_framework import permissions 3 | from .models import User 4 | 5 | from board.models import SettingBoard 6 | 7 | 8 | def getWikiPermission(): 9 | setting = SettingBoard.objects.filter(id=1) 10 | if len(setting) != 0: 11 | if setting[0].openwiki is False: 12 | return False 13 | else: 14 | return True 15 | else: 16 | return False 17 | 18 | def getVisitorPermission(request): 19 | setting = SettingBoard.objects.filter(id=1) 20 | if len(setting) != 0: 21 | if setting[0].openvisitor is False: 22 | userid = request.session.get('user_id', None) 23 | if userid: 24 | return True 25 | else: 26 | return False 27 | else: 28 | return True 29 | else: 30 | return True 31 | 32 | class UserOnly(permissions.BasePermission): 33 | def has_permission(self, request, view): 34 | if getVisitorPermission(request) == False: 35 | return False 36 | 37 | if getWikiPermission() == False: 38 | return False 39 | 40 | if request.method == "DELETE": 41 | return True 42 | if request.method == "GET": 43 | return False 44 | else: 45 | data = request.data 46 | username = str(data.get('user')) 47 | userid = request.session.get('user_id', None) 48 | if userid == username: 49 | return True 50 | else: 51 | return False 52 | 53 | def has_object_permission(self, request, view, item): 54 | if getVisitorPermission(request) == False: 55 | return False 56 | 57 | if getWikiPermission() == False: 58 | return False 59 | 60 | if request.method == "GET": 61 | return False 62 | else: 63 | username = str(item.user.username) 64 | userid = request.session.get('user_id', None) 65 | if userid == username: 66 | return True 67 | else: 68 | return False 69 | 70 | -------------------------------------------------------------------------------- /Backend/item/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import Item 4 | 5 | class ItemSerializer(serializers.ModelSerializer): 6 | 7 | class Meta: 8 | model = Item 9 | fields = '__all__' 10 | 11 | -------------------------------------------------------------------------------- /Backend/item/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('putitem', views.ItemPutView) 8 | 9 | urlpatterns = [ 10 | url('', include(routers.urls)), 11 | url(r'^item', views.ItemGetAPIView.as_view()), 12 | ] 13 | -------------------------------------------------------------------------------- /Backend/item/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django_filters.rest_framework import DjangoFilterBackend 3 | from django.contrib.auth.hashers import make_password, check_password 4 | from rest_framework import viewsets,filters,generics,mixins 5 | from rest_framework.permissions import AllowAny 6 | from rest_framework.response import Response 7 | from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST 8 | from rest_framework.views import APIView 9 | from rest_framework.pagination import LimitOffsetPagination 10 | from rest_framework.throttling import ScopedRateThrottle 11 | from .models import Item 12 | from .serializers import ItemSerializer 13 | from .permission import UserOnly 14 | from board.models import SettingBoard 15 | 16 | 17 | def getWikiPermission(): 18 | setting = SettingBoard.objects.filter(id=1) 19 | if len(setting) != 0: 20 | if setting[0].openwiki is False: 21 | return False 22 | else: 23 | return True 24 | else: 25 | return False 26 | 27 | class ItemPutView(viewsets.ModelViewSet): 28 | queryset = Item.objects.all() 29 | serializer_class = ItemSerializer 30 | permission_classes = (UserOnly,) 31 | 32 | class ItemGetAPIView(generics.GenericAPIView): 33 | queryset = Item.objects.all() 34 | serializer_class = ItemSerializer 35 | permission_classes = (AllowAny,) 36 | 37 | def get(self, request, format=None): 38 | if getWikiPermission() == False: 39 | return Response("not open!", HTTP_400_BAD_REQUEST) 40 | username = request.session.get('user_id', None) 41 | user = Item.objects.filter(user=username) 42 | serializer = ItemSerializer(user, many=True) 43 | return Response(serializer.data, HTTP_200_OK) 44 | -------------------------------------------------------------------------------- /Backend/judgestatus/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/judgestatus/__init__.py -------------------------------------------------------------------------------- /Backend/judgestatus/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/judgestatus/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/judgestatus/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from django.db import models 4 | 5 | 6 | class JudgeStatus(models.Model): 7 | 8 | user = models.CharField(max_length=50) 9 | oj = models.CharField(max_length=50, default="LPOJ") 10 | problem = models.CharField(max_length=50) 11 | result = models.IntegerField() 12 | time = models.IntegerField() 13 | memory = models.IntegerField() 14 | length = models.IntegerField() 15 | language = models.CharField(max_length=50) 16 | submittime = models.DateTimeField() 17 | judger = models.CharField(max_length=50) 18 | contest = models.IntegerField() 19 | contestproblem = models.IntegerField(default=-1) # 对应比赛里的哪一题 20 | code = models.TextField(max_length=200000) 21 | testcase = models.CharField(max_length=50, default="0") 22 | message = models.TextField() # 也作为 其他OJ 的 proid 23 | problemtitle = models.CharField(max_length=100, default="") 24 | rating = models.IntegerField(default=1500) 25 | ip = models.CharField(max_length=50, default="无法获取ip") 26 | 27 | objects = models.Manager() 28 | 29 | def __str__(self): 30 | return self.user 31 | 32 | 33 | class CaseStatus(models.Model): 34 | 35 | statusid = models.IntegerField() 36 | username = models.CharField(max_length=50) 37 | problem = models.CharField(max_length=50) 38 | result = models.CharField(max_length=500, default="System Error") 39 | time = models.IntegerField(default=0) 40 | memory = models.IntegerField(default=0) 41 | testcase = models.CharField(max_length=500, default="unknow") 42 | casedata = models.CharField(max_length=500) # 非比赛才能查看,Judger中控制 43 | outputdata = models.CharField( 44 | max_length=500, default="") # 非比赛才能查看,Judger中控制 45 | useroutput = models.CharField( 46 | max_length=500, default="") # 非比赛才能查看,Judger中控制 47 | 48 | objects = models.Manager() 49 | 50 | def __str__(self): 51 | return self.statusid 52 | -------------------------------------------------------------------------------- /Backend/judgestatus/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from rest_framework import serializers 4 | from .models import JudgeStatus, CaseStatus 5 | 6 | 7 | class JudgeStatusSerializer(serializers.ModelSerializer): 8 | class Meta: 9 | model = JudgeStatus 10 | exclude = ['code', 'message'] 11 | 12 | 13 | class JudgeStatusCodeSerializer(serializers.ModelSerializer): 14 | class Meta: 15 | model = JudgeStatus 16 | fields = '__all__' 17 | 18 | 19 | class CaseStatusSerializer(serializers.ModelSerializer): 20 | class Meta: 21 | model = CaseStatus 22 | fields = '__all__' 23 | -------------------------------------------------------------------------------- /Backend/judgestatus/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('judgestatus', views.JudgeStatusView) 8 | routers.register('judgestatusput', views.JudgeStatusPutView) 9 | routers.register('judgestatuscode', views.JudgeStatusCodeView) 10 | routers.register('casestatus', views.CaseStatusView) 11 | routers.register('acrank', views.ACRankView) 12 | 13 | urlpatterns = [ 14 | url('', include(routers.urls)), 15 | url(r'^rejudge', views.RejudgeAPIView.as_view()), 16 | ] 17 | -------------------------------------------------------------------------------- /Backend/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Backend.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /Backend/problem/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/problem/__init__.py -------------------------------------------------------------------------------- /Backend/problem/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/problem/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/problem/permission.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from rest_framework import permissions 3 | 4 | from board.models import SettingBoard 5 | 6 | def getVisitorPermission(request): 7 | setting = SettingBoard.objects.filter(id=1) 8 | if len(setting) != 0: 9 | if setting[0].openvisitor is False: 10 | userid = request.session.get('user_id', None) 11 | if userid: 12 | return True 13 | else: 14 | return False 15 | else: 16 | return True 17 | else: 18 | return True 19 | 20 | class ManagerOnly(permissions.BasePermission): 21 | def has_permission(self, request, view): 22 | if getVisitorPermission(request) == False: 23 | return False 24 | if request.method in permissions.SAFE_METHODS: 25 | return True 26 | 27 | type = request.session.get('type', 1) 28 | if type == 2 or type == 3: 29 | return True 30 | else: 31 | return False 32 | 33 | 34 | class AuthOnly(permissions.BasePermission): 35 | def has_permission(self, request, view): 36 | if getVisitorPermission(request) == False: 37 | return False 38 | if request.method in permissions.SAFE_METHODS: 39 | return True 40 | type = request.session.get('type', 1) 41 | if type == 2 or type == 3: 42 | return True 43 | else: 44 | return False 45 | 46 | def has_object_permission(self, request, view, problem): 47 | if getVisitorPermission(request) == False: 48 | return False 49 | type = request.session.get('type', 1) 50 | if type == 2 or type == 3: 51 | return True 52 | return problem.auth == 1 or problem.auth == 3 53 | -------------------------------------------------------------------------------- /Backend/problem/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import Problem, ProblemData, ProblemTag,ChoiceProblem 4 | 5 | 6 | class ProblemSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = Problem 9 | fields = '__all__' 10 | 11 | class ChoiceProblemSerializer(serializers.ModelSerializer): 12 | class Meta: 13 | model = ChoiceProblem 14 | fields = '__all__' 15 | 16 | 17 | class ProblemDataSerializer(serializers.ModelSerializer): 18 | class Meta: 19 | model = ProblemData 20 | fields = '__all__' 21 | 22 | 23 | class ProblemTagSerializer(serializers.ModelSerializer): 24 | class Meta: 25 | model = ProblemTag 26 | fields = '__all__' 27 | 28 | -------------------------------------------------------------------------------- /Backend/problem/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('problem', views.ProblemView) 8 | routers.register('problemdata', views.ProblemDataView) 9 | routers.register('problemtag', views.ProblemTagView) 10 | routers.register('choiceproblem', views.ChoiceProblemView) 11 | 12 | urlpatterns = [ 13 | url('', include(routers.urls)), 14 | url(r'^uploadfile', views.UploadFileAPIView.as_view()), 15 | url(r'^downloadfile/',views.filedown,name='download'), 16 | url(r'^showpic/',views.showpic,name='show_picture'), 17 | url(r'^judgerdownloadfile/',views.judgerfiledown,name='judgerfiledown'), 18 | url(r'^judgerfiletime/',views.judgerfiletime,name='judgerfiletime'), 19 | ] 20 | -------------------------------------------------------------------------------- /Backend/requirements.txt: -------------------------------------------------------------------------------- 1 | Django==2.2.8 2 | djangorestframework==3.9.3 3 | django-filter==2.1.0 4 | django-cors-headers==2.5.3 5 | mysqlclient==1.4.2.post1 6 | django-sslserver 7 | gevent 8 | gunicorn==19.9.0 -------------------------------------------------------------------------------- /Backend/user/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/user/__init__.py -------------------------------------------------------------------------------- /Backend/user/admin.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.contrib import admin 4 | from .models import User,UserData 5 | 6 | admin.site.register(User) 7 | admin.site.register(UserData) -------------------------------------------------------------------------------- /Backend/user/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/user/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/user/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.db import models 3 | class User(models.Model): 4 | username = models.CharField(max_length=50, null=False, primary_key=True) 5 | password = models.CharField(max_length=50, null=False) 6 | name = models.CharField(max_length=50, null=False) # 名称 7 | regtime = models.DateTimeField(auto_now=True) 8 | logintime = models.DateTimeField(auto_now=True) 9 | school = models.CharField(max_length=50, null=False, default="") 10 | course = models.CharField(max_length=50, null=False, default="") 11 | classes = models.CharField(max_length=50, null=False, default="") #行政班 12 | number = models.CharField(max_length=50, null=False, default="") 13 | realname = models.CharField(max_length=50, null=False) 14 | qq = models.CharField(max_length=50, null=True, default="") 15 | email = models.CharField(max_length=50, null=True, default="") 16 | type = models.IntegerField(null=False, default=1) # 1 普通 2 管理员 3 超级管理员 17 | 18 | objects = models.Manager() 19 | 20 | def __str__(self): 21 | return self.username 22 | 23 | 24 | class UserData(models.Model): 25 | username = models.CharField(max_length=50, null=False, primary_key=True) 26 | ac = models.IntegerField(null=False, default=0) 27 | submit = models.IntegerField(null=False, default=0) 28 | score = models.IntegerField(default=0) 29 | des = models.CharField(max_length=50, null=True) 30 | rating = models.IntegerField(default=1500) 31 | acpro = models.TextField(null=True, default="") 32 | 33 | objects = models.Manager() 34 | 35 | def __str__(self): 36 | return self.username 37 | 38 | class UserLoginData(models.Model): 39 | username = models.CharField(max_length=50, null=False) 40 | ip = models.CharField(max_length=50, null=True,default="unknow") 41 | logintime = models.DateTimeField(auto_now=True) 42 | msg = models.TextField(null=True) 43 | 44 | objects = models.Manager() 45 | 46 | def __str__(self): 47 | return self.username 48 | 49 | 50 | -------------------------------------------------------------------------------- /Backend/user/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import User, UserData, UserLoginData 4 | 5 | class UserLoginDataSerializer(serializers.ModelSerializer): 6 | class Meta: 7 | model = UserLoginData 8 | fields = '__all__' 9 | 10 | class UserSerializer(serializers.ModelSerializer): 11 | class Meta: 12 | model = User 13 | fields = '__all__' 14 | 15 | 16 | class UserNoPassSerializer(serializers.ModelSerializer): 17 | class Meta: 18 | model = User 19 | exclude = ['password'] 20 | 21 | 22 | class UserNoTypeSerializer(serializers.ModelSerializer): 23 | class Meta: 24 | model = User 25 | exclude = ['type'] 26 | 27 | 28 | class UserDataSerializer(serializers.ModelSerializer): 29 | class Meta: 30 | model = UserData 31 | fields = '__all__' 32 | -------------------------------------------------------------------------------- /Backend/user/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('userdata', views.UserDataView) 8 | routers.register('user', views.UserView) 9 | #routers.register('change', views.UserChangeView) 10 | #routers.register('changeall', views.UserChangeAllView) 11 | routers.register('userlogindata', views.UserLoginDataView) 12 | 13 | urlpatterns = [ 14 | url('', include(routers.urls)), 15 | url(r'^register', views.UserRegisterAPIView.as_view()), 16 | url(r'^login', views.UserLoginAPIView.as_view()), 17 | url(r'^logout', views.UserLogoutAPIView.as_view()), 18 | url(r'^updaterating', views.UserUpdateRatingAPIView.as_view()), 19 | url(r'^setlogindata', views.UserLoginDataAPIView.as_view()), 20 | url(r'^changeone', views.UserChangeView.as_view()), 21 | url(r'^changeall', views.UserChangeAllView.as_view()), 22 | ] 23 | -------------------------------------------------------------------------------- /Backend/wiki/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/wiki/__init__.py -------------------------------------------------------------------------------- /Backend/wiki/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Backend/wiki/migrations/__init__.py -------------------------------------------------------------------------------- /Backend/wiki/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Wiki(models.Model): 5 | 6 | username = models.CharField(max_length=50, default="std") # 发布人的用户名 7 | type = models.CharField(max_length=50) # 发布了哪篇文章 8 | value = models.TextField(default="暂无文本") 9 | time = models.DateTimeField(auto_now=True) 10 | group = models.CharField(max_length=50, null=True, default="") # 新添加的算法的分类 11 | std = models.IntegerField(default=0) # 是否是标准算法,0代表是,1代表新添加的算法 12 | title = models.CharField(max_length=50, null=True, default="") # 新添加的算法标题 13 | 14 | objects = models.Manager() 15 | 16 | def __str__(self): 17 | return self.username 18 | 19 | 20 | class MBCode(models.Model): 21 | 22 | username = models.CharField( 23 | max_length=50, default="std", primary_key=True) # 发布人的用户名 24 | des = models.CharField(max_length=500) 25 | time = models.DateTimeField(auto_now=True) 26 | 27 | objects = models.Manager() 28 | 29 | def __str__(self): 30 | return self.username 31 | 32 | 33 | class MBCodeDetail(models.Model): 34 | 35 | username = models.CharField(max_length=50, default="std") # 发布人的用户名 36 | title = models.CharField(max_length=50) 37 | des = models.CharField(max_length=1000, default="none") 38 | group = models.CharField(max_length=50, default="none") 39 | code = models.TextField(default="暂无代码") 40 | time = models.DateTimeField(auto_now=True) 41 | 42 | objects = models.Manager() 43 | 44 | def __str__(self): 45 | return self.username 46 | 47 | 48 | class TrainningContest(models.Model): 49 | 50 | title = models.CharField(max_length=50) # 标题 51 | des = models.CharField(max_length=500) 52 | tips = models.CharField(max_length=500, null=True, 53 | blank=True, default="") # 教程 | 隔开 54 | group = models.IntegerField() # 第几章 55 | num = models.IntegerField() # 第几关 56 | problem = models.CharField( 57 | max_length=500, null=True, blank=True, default="") # 题目 | 隔开 58 | 59 | objects = models.Manager() 60 | 61 | def __str__(self): 62 | return self.title 63 | -------------------------------------------------------------------------------- /Backend/wiki/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework import serializers 3 | from .models import Wiki, MBCode, MBCodeDetail, TrainningContest 4 | 5 | 6 | class WikiSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = Wiki 9 | fields = '__all__' 10 | 11 | 12 | class WikiCountSerializer(serializers.ModelSerializer): 13 | class Meta: 14 | model = Wiki 15 | exclude = ['value'] 16 | 17 | 18 | class MBCodeSerializer(serializers.ModelSerializer): 19 | class Meta: 20 | model = MBCode 21 | fields = '__all__' 22 | 23 | 24 | class MBCodeDetailSerializer(serializers.ModelSerializer): 25 | class Meta: 26 | model = MBCodeDetail 27 | fields = '__all__' 28 | 29 | 30 | class MBCodeDetailNoCodeSerializer(serializers.ModelSerializer): 31 | class Meta: 32 | model = MBCodeDetail 33 | exclude = ['code'] 34 | 35 | 36 | class TrainningContestSerializer(serializers.ModelSerializer): 37 | class Meta: 38 | model = TrainningContest 39 | fields = '__all__' 40 | -------------------------------------------------------------------------------- /Backend/wiki/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from django.conf.urls import url, include 3 | from . import views 4 | from rest_framework import routers 5 | 6 | routers = routers.DefaultRouter() 7 | routers.register('wiki', views.WikiView) 8 | routers.register('wikicount', views.WikiCountView) 9 | routers.register('mbcode', views.MBCodeView) 10 | routers.register('mbcodedetail', views.MBCodeDetailView) 11 | routers.register('mbcodedetailnocode', views.MBCodeDetailNoCodeView) 12 | routers.register('trainning', views.TrainningContestView) 13 | 14 | urlpatterns = [ 15 | url('', include(routers.urls)), 16 | ] 17 | -------------------------------------------------------------------------------- /Backend/wiki/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework.throttling import ScopedRateThrottle 2 | from rest_framework import viewsets 3 | from .serializers import TrainningContestSerializer, WikiSerializer, WikiCountSerializer, MBCodeSerializer, MBCodeDetailSerializer, MBCodeDetailNoCodeSerializer 4 | from .permission import UserOnly, ManagerOnly, WikiUserOnly 5 | from .models import Wiki, MBCode, MBCodeDetail, TrainningContest 6 | 7 | 8 | class WikiView(viewsets.ModelViewSet): 9 | queryset = Wiki.objects.all() 10 | serializer_class = WikiSerializer 11 | filter_fields = ('username', 'type', 'group', 'std',) 12 | permission_classes = (WikiUserOnly,) 13 | throttle_scope = "post" 14 | throttle_classes = [ScopedRateThrottle, ] 15 | 16 | 17 | class WikiCountView(viewsets.ModelViewSet): 18 | queryset = Wiki.objects.all() 19 | serializer_class = WikiCountSerializer 20 | filter_fields = ('username', 'type') 21 | permission_classes = (UserOnly,) 22 | throttle_scope = "post" 23 | throttle_classes = [ScopedRateThrottle, ] 24 | 25 | 26 | class MBCodeView(viewsets.ModelViewSet): 27 | queryset = MBCode.objects.all() 28 | serializer_class = MBCodeSerializer 29 | filter_fields = ('username',) 30 | permission_classes = (UserOnly,) 31 | throttle_scope = "post" 32 | throttle_classes = [ScopedRateThrottle, ] 33 | 34 | 35 | class MBCodeDetailView(viewsets.ModelViewSet): 36 | queryset = MBCodeDetail.objects.all() 37 | serializer_class = MBCodeDetailSerializer 38 | filter_fields = ('username', 'group', 'des', 'title') 39 | permission_classes = (UserOnly,) 40 | throttle_scope = "post" 41 | throttle_classes = [ScopedRateThrottle, ] 42 | 43 | 44 | class MBCodeDetailNoCodeView(viewsets.ModelViewSet): 45 | queryset = MBCodeDetail.objects.all() 46 | serializer_class = MBCodeDetailNoCodeSerializer 47 | filter_fields = ('username', 'group', 'des', 'title') 48 | permission_classes = (UserOnly,) 49 | throttle_scope = "post" 50 | throttle_classes = [ScopedRateThrottle, ] 51 | 52 | 53 | class TrainningContestView(viewsets.ModelViewSet): 54 | queryset = TrainningContest.objects.all().order_by("num") 55 | serializer_class = TrainningContestSerializer 56 | filter_fields = ('group', 'title',) 57 | permission_classes = (ManagerOnly,) 58 | throttle_scope = "post" 59 | throttle_classes = [ScopedRateThrottle, ] 60 | -------------------------------------------------------------------------------- /CrawlingServer/CodeForceContestCounter.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import datetime 3 | import json 4 | 5 | # 返回一个月内的cf场数和上/掉分情况 6 | def get_CF_ContestCount(name): 7 | apiUrl = "https://codeforces.com/api/user.rating?handle=" + name 8 | 9 | try: 10 | page = urllib.request.urlopen(apiUrl, timeout=2000) 11 | s = page.read().decode('utf-8') 12 | contestsData = json.loads(s)['result'] 13 | 14 | # 改为直接用rating变化的时间当做比赛时间 15 | # 由于rating变化时间一般延迟一天,放宽到32天 16 | lastTime=(datetime.timedelta(days=-32) + 17 | datetime.datetime.now()).timestamp() 18 | 19 | sum=0 20 | cnt=0 21 | for contest in contestsData: 22 | if contest['ratingUpdateTimeSeconds'] < lastTime: 23 | continue 24 | cnt += 1 25 | sum += contest['newRating'] - contest['oldRating'] 26 | return [cnt, sum] 27 | 28 | except Exception as e: 29 | print(str(e)) 30 | return [-1, -1] 31 | 32 | if __name__ == "__main__": 33 | while(True): 34 | name=input("请输入要爬的ID:") 35 | print(get_CF_ContestCount(name)) 36 | -------------------------------------------------------------------------------- /CrawlingServer/Codeforces.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import json 3 | def get_CF_data(name): 4 | api_url = "http://codeforces.com/api/user.status?handle="+name 5 | try: 6 | response = urllib.request.urlopen(api_url,timeout=2000) 7 | response_data=response.read() 8 | 9 | response_data = json.loads(response_data) 10 | 11 | # print(response_data) 12 | acpro = set() 13 | attpro = set() 14 | 15 | for data in response_data["result"]: 16 | if data["verdict"]=="OK": 17 | acpro.add(str(data["problem"]["contestId"])+str(data["problem"]["index"])) 18 | attpro.add(str(data["problem"]["contestId"])+str(data["problem"]["index"])) 19 | return [len(acpro),len(attpro)] 20 | except: 21 | return [-1,-1] 22 | 23 | if __name__ == "__main__": 24 | while(True): 25 | name = input("请输入要爬的ID:") 26 | print(get_CF_data(name)) -------------------------------------------------------------------------------- /CrawlingServer/CodeforcesRate.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import re 3 | 4 | def get_CF_Rate(name): 5 | api_url = "https://codeforces.com/profile/"+name 6 | try: 7 | response = urllib.request.urlopen(api_url,timeout=2000) 8 | response_data=response.read().decode('utf-8') 9 | 10 | score = re.findall('([0-9]{2,4})', response_data)[0] 11 | return score 12 | except: 13 | return -1 14 | 15 | if __name__ == "__main__": 16 | while(True): 17 | name = input("请输入要爬的ID:") 18 | print(get_CF_Rate(name)) 19 | -------------------------------------------------------------------------------- /CrawlingServer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.2 2 | MAINTAINER linzecong 3 | ADD . ./CrawlingServer 4 | WORKDIR /CrawlingServer 5 | RUN pip install -r requirements.txt 6 | CMD ["python", "main.py"] 7 | -------------------------------------------------------------------------------- /CrawlingServer/HDU.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import json 3 | def get_HDU_data(name): 4 | try: 5 | api_url = "http://acm.hdu.edu.cn/userstatus.php?user="+name 6 | response = urllib.request.urlopen(api_url,timeout=2000) 7 | response_data=response.read() 8 | response_data = str(response_data) 9 | 10 | ac = response_data[response_data.find("Problems Solved")+len("Problems Solved"):response_data.find("",response_data.find("Problems Solved"))] 11 | submit =response_data[response_data.find("Problems Submitted")+len("Problems Submitted"):response_data.find("",response_data.find("Problems Submitted"))] 12 | return [int(ac),int(submit)] 13 | except: 14 | return [-1,-1] 15 | 16 | if __name__ == "__main__": 17 | while(True): 18 | name = input("请输入要爬的ID:") 19 | print(get_HDU_data(name)) -------------------------------------------------------------------------------- /CrawlingServer/LPOJ.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import json 3 | import urllib.parse 4 | import ssl 5 | ssl._create_default_https_context = ssl._create_unverified_context 6 | 7 | 8 | def get_LPOJ_data(name): 9 | if name == "": 10 | return [-1, -1] 11 | 12 | api_url = "https://www.lpoj.cn/api/userdata/?username=" + \ 13 | urllib.parse.quote(name) 14 | try: 15 | response = urllib.request.urlopen(api_url, timeout=2000) 16 | response_data = response.read() 17 | 18 | response_data = json.loads(response_data) 19 | if len(response_data) == 0: 20 | return [-1, -1] 21 | for data in response_data: 22 | return [data["ac"], data["submit"]] 23 | except: 24 | return [-1, -1] 25 | 26 | 27 | if __name__ == "__main__": 28 | while(True): 29 | name = input("请输入要爬的ID:") 30 | print(get_LPOJ_data(name)) 31 | -------------------------------------------------------------------------------- /CrawlingServer/README.md: -------------------------------------------------------------------------------- 1 | # 爬虫机器人 2 | 3 | 主要用于爬取学生的博客和大OJ的做题数 4 | 5 | ## Docker部署 6 | 7 | 首先修改配置文件,setting.json里的东西都要修改为你的ip 8 | ``` 9 | cd CrawlingServer 10 | nano setting.json 11 | ``` 12 | 接着运行容器 13 | ``` 14 | docker build -t lpojcrawlingserver . 15 | docker run -d lpojcrawlingserver 16 | ``` 17 | 18 | ## 一般部署 19 | 20 | ``` 21 | cd CrawlingServer 22 | nano setting.json 23 | # 修改对应的数据库IP和端口保存退出 24 | pip install feedparser 25 | pip install mysqlclient 26 | sudo python main.py 27 | ``` -------------------------------------------------------------------------------- /CrawlingServer/Vjudge.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import urllib.parse 3 | import json 4 | import ssl 5 | ssl._create_default_https_context = ssl._create_unverified_context 6 | 7 | def get_VJ_data(name): 8 | try: 9 | api_url = "https://vjudge.net/user/"+name 10 | response = urllib.request.urlopen(api_url) 11 | response_data=response.read() 12 | response_data = str(response_data) 13 | 14 | ac = response_data[response_data.find("title=\"Overall solved\" target=\"_blank\">")+len("title=\"Overall solved\" target=\"_blank\">"):response_data.find("",response_data.find("title=\"Overall solved\" target=\"_blank\">"))] 15 | submit =response_data[response_data.find("title=\"Overall attempted\" target=\"_blank\">")+len("title=\"Overall attempted\" target=\"_blank\">"):response_data.find("",response_data.find("title=\"Overall attempted\" target=\"_blank\">"))] 16 | return [int(ac),int(submit)] 17 | except: 18 | return [-1,-1] 19 | 20 | if __name__ == "__main__": 21 | while(True): 22 | name = input("请输入要爬的ID:") 23 | print(get_VJ_data(name)) -------------------------------------------------------------------------------- /CrawlingServer/requirements.txt: -------------------------------------------------------------------------------- 1 | feedparser==5.2.1 2 | mysqlclient==1.4.2.post1 3 | -------------------------------------------------------------------------------- /CrawlingServer/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_user":"root", 3 | "db_pass":"504603913", 4 | "db_ip":"localhost", 5 | "db_port":"3306", 6 | "db_database":"LPOJ" 7 | } -------------------------------------------------------------------------------- /Database/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.7 2 | MAINTAINER linzecong 3 | ENV AUTO_RUN_DIR /docker-entrypoint-initdb.d 4 | ENV INSTALL_DB_SQL init_database.sql 5 | COPY ./$INSTALL_DB_SQL $AUTO_RUN_DIR/ 6 | EXPOSE 3306 33060 7 | RUN chmod a+x $AUTO_RUN_DIR/$INSTALL_DB_SQL -------------------------------------------------------------------------------- /Database/README.md: -------------------------------------------------------------------------------- 1 | # 这里主要存放数据库文件 2 | 3 | 数据库初始脚本等 -------------------------------------------------------------------------------- /Database/conf/mysqld_safe_syslog.cnf: -------------------------------------------------------------------------------- 1 | [mysqld_safe] 2 | syslog 3 | -------------------------------------------------------------------------------- /Database/init_database.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE LPOJ DEFAULT CHARACTER SET utf8 COLLATE utf8_bin; 2 | GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; 3 | FLUSH PRIVILEGES; 4 | SET time_zone = '+8:00'; 5 | FLUSH PRIVILEGES; -------------------------------------------------------------------------------- /Docs/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | docs/.vuepress/dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /Docs/README.md: -------------------------------------------------------------------------------- 1 | # 文档文件夹 2 | 3 | # [docs.lpoj.cn](http://docs.lpoj.cn) 4 | 5 | npm run docs:dev 6 | npm run docs:build -------------------------------------------------------------------------------- /Docs/docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'LPOJ 文档', 3 | description: 'LPOJ 的开发与使用文档', 4 | head: [ 5 | ['link', { rel: 'icon', href: '/img/favicon.ico' }], 6 | ], 7 | base: '/', 8 | markdown: { 9 | lineNumbers: true // 代码块显示行号 10 | }, 11 | themeConfig: { 12 | sidebarDepth: 5, 13 | nav: [ 14 | { text: 'Demo', link: 'https://www.lpoj.cn/' }, 15 | { text: 'GitHub首页', link: 'https://github.com/Linzecong/LPOJ/' }, 16 | { text: '作者首页', link: 'https://github.com/Linzecong/' }, 17 | ], 18 | 19 | sidebar: [ 20 | { 21 | title: '开始上手', 22 | collapsable: true, 23 | children: [ 24 | '/faq/', 25 | '/faq/intro', 26 | '/faq/whatisoj', 27 | '/faq/systemstruct' 28 | ] 29 | }, 30 | { 31 | title: '部署文档', 32 | collapsable: true, 33 | children: [ 34 | '/deploy/', 35 | '/deploy/frontend', 36 | '/deploy/backend', 37 | '/deploy/judgeserver', 38 | '/deploy/judger', 39 | '/deploy/crawlingserver' 40 | ] 41 | }, 42 | { 43 | title: '开发文档', 44 | collapsable: true, 45 | children: [ 46 | '/dev/', 47 | '/dev/frontend', 48 | '/dev/backend', 49 | '/dev/judgerserver', 50 | '/dev/judger', 51 | ] 52 | }, 53 | { 54 | title: '使用文档', 55 | collapsable: true, 56 | children: [ 57 | '/doc/', 58 | '/doc/oj', 59 | '/doc/judger', 60 | '/doc/utils', 61 | '/doc/faq', 62 | ] 63 | }, 64 | ] 65 | 66 | 67 | }, 68 | 69 | 70 | } -------------------------------------------------------------------------------- /Docs/docs/.vuepress/public/img/donate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Docs/docs/.vuepress/public/img/donate.jpg -------------------------------------------------------------------------------- /Docs/docs/.vuepress/public/img/faq/db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Docs/docs/.vuepress/public/img/faq/db.png -------------------------------------------------------------------------------- /Docs/docs/.vuepress/public/img/faq/db2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Docs/docs/.vuepress/public/img/faq/db2.png -------------------------------------------------------------------------------- /Docs/docs/.vuepress/public/img/faq/db3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Docs/docs/.vuepress/public/img/faq/db3.png -------------------------------------------------------------------------------- /Docs/docs/.vuepress/public/img/faq/db4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Docs/docs/.vuepress/public/img/faq/db4.png -------------------------------------------------------------------------------- /Docs/docs/.vuepress/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Docs/docs/.vuepress/public/img/favicon.ico -------------------------------------------------------------------------------- /Docs/docs/.vuepress/public/img/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Docs/docs/.vuepress/public/img/logo.jpg -------------------------------------------------------------------------------- /Docs/docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /img/logo.jpg 4 | heroText: LPOJ 使用与开发文档 5 | tagline: 帮助你快速的了解LPOJ 6 | actionText: 快速了解 7 | actionLink: /faq/ 8 | features: 9 | - title: 开源 10 | details: 一个开源的程序在线评测系统。 11 | - title: 高效 12 | details: 采用前后端分离,开发迅速。 13 | - title: 轻量级 14 | details: 使用最简单的技术开发,方便自定义修改 15 | footer: MIT Licensed | Copyright © 2020.05.13 Linzecong QQ群:875136693 16 | --- -------------------------------------------------------------------------------- /Docs/docs/deploy/README.md: -------------------------------------------------------------------------------- 1 | # 环境说明 2 | 3 | 判题机需部署在Linux环境下! 4 | 5 | 我使用的环境是: 6 | 7 | + 前端: Ubuntu 18.10 + Nginx 8 | + 后端: Ubuntu 18.10 + Python 3.7 9 | + 判题服务器: Ubuntu 18.10 + Python 3.7 10 | + 判题机: Ubuntu 18.10 + Python 3.7 (必须Linux系统) 11 | + 爬虫部分: Ubuntu 18.10 + Python 3.7 12 | 13 | 整个OJ对系统要求不高。1G内存 1核的机器足以。但是部分题目需要大内存,所以推荐使用2G内存 1核的服务器。 14 | 15 | ## 准备部署 16 | 17 | 接下来所有操作,均在Ubuntu系统下进行,如果是其他系统,请自行百度对应的命令行语句 18 | 19 | 首先我们把代码clone下来,或者直接在Github上[下载](https://github.com/Linzecong/LPOJ/archive/master.zip)下来。 20 | 首先我们将代码解压到一个文件夹中(就用LPOJ作为名字吧!) 21 | 22 | ``` 23 | mkdir LPOJ 24 | cd LPOJ 25 | git clone https://github.com/Linzecong/LPOJ.git 26 | ``` 27 | 28 | 然后你就成功的把所有所需的文件下载下来了,接下来开始部署,具体看后面的教程。 29 | 30 | ## 使用Docker部署 31 | 32 | ### 环境准备 33 | 34 | ### 1. 安装必要的依赖 35 | ``` 36 | sudo apt-get update 37 | sudo apt-get install -y git 38 | sudo apt install docker.io -y 39 | sudo apt install docker-compose -y 40 | ``` 41 | ### 2. 开始安装 42 | 43 | ``` 44 | git clone https://github.com/Linzecong/LPOJ.git && cd LPOJ 45 | ``` 46 | 47 | **请修改docker-compose.yml中的数据库密码(所有的 DB_PASSWORD,MYSQL_ROOT_PASSWORD 字段)和一些你认为必要的设置** 48 | 49 | 50 | ``` 51 | sudo docker-compose up -d --scale judger=3 52 | ``` 53 | 54 | 以上命令默认开启3个判题机,可以自行修改数量 55 | 56 | 57 | 根据网速和配置情况,大约10到20分钟就可以自动搭建完成,全程无需人工干预。 58 | 59 | 等命令执行完成,然后运行 **sudo docker ps -a** 当看到所有的容器的状态均为 Up 就代表 OJ 已经启动成功。 60 | 61 | ### 3. 准备工作 62 | 63 | 1. 安装成功后,先通过IP:8080访问OJ,注册一个用户 64 | 65 | 2. 然后进入 IP:8000/admin 以用户名admin 密码admin 登录后台(请及时修改后台密码,这个后台作用仅用于修改管理员权限,因此没有样式) 66 | 67 | 3. 修改User表中,你注册的超级用户的type为3,使得你注册的用户变为超级管理员 68 | 69 | 4. 以管理员登录,右上角进入管理员页面,然后在网站设置标签,提交一次设置 70 | 71 | ### 4. 更新OJ 72 | 73 | 如要更新OJ只需在LPOJ目录下执行如下步骤 74 | ``` 75 | git pull # 如果你修改了代码,自行解决merge得到情况 76 | sudo docker-compose stop 77 | sudo docker-compose pull 78 | sudo docker-compose up -d --scale judger=3 79 | ``` 80 | 81 | **容器运行时产生的数据会保存在对应的文件夹中,如数据库文件,题目数据等** 82 | 83 | ## 一般安装 84 | 85 | 如果你想用传统的方法,感受自己一步步搭起一个OJ的快感,你可以阅读后面的教程。 86 | 但是相信我,你会回来用一键部署的。 87 | 88 | # 部署HTTPS 89 | 90 | [https://blog.csdn.net/lzc504603913/article/details/101357133](https://blog.csdn.net/lzc504603913/article/details/101357133) 91 | -------------------------------------------------------------------------------- /Docs/docs/deploy/backend.md: -------------------------------------------------------------------------------- 1 | # 后端与数据库部署 2 | 3 | 4 | ### 部署数据库 5 | 6 | 首先安装Mysql数据库 7 | 8 | > 如果自己已经安装了数据库的,可以跳过本步骤 9 | 10 | ``` 11 | sudo apt-get install mysql-server 12 | ``` 13 | 然后新建数据库 14 | ``` 15 | CREATE DATABASE LPOJ DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 16 | ``` 17 | 如果要公网访问,可以执行以下数据库语句 18 | ``` 19 | mysql -uroot -p 20 | mysql > USE mysql 21 | mysql > GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION; 22 | mysql > ALTER user 'root'@'%' IDENTIFIED WITH mysql_native_password by 'your_password'; 23 | mysql > flush privileges; 24 | 然后修改配置文件(不同系统可能在不同地方) 25 | sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf 26 | 修改bind-address 为 0.0.0.0 27 | ``` 28 | 29 | ### 部署后端 30 | 31 | 按顺序安装Django,如已安装,可跳过 32 | 33 | 1. 首先安装Django 34 | ``` 35 | pip install django 36 | 37 | pip install djangorestframework 38 | 39 | pip install django-filter 40 | 41 | sudo apt-get install python-django 42 | 43 | pip install django-cors-headers 44 | ``` 45 | 2. 安装python数据库操作类 46 | ``` 47 | pip install mysqlclient 48 | ``` 49 | 50 | 3. 部署后端 51 | ``` 52 | cd Backend 53 | 54 | cd Backend 55 | 56 | sudo nano setting.py 57 | ``` 58 | 59 | **修改数据库配置为你自己的数据库IP端口和用户名密码** 60 | 61 | ``` 62 | cd .. 63 | 64 | python manage.py makemigrations 65 | 66 | python manage.py makemigrations judgestatus item problem user contest board blog wiki classes && 67 | 68 | python manage.py migrate 69 | 70 | echo "from django.contrib.auth.models import User; User.objects.filter(email=\"admin@example.com\").delete(); User.objects.create_superuser(\"admin\", \"admin@example.com\", \"admin\")" | python manage.py shell 71 | 72 | python manage.py runserver 0.0.0.0:8000 73 | ``` 74 | 75 | ### 添加管理员 76 | > 安装成功后,先通过IP:80访问OJ,注册一个用户 77 | > 78 | > 然后进入 IP:8000/admin 以用户名admin 密码admin 登录后台(请及时修改后台密码) 79 | > 80 | > 修改User表中,你注册的超级用户的type为3,使得你注册的用户变为超级管理员 81 | 82 | ## Docker 部署 83 | 非专业用户不推荐使用Docker单独部署 84 | 修改Dockerfile中的ENV为你的数据库地址和密码等 85 | ``` 86 | docker build -t lpojbackend . 87 | docker run -d -p 8000:8000 lpojbackend 88 | ``` -------------------------------------------------------------------------------- /Docs/docs/deploy/crawlingserver.md: -------------------------------------------------------------------------------- 1 | # 爬虫机器人部署 2 | 3 | 主要用于爬取学生的博客和大OJ的做题数 4 | 5 | ## 一般部署 6 | 7 | ``` 8 | cd CrawlingServer 9 | nano setting.json 10 | # 修改对应的数据库IP和端口保存退出 11 | pip install feedparser 12 | pip install mysqlclient 13 | sudo python main.py 14 | ``` 15 | 16 | 17 | ## Docker部署 18 | 19 | 首先修改配置文件,setting.json里的东西都要修改为你的ip 20 | ``` 21 | cd CrawlingServer 22 | nano setting.json 23 | ``` 24 | 接着运行容器 25 | ``` 26 | docker build -t lpojcrawlingserver . 27 | docker run -d lpojcrawlingserver -------------------------------------------------------------------------------- /Docs/docs/deploy/frontend.md: -------------------------------------------------------------------------------- 1 | # 前端部署 2 | 3 | ## 一般部署 4 | 5 | 首先要先安装 npm ,具体安装教程,自行百度(要先安装node.js) 6 | 7 | 安装完毕后,依次执行以下命令(以LPOJ文件夹为根目录) 8 | 由于需要安装依赖,可能会话比较多的时间。 9 | 10 | ``` 11 | cd Frontend 12 | npm install 13 | npm run build 14 | ``` 15 | 16 | 等待npm编译前端,编译成功后可以在前端中的dist文件夹找到编译成功后的静态文件。接下来我们只要把那些文件,扔到Web服务器中即可。Web服务器随意,我这里使用的是Nginx,也推荐使用Nginx。首先让我们先安装Nginx 17 | 18 | ``` 19 | sudo apt-get install nginx 20 | ``` 21 | 这样就安装成功了 22 | 我们将编译成功的dist文件夹下的所有内容,拖到Nginx的默认网站根目录中(通常是/var/www/html) 23 | 24 | Win下推荐使用WinSCP进行拖放操作! 25 | 26 | 接下来我们要修改Nginx的配置文件(不同版本可能在不同的地方) 27 | ``` 28 | sudo nano /etc/nginx/nginx.conf 29 | ``` 30 | 31 | 主要修改如下几个配置 32 | 33 | 1. 路由重定向 34 | 2. API重定向 35 | 36 | 37 | 将如下配置复制到 **http{}** 中 38 | ``` 39 | server{ 40 | listen 80; 41 | server_name www.lpoj.cn; # 此处填写你的域名或IP 42 | root /var/www/html; # 此处填写你的网页根目录 43 | location /api { # 将API重定向到后台服务器(如果你修改了前端中的代理配置,这里需要对应的修改) 44 | rewrite ^.*api/?(.*)$ /$1 break; 45 | proxy_pass http://localhost:8000; # 填写你的后端地址和端口 46 | } 47 | location / { # 路由重定向以适应Vue中的路由 48 | index index.html; 49 | try_files $uri $uri/ /index.html; 50 | } 51 | } 52 | ``` 53 | 54 | Nginx的配置多种多样,比如说开启Gzip支持等等,这些东西大家随意配置就好,具体的配置可以自行百度。 55 | 56 | 修改完后记得重启服务 57 | ``` 58 | sudo systemctl restart nginx 59 | ``` 60 | 61 | 如无意外,可以在浏览器中访问你的前端了。试一试localhost~ 62 | 63 | ## Docker 部署 64 | 65 | 非专业用户不推荐使用Docker单独部署 66 | 首先修改default.conf中proxy_pass的地址为你的后端地址,如有需要,可以修改其他配置 67 | 68 | ``` 69 | docker build -t lpojfrontend . 70 | docker run -d -p 80:80 lpojfrontend 71 | ``` -------------------------------------------------------------------------------- /Docs/docs/deploy/judger.md: -------------------------------------------------------------------------------- 1 | # 部署判题机 2 | 3 | 判题机支持多个且异地部署 4 | 5 | ## 一般部署 6 | 修改配置文件 7 | ``` 8 | cd Judger 9 | nano setting.json 10 | ``` 11 | 修改对应的数据库IP和端口,用户名和密码 12 | 13 | 修改server_ip为你的判题服务器的IP地址 14 | 15 | 如果你需要Python判题,那么请注意修改python_path 16 | 17 | 你可以使用 whereis python 命名查看python路径 18 | 19 | 需要数据库模块支持!如已安装可跳过 20 | 21 | ``` 22 | pip install mysqlclient 23 | ``` 24 | 安装依赖库 25 | ``` 26 | sudo apt-get install libseccomp-dev 27 | mkdir build && cd build && cmake .. && make && sudo make install 28 | cd .. 29 | cd JudgerCore 30 | sudo python setup.py install 31 | cd .. 32 | pip install paramiko 33 | sudo apt install time 34 | ``` 35 | 36 | 安装Java环境 37 | ``` 38 | sudo apt install openjdk-8-jdk 39 | ``` 40 | 41 | 42 | 最后运行 43 | ``` 44 | sudo python main.py 45 | ``` 46 | 47 | ## Docker 部署 48 | 49 | 非专业用户不推荐使用Docker单独部署 50 | 51 | 首先修改配置文件,setting.json里的东西都要修改为你的ip 52 | 53 | ``` 54 | cd Judger 55 | nano setting.json 56 | ``` 57 | 接着运行容器 58 | ``` 59 | docker build -t lpojjudger . 60 | docker run -d lpojjudger 61 | ``` -------------------------------------------------------------------------------- /Docs/docs/deploy/judgeserver.md: -------------------------------------------------------------------------------- 1 | # 部署判题服务器 2 | 3 | ## 一般部署 4 | 首先修改配置文件 5 | ``` 6 | cd JudgeServer 7 | nano setting.json 8 | ``` 9 | 修改对应的数据库IP和端口,用户名和密码保存退出 10 | 11 | 需要数据库模块支持!如已安装可跳过 12 | 13 | ``` 14 | sudo apt-get install libmysqlclient-dev 15 | 16 | pip install mysqlclient 17 | ``` 18 | 最后运行 19 | ``` 20 | sudo python main.py 21 | ``` 22 | 23 | ## Docker 部署 24 | 25 | 非专业用户不推荐使用Docker单独部署 26 | 27 | 首先修改配置文件,setting.json 28 | ``` 29 | cd JudgerServer 30 | nano setting.json 31 | ``` 32 | 接着运行容器 33 | ``` 34 | docker build -t lpojjudgerserver . 35 | docker run -d -p 9906:9906 lpojjudgerserver 36 | ``` -------------------------------------------------------------------------------- /Docs/docs/dev/README.md: -------------------------------------------------------------------------------- 1 | # 开发入门 2 | 3 | 这个章节将会介绍整个OJ是如何开发起来的,方便大家二次开发 4 | 5 | 整个章节分为如下几个部分: 6 | 7 | + 前端开发 8 | + 后端开发 9 | + 判题服务器原理 10 | + 判题机原理 11 | 12 | 13 | 首先我们要做一下准备工作!下载源码和切换工作目录 14 | 15 | ``` 16 | git clone https://github.com/Linzecong/LPOJ.git 17 | cd LPOJ 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /Docs/docs/dev/judgerserver.md: -------------------------------------------------------------------------------- 1 | # 判题服务器开发 2 | 3 | 判题服务器非常的简单,几乎无需做任何修改。采用TCP技术来通知判题机。 4 | 5 | ## 架构详解 6 | 测评模块仅提供了安全稳定的程序运行稳定,但是并不能判断程序是否通过,因此还要自己完成许多的逻辑工作。本系统的测评模块分为两部分,一部分是测评服务器,负责分发测评任务,另一部分是测评机,负责运行程序和提交测评结果。程序在运行过程中难免会消耗系统资源,如果只有一个判题程序在判题,如果判题时间较长,会导致后面的题目无法得到及时的反馈,但是如果太多判题程序同时运行,会导致系统资源消耗过大,导致前端和后台系统可能无法正确运行,所以要设计一个能够在多个机器上运行的判题程序,实现均衡负载功能,因此本OJ测评模块示意图如下: 7 | 8 | ![测评模块示意图](/img/faq/db3.png) 9 | 10 | 利用了数据库的事务管理,可使得高并发得以实现。用户相当于生产者,不断地向数据库提交待测评列表,测评服务器相当于一个消费者,不断的从数据库中获取未判提交列表,然后将这些题目分发到准备就绪的判题机,判题机收到判题任务后会进入忙状态,此时判题服务器不再向该判题机发送判题任务。当判题机判题完毕,会告诉服务器,可以继续判题。服务器再将该判题机纳入空闲列表。这样我们就能实现多个判题机同时运行,且这些判题机可以在任意的机器上运行,只需要通过TCP协议,链接到服务器上即可。同时服务器被设计成多线程的形式,在通过资源锁去控制并发的资源访问,使得多个判题程序能同时判题。 测评服务器,测评服务器使用Python开发,运行时会循环监听9906端口,一旦有测评机连上服务器,会新建一个线程,专门处理该测评机的消息。该线程首先会向测评机发送getstatus信息,测评机收到消息后会向服务器发送ok信号,代表已准备好判题。此时服务器会将该测评机纳入空闲列表。然后不断地循环发送getstatus信号,如果是not ok,代表非空闲状态,会将该测评机纳入非空闲列表。同时会有一个线程专门负责向数据库获取未判题列表,然后将未判题发放给空闲的判题机进行判题。 11 | 12 | 13 | ## 额外功能 14 | 15 | 由于历史原因和出于安全性的考虑,需要通过额外的程序来实现将比赛中的题目的权限设置为**可访问**,即将比赛中的题目访问权限设置为**私密**,这里将这个功能集成到了判题服务器的代码里。实际上这一部分可以独立出来运行。 16 | 17 | 18 | ## 源码解析 19 | 20 | 大概原理是这样的,这个判题服务器充当一个网关的功能,由他来拉取需要判题的列表,然后发送给各个服务器。这个判题服务器直接跟数据库进行通讯(直接把数据库当做中间件来用,比较方便)。用轮训的方式,不断地从数据库获取未判题列表,然后发送给各个判题机。当有判题机连入时,自动起一个线程来处理判题机的消息。判题机会不断地发送心跳包给判题服务器。 21 | 22 | 我真的写不动注释了!!! 23 | 24 | [main.py](https://github.com/Linzecong/LPOJ/blob/master/JudgerServer/main.py) 25 | 26 | [HDUVjudge.py](https://github.com/Linzecong/LPOJ/blob/master/Judger/VJudge/HDUVjudge.py) -------------------------------------------------------------------------------- /Docs/docs/doc/README.md: -------------------------------------------------------------------------------- 1 | # 简介 2 | 3 | 本章只要介绍整个OJ的使用,和一些常见问题! 4 | 5 | 很多东西可能说不清楚,有问题可以在群里问! 6 | 7 | 8 | -------------------------------------------------------------------------------- /Docs/docs/doc/faq.md: -------------------------------------------------------------------------------- 1 | 2 | # OJ常见问题 3 | 4 | ## 不想使用HTTP下载文件 5 | 6 | 如果你不想使用HTTP咋办? 7 | 8 | 因为有的服务器不支持或者觉得不安全! 9 | 10 | 那么你可以修改docker-comopse.yml中的 NO_DOWNLOAD 为yes, 11 | 12 | yes则不使用HTTP 13 | 14 | 15 | 但是你就需要手动将数据压缩包放到Judger/ProblemData中 16 | 17 | 注意!!每一个判题机所以在的服务器都要放!这样就不能分布式判题了~!因为每次更改数据文件,都需要对每一个判题机的数据进行更新。当然,如果你只有一个判题机,那还是很方便的 18 | 19 | 这里可用Rsync服务优化!但是作者真的太懒了! 20 | 21 | ## OJ判题安全吗? 22 | 23 | 使用的都是青岛大学提供的沙箱!这个要问他们了~! 24 | 25 | ## 添加题目失败 26 | 27 | 可能是数据库不一致导致的!自行进入数据库,检查problem_problem表和problem_peoblemdata表的题目数据是否一致! 28 | 29 | 目前这个bug已经修复,但是仍有触发的可能~ 30 | 31 | 如果真的遇到,可以加群咨询 32 | 33 | ## 注册提示已注册,但是登录不了 34 | 35 | 可能是数据库不一致导致的!自行进入数据库,检查user_user表和user_userdata表的用户数据是否一致! 36 | 37 | 目前这个bug已经修复,但是仍有触发的可能~ 38 | 39 | 如果真的遇到,可以加群咨询 40 | 41 | 42 | ## 支持封榜吗? 43 | 44 | 准备支持了!! 45 | 46 | 47 | ## 提交数据卡住怎么办 48 | 49 | 在浏览器按F12,刷新页面,然后重新提交,看看报什么错误 50 | 51 | 一般来说不会卡住,如果一直上传失败,可以自行把数据文件放到后台的数据文件夹中 52 | 53 | /Backend/ProblemData 中 54 | 55 | 限500M大小,太大了请减少体积 56 | 57 | ## 测评机卡住了怎么办 58 | 59 | 一般不会卡住! 60 | 61 | 检查是不是数据太多的原因! 62 | 63 | 如果开启了OI模式,会对所有样例都判一次。假如你设置5S超时,刚好有个人提交一份超时的代码。假设你有100组数据。那么你就要跑500S!!!!所以要精简数据量,或者在比赛中关闭OI模式 64 | 65 | 如果使用Docker部署的话,崩了会自动重启的 66 | 67 | ## OJ太慢了怎么办? 68 | 69 | 后台是异步多进程多线程的!如果是数据库太慢,请使用自己的数据库,自行修改数据库地址等! 70 | 71 | 或者加大设备!在不同设备上跑Judger 72 | 73 | ## 我想独立部署多个Judger怎么办 74 | 75 | 把docker-compose.yml文件中除judger以外的内容全部删除。 76 | 77 | 然后修改各种参数即可 78 | 79 | 如可参考如下 80 | 81 | ```yml 82 | version: '2' 83 | services: 84 | 85 | judger: 86 | image: ccr.ccs.tencentyun.com/lpoj/judger 87 | command: > 88 | /bin/bash -c ' 89 | sleep 65 ; 90 | python3 main.py 91 | ' 92 | 93 | environment: 94 | DB_PASSWORD: "123456" # 必须修改!! 95 | DB_HOST: "111.111.111.111" # 必须修改!! 96 | DB_USER: 'root' # 必须修改!! 97 | DB_PORT: 3306 # 必须修改!! 98 | 99 | SERVER_IP: "111.111.111.112" # 必须修改!! 100 | BACKEND_PORT: 8000 101 | BACKEND_IP: "localhost" # 必须修改,不能写127.0.0.1或localhost,必须写你的局域网地址或者公网地址 102 | BACKEND_HEAD: 'http' # 如果你用了https,请改为https 103 | 104 | NO_DOWNLOAD: "no" # 设为yes,则不使用http,需要手动将数据压缩包放到Judger/ProblemData中 105 | 106 | restart: always 107 | volumes: 108 | - "./Judger/ProblemData:/Judger/ProblemData" 109 | 110 | ``` 111 | 112 | 113 | ## 前端加载太慢怎么办 114 | 115 | 自行优化!我已经优化不动了! 116 | 117 | 或者使用CDN 118 | 119 | 自己申请域名 120 | 121 | 自己做个代理转发 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /Docs/docs/doc/utils.md: -------------------------------------------------------------------------------- 1 | # 其他工具 2 | 3 | ## CrawlingServer 4 | 5 | 在管理员页面设置好爬虫信息后,可以启动爬虫机器人进行爬虫。 6 | 主要可以爬取的信息是 各OJ做题数,博客,和近期比赛列表 7 | 8 | ### 启动 9 | 10 | ```bash 11 | python main.py 12 | ``` 13 | ### 源码解析 14 | 15 | [main.py](https://github.com/Linzecong/LPOJ/blob/master/CrawlingServer/main.py) 16 | 17 | 18 | ## Tools 19 | 20 | 这个文件夹中,包含了各种实用的工具! 21 | 22 | 23 | ### 查重脚本 duplication_checking.py 24 | 25 | 此脚本基于SIM工具查重 26 | 27 | 28 | 自行查看攻略! https://dickgrune.com/Programs/similarity_tester/ 29 | 30 | 修改其中的数据库信息 31 | ```py 32 | db = MySQLdb.connect( 33 | host="localhost", # 主机名 34 | user="root", # 数据库用户名 35 | passwd="", # 数据库密码 36 | db="LPOJ") # 数据库名称 37 | ``` 38 | 用法 39 | ```py 40 | sudo python duplication_checking.py 41 | ``` 42 | 脚本将会在脚本所在的目录下生成一个contest_duplication_checking的文件夹用于存放AC代码,子文件夹为contest_i分别存放了每一场比赛的AC代码,AC代码按用户名存放 43 | 44 | 45 | ### HDUSpider.py 46 | 47 | 用于爬取杭电题目数据并保存到数据库中! 48 | 49 | 你需要这只你的管理员的用户名和密码来登录! 50 | 51 | 运行时,记得正确设置题目的编号和杭电上题目的编号,看清楚源码再运行! 52 | 53 | ### RaiseCheck.py 54 | 55 | 这个脚本用于检查用户的代码有多少个raise 56 | 57 | 因为Python的话,可以用过爆破数据库来找到正确答案 58 | 59 | 通过这个脚本我们能找到爆破的用户,当然你也可以检查其他东西。代码很简单 60 | 61 | ### RatingCalculator.py 62 | 63 | 用于计算rated的比赛的rating 变化! 64 | 65 | 就是每次Rated比赛完毕后,需要手动的更新所有参加比赛的用户的Rating! 66 | 67 | 就要运行这个脚本!具体规则请看LPOJ首页的规则说明 68 | 69 | 你可以自己修改代码,来改变Rating的计算规则! 70 | 71 | ### RecoverBoard.py 72 | 73 | 排行榜恢复器!有时候由于网络原因,排行榜可能会记录失败!(低概率事件) 74 | 75 | 排查后,如果的确有用户的排行榜错了,可以用这个脚本重新生成整个排行榜 76 | 77 | 修改source_contest为你的比赛ID 78 | 79 | 然后运行~ 80 | 81 | ### SubmitExport.py 82 | 83 | 这个脚本可以把用户提交的代码导出 84 | 85 | 由于数据量太大!因此直接通过读取文件的方式 86 | 87 | 在运行前,你需要将judgestatus_judgestatus表中的数据导出!(如果只导出某个比赛的,请自行筛选!) 88 | 89 | 导出成JSON格式!网上很多教程 90 | 91 | 然后保存为data.json文件。然后运行即可! 92 | 93 | 详见代码! 94 | 95 | ### UserImporter.py 96 | 97 | 代码原理很简单!就是自动提交api。自己看代码! 98 | 99 | -------------------------------------------------------------------------------- /Docs/docs/faq/README.md: -------------------------------------------------------------------------------- 1 | # 引言 2 | 3 | ## 什么是LPOJ? 4 | 5 | LPOJ是一个由在校学生(现在已毕业)的学生自主开发的一个程序在线评测系统。 6 | 7 | ## 为什么要开发? 8 | 9 | 因为不开发,他毕不了业了。这是他的毕业设计。 10 | 11 | ## 你为什么要选择LPOJ 12 | 13 | 因为它使用的是最简单的技术。一天速成的Vue.js技术,和一天速成的Django REST framework技术。 14 | 15 | 理论上你只需要花两天时间,就能过看懂本OJ是怎么写出来的 16 | 17 | 使用的都是最简单的实现方法!没有高深的前后端知识! 18 | 19 | ## 文档最后更新于 **2020-5-13** 20 | 21 | 写文档太累了!! 22 | 23 | ## 打赏一下会写的更快吗? 24 | 25 | 那肯定了!赶紧微信赞赏一下吧!顺便备注里写一下鼓励语吧!个人开发实属不易!您的打赏将用于日常服务器的开支!服务器真的贵啊! 26 | 27 | ![打赏我吧](/img/donate.jpg) 28 | 29 | 30 | # 打赏人员名单 31 | 32 | **更新于2020-5-26** 33 | 34 | 感谢GWT20.00元 35 | 36 | 感谢Kurisu5.00元 37 | 38 | 感谢04G赞赏的20.00元 39 | 40 | 感谢0字节赞赏的20.00元 41 | 42 | 感谢Daniel赞赏的10.00元 43 | 44 | 感谢张顺赞赏的0.66元 45 | 46 | 感谢家煜赞赏的0.10元 47 | 48 | 感谢哈哈赞赏的5.00元 49 | 50 | 感谢陆嘉俊赞赏的6.66元 51 | 52 | 感谢膜大佬赞赏的10.00元 53 | 54 | 感谢甄英明赞赏的9.99元 55 | 56 | 感谢维度旅客赞赏的1.00元 57 | 58 | 感谢马涛赞赏的10.00元 59 | 60 | 感谢你的鼓励是我最大的动力!的10.00元 61 | 62 | 感谢Sebastian Lin赞赏的10.00元 63 | 64 | 感谢在下大名风大船赞赏的20.00元 65 | 66 | 感谢残阳赞赏的5.00元 67 | 68 | 感谢坚持.赞赏的5.20元 69 | 70 | 感谢曹岩奇赞赏的8.88元 71 | 72 | 感谢lww小粉丝赞赏的15.00元 73 | 74 | 感谢cineny赞赏的15.00元 75 | 76 | 感谢Hongrock赞赏的10.00元 77 | -------------------------------------------------------------------------------- /Docs/docs/faq/whatisoj.md: -------------------------------------------------------------------------------- 1 | # 什么是OJ 2 | 3 | 以下摘自我的毕业论文 4 | 5 | ## 背景及研究意义 6 | 随着信息技术的发展,人们越来越注重基础的算法知识教学。现代企业中,人工智能无处不在,而人工智能又离不开算法,对于未来人才的培养,基础算法显得尤为重要。因此各大高校也越来越重视算法人才的培养。现在许多高校都有一套成熟的培养系统,比如杭州电子科技大学,北京大学,清华大学都有自己的判题系统。所谓判题系统,就是一个能对学生提交的程序进行自动判断的系统,这样不仅能省下老师许多时间,学生还能够自行的进行更多的训练,并从中学到更多的算法。一个好的判题系统不仅能进行判题,还能让学生随时随地的学习,即让判题程序以网页的形式呈现,只需要一个浏览器即可访问。同时还配套有一系列功能,如学生能迅速定位到自己的错误,并且能动态的看到自己的学习与锻炼情况等等。 7 | 8 | 上述判题系统我们称之为OJ,即Online Judge,中文名叫在线评测系统,目前在国内比较出名的在线评测系统有学校运营着的杭州电子科技大学的HDOJ,有北大的POJ,有浙江大学的ZOJ等等,同时也有企业运营着的PTA系统,计蒜客的判题系统,和企业面试常用的牛客网。这些均是国内出名的判题系统。在国外也有在全球出名的LeetCode网站,许多程序员在面试前都会上这个网站进行学习,同时还有由俄罗斯高校运营着的一个算法竞赛的做题网站Codeforces,还有日本的AtCoder等等。 9 | 10 | 11 | 虽然市面上有许许多多的OJ,但是OJ之间的题目数据并不共享,这就使得这些学习资源被垄断,因此一个属于学校本身的OJ就显得尤为重要。虽然在Github上有许多开源的OJ,最出名的如华中科技大学主持开源的HustOJ,有青岛大学主持的QDUOJ,但是要理解且修改当中的源码或者定制自己的功能显得尤为困难。所以学校要有自己的一个判题系统去培养算法人才。 12 | 13 | ## 算法竞赛介绍与OJ介绍 14 | 现代科技企业为了招到算法人才,会举办各种各样的算法竞赛去吸引人才。如百度每年都会举办百度之星,美团也会举办算法竞赛,同时在国际上,有由美国计算机协会(现在由JetBrain公司)支持举办的国际大学生程序设计竞赛,每年都会举办各国区域赛选拔顶尖算法人才去参加全球总决赛。在国内,也有中国大学生程序设计赛,也有各省的省赛。这些竞赛的目的都是为了培养各种各样的算法人才。 15 | 16 | 17 | 算法竞赛的形式非常简单,通常是在比赛的时候,每人或每只队伍使用一台电脑,然后需要在有限的5个小时内使用自己熟悉的编程语言写程序解决七个以上的问题。程序提交之后会给裁判或者在线的测评系统进行编译,然后运行,运行的结果会判定为正确或错误两种并及时通知各个参赛队。比赛形式非常的简单,但是却很非常紧张且具有挑战性。这些题目涵盖的领域非常广,包括数据结构,动态规划,图论,数论,运筹学,博弈论,概率论等等,而且通常需要学生编写非常严谨的程序,不容得一丝错误。 18 | 19 | 在实际工作当中,一个小小的漏洞都会给企业带来非常大的损失,所以一个长期参加算法竞赛的学生在工作中会展现出自身的优势,因此各大高校和企业也都非常重视算法竞赛的发展。但是要判断学生写的程序是否正确就需要一个能自动对学生程序进行判题的系统。这个系统会在数据库中存放各种题目数据,然后通过前端展示给学生,通常题目由:题目描述、输入描述、输出描述组成。学生需要编写一个程序去接收系统提供的输入数据,然后按照题目要求,对数据进行处理后,输出一个正确的答案。系统会将这个答案与后台的答案进行比较,如果相同,则代表学生的程序是正确的,错误则代表学生的程序有漏洞。通常系统会限制学生的程序要在一定时间内运行完毕,即程序的时间复杂度要在合理的范围内,同时空间复杂度也要在限定的范围内。因为在实际工作中效率非常重要。 20 | 21 | 同时程序在运行过程中不容得出现致命的系统错误,比如数组越界,除零等等。还有在比赛过程当中,由于集中提交,会有高并发的业务,因此一个系统要对上述所有情况作出判断且稳定的运行是非常困难的,这也是一个要攻克的难点。在本文后面会有提到如何解决。 22 | -------------------------------------------------------------------------------- /Docs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Docs", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /Docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Docs", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "docs:dev": "vuepress dev docs", 8 | "docs:build": "vuepress build docs" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC" 13 | } 14 | -------------------------------------------------------------------------------- /Frontend/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "entry" 8 | } 9 | ], 10 | "stage-3" 11 | ], 12 | 13 | "plugins": [ 14 | ["import", { 15 | "libraryName": "muse-ui", 16 | "libraryDirectory": "lib", 17 | "camel2DashComponentName": false 18 | }] 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /Frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /Frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /Frontend/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:13.10-slim 2 | MAINTAINER linzecong 3 | ADD . ./Frontend 4 | WORKDIR /Frontend 5 | RUN apt-get update 6 | RUN npm install 7 | RUN npm run build 8 | RUN apt-get install nginx -y 9 | 10 | RUN rm -rf /Frontend/node_modules 11 | 12 | EXPOSE 80 13 | ADD nginx.conf /etc/nginx/nginx.conf 14 | CMD ["nginx", "-g", "daemon off;"] -------------------------------------------------------------------------------- /Frontend/README.md: -------------------------------------------------------------------------------- 1 | # 前端部署 2 | 3 | ## Docker部署 4 | 非专业用户不推荐使用Docker单独部署 5 | 修改nginx.conf中proxy_pass的地址为你的后端地址,如有需要,可以修改其他配置 6 | 7 | ``` 8 | docker build -t lpojfrontend . 9 | docker run -d -p 80:80 lpojfrontend 10 | ``` 11 | 12 | ## 一般部署 13 | 14 | ``` 15 | cd Frontend 16 | npm install 17 | npm run build 18 | ``` 19 | 编译完毕后,网站文件保存在dist目录中,接下来部署到服务器中 20 | + 推荐使用Nginx 21 | ``` 22 | sudo apt-get install nginx 23 | ``` 24 | 将dist文件夹中的文件复制到Web服务器目录中(默认根目录 **/var/www/html/**) 25 | 接下来修改Nginx配置文件(不同版本可能在不同的地方) 26 | ``` 27 | sudo nano /etc/nginx/nginx.conf 28 | ``` 29 | 主要修改如下几个配置 30 | 1. 路由重定向 31 | 2. API重定向 32 | 33 | 将如下配置复制到http{}中 34 | ``` 35 | server{ 36 | listen 80; 37 | server_name www.lpoj.cn; # 此处填写你的域名或IP地址 38 | root /var/www/html; # 此处填写你的网页根目录 39 | location /api { # 将API重定向到后台服务器(如果你修改了前端中的代理配置,这里需要对应的修改) 40 | rewrite ^.*api/?(.*)$ /$1 break; 41 | proxy_pass http://localhost:8000; # 填写你的后端地址和端口 42 | } 43 | location / { # 路由重定向以适应Vue中的路由 44 | index index.html; 45 | try_files $uri $uri/ /index.html; 46 | } 47 | } 48 | ``` 49 | 其他配置请自行参考Nginx配置 50 | 51 | 至此,前端部署完毕。**如要进行OJ二次开发,请参阅[文档](http://docs.lpoj.cn)** -------------------------------------------------------------------------------- /Frontend/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /Frontend/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Frontend/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/build/logo.png -------------------------------------------------------------------------------- /Frontend/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Frontend/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | 12 | 13 | module.exports = { 14 | context: path.resolve(__dirname, '../'), 15 | entry: { 16 | app: ['babel-polyfill', './src/main.js'] 17 | }, 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: '[name].js', 21 | publicPath: process.env.NODE_ENV === 'production' 22 | ? config.build.assetsPublicPath 23 | : config.dev.assetsPublicPath 24 | }, 25 | resolve: { 26 | extensions: ['.js', '.vue', '.json'], 27 | alias: { 28 | 'vue$': 'vue/dist/vue.esm.js', 29 | '@': resolve('src'), 30 | } 31 | }, 32 | module: { 33 | rules: [ 34 | { 35 | test: /\.vue$/, 36 | loader: 'vue-loader', 37 | options: vueLoaderConfig 38 | }, 39 | { 40 | test: /\.js$/, 41 | loader: 'babel-loader', 42 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] 43 | }, 44 | { 45 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 46 | loader: 'url-loader', 47 | options: { 48 | limit: 10000, 49 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 50 | } 51 | }, 52 | { 53 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 54 | loader: 'url-loader', 55 | options: { 56 | limit: 10000, 57 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 58 | } 59 | }, 60 | { 61 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 62 | loader: 'url-loader', 63 | options: { 64 | limit: 10000, 65 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 66 | } 67 | } 68 | ] 69 | }, 70 | node: { 71 | // prevent webpack from injecting useless setImmediate polyfill because Vue 72 | // source contains it (although only uses it if it's native). 73 | setImmediate: false, 74 | // prevent webpack from injecting mocks to Node native modules 75 | // that does not make sense for the client 76 | dgram: 'empty', 77 | fs: 'empty', 78 | net: 'empty', 79 | tls: 'empty', 80 | child_process: 'empty' 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Frontend/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"', 7 | API_ROOT: '"/api"' 8 | }) 9 | -------------------------------------------------------------------------------- /Frontend/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: { 14 | '/api': { 15 | target: 'https://www.lpoj.cn/api', 16 | changeOrigin: true, 17 | pathRewrite: { 18 | '^/api': '/' 19 | } 20 | } 21 | }, 22 | 23 | // Various Dev Server settings 24 | host: '0.0.0.0', // can be overwritten by process.env.HOST 25 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 26 | autoOpenBrowser: false, 27 | errorOverlay: true, 28 | notifyOnErrors: true, 29 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 30 | 31 | 32 | /** 33 | * Source Maps 34 | */ 35 | 36 | // https://webpack.js.org/configuration/devtool/#development 37 | devtool: 'cheap-module-eval-source-map', 38 | 39 | // If you have problems debugging vue-files in devtools, 40 | // set this to false - it *may* help 41 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 42 | cacheBusting: true, 43 | 44 | cssSourceMap: true 45 | }, 46 | 47 | build: { 48 | // Template for index.html 49 | index: path.resolve(__dirname, '../dist/index.html'), 50 | 51 | // Paths 52 | assetsRoot: path.resolve(__dirname, '../dist'), 53 | assetsSubDirectory: 'static', 54 | assetsPublicPath: '/', 55 | 56 | /** 57 | * Source Maps 58 | */ 59 | 60 | productionSourceMap: false, 61 | // https://webpack.js.org/configuration/devtool/#production 62 | devtool: '#source-map', 63 | 64 | // Gzip off by default as many popular static hosts such as 65 | // Surge or Netlify already gzip all static assets for you. 66 | // Before setting to `true`, make sure to: 67 | // npm install --save-dev compression-webpack-plugin 68 | productionGzip: true, 69 | productionGzipExtensions: ['js', 'css'], 70 | 71 | // Run the build command with an extra argument to 72 | // View the bundle analyzer report after build finishes: 73 | // `npm run build --report` 74 | // Set to `true` or `false` to always turn it on or off 75 | bundleAnalyzerReport: process.env.npm_config_report 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Frontend/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | API_ROOT: '"/api"' 5 | } 6 | -------------------------------------------------------------------------------- /Frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to LPOJ 10 | 19 | 20 | 31 | 32 | 33 | 34 |
35 |



36 |
First time loading, please wait for a second
如果等太久,可以尝试按一下F5
37 |

38 |
39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Frontend/src/components/chart/echarts.js: -------------------------------------------------------------------------------- 1 | import echarts from 'echarts/lib/echarts' 2 | 3 | // 再引入你需要使用的图表类型,标题,提示信息等 4 | 5 | import 'echarts/lib/chart/line' // 按需导入折线组件 6 | import 'echarts/lib/component/tooltip' // 提示组件 7 | import 'echarts/lib/component/legend' // 图例组件 8 | import 'echarts/lib/component/visualMap' 9 | 10 | export default echarts -------------------------------------------------------------------------------- /Frontend/src/components/contest/contestannounce.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 77 | 78 | 79 | 81 | -------------------------------------------------------------------------------- /Frontend/src/components/contest/contestsubmit.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 26 | 27 | 28 | 33 | -------------------------------------------------------------------------------- /Frontend/src/components/main.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 88 | 89 | 95 | -------------------------------------------------------------------------------- /Frontend/src/components/mainpage/homework.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 71 | 72 | 73 | 75 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/blogmini.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 67 | 68 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/contestmini.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 59 | 60 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/description.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 43 | 44 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/languageselect.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 44 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/soulrow.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 68 | 69 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/topuser.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 56 | 57 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/welcomemessage.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 48 | 49 | -------------------------------------------------------------------------------- /Frontend/src/components/utils/wikidetail.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 58 | 59 | 60 | 62 | -------------------------------------------------------------------------------- /Frontend/src/components/wiki/algorithm.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 77 | 78 | 79 | 81 | -------------------------------------------------------------------------------- /Frontend/src/components/wiki/code.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 59 | 60 | 61 | 63 | -------------------------------------------------------------------------------- /Frontend/src/components/wiki/newalgorithm.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 26 | 27 | 28 | 30 | -------------------------------------------------------------------------------- /Frontend/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/.gitkeep -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Math-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Math-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff -------------------------------------------------------------------------------- /Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Frontend/static/js/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff -------------------------------------------------------------------------------- /FrontendMobile/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "modules": false, 7 | "useBuiltIns": "entry" 8 | } 9 | ], 10 | "stage-3" 11 | ] 12 | } -------------------------------------------------------------------------------- /FrontendMobile/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /FrontendMobile/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /FrontendMobile/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /FrontendMobile/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FrontendMobile/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:13.10-slim 2 | MAINTAINER linzecong 3 | ADD . ./FrontendMobile 4 | WORKDIR /FrontendMobile 5 | RUN apt-get update 6 | RUN npm install 7 | RUN npm run build 8 | RUN apt-get install nginx -y 9 | RUN rm -rf /Frontend/node_modules 10 | 11 | EXPOSE 8081 12 | ADD nginx.conf /etc/nginx/nginx.conf 13 | CMD ["nginx", "-g", "daemon off;"] -------------------------------------------------------------------------------- /FrontendMobile/README.md: -------------------------------------------------------------------------------- 1 | # 手机前端部署 2 | 3 | # 2019-08-01 后不再维护! 4 | 5 | ## Docker部署 6 | 非专业用户不推荐使用Docker单独部署 7 | 修改nginx.conf中proxy_pass的地址为你的后端地址,如有需要,可以修改其他配置 8 | 9 | ``` 10 | docker build -t lpojfrontendmobile . 11 | docker run -d -p 80:80 lpojfrontendmobile 12 | ``` 13 | 14 | ## 一般部署 15 | 16 | ``` 17 | cd FrontendMobile 18 | npm install 19 | npm run build 20 | ``` 21 | 编译完毕后,网站文件保存在dist目录中,接下来部署到服务器中 22 | + 推荐使用Nginx 23 | ``` 24 | sudo apt-get install nginx 25 | ``` 26 | 将dist文件夹中的文件复制到Web服务器目录中(默认根目录 **/var/www/html/**) 27 | 接下来修改Nginx配置文件(不同版本可能在不同的地方) 28 | ``` 29 | sudo nano /etc/nginx/nginx.conf 30 | ``` 31 | 主要修改如下几个配置 32 | 1. 路由重定向 33 | 2. API重定向 34 | 35 | 将如下配置复制到http{}中 36 | ``` 37 | server{ 38 | listen 80; 39 | server_name m.lpoj.cn; # 此处填写你的域名或IP地址 40 | root /var/www/html; # 此处填写你的网页根目录 41 | location /api { # 将API重定向到后台服务器(如果你修改了前端中的代理配置,这里需要对应的修改) 42 | rewrite ^.*api/?(.*)$ /$1 break; 43 | proxy_pass http://localhost:8000; # 填写你的后端地址和端口 44 | } 45 | location / { # 路由重定向以适应Vue中的路由 46 | index index.html; 47 | try_files $uri $uri/ /index.html; 48 | } 49 | } 50 | ``` 51 | 其他配置请自行参考Nginx配置 52 | 53 | 至此,手机前端部署完毕。**如要进行OJ二次开发,请参阅[文档](http://docs.lpoj.cn)** -------------------------------------------------------------------------------- /FrontendMobile/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /FrontendMobile/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /FrontendMobile/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/FrontendMobile/build/logo.png -------------------------------------------------------------------------------- /FrontendMobile/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FrontendMobile/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | 12 | 13 | module.exports = { 14 | context: path.resolve(__dirname, '../'), 15 | entry: { 16 | app: ['babel-polyfill', './src/main.js'] 17 | }, 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: '[name].js', 21 | publicPath: process.env.NODE_ENV === 'production' 22 | ? config.build.assetsPublicPath 23 | : config.dev.assetsPublicPath 24 | }, 25 | resolve: { 26 | extensions: ['.js', '.vue', '.json'], 27 | alias: { 28 | 'vue$': 'vue/dist/vue.esm.js', 29 | '@': resolve('src'), 30 | } 31 | }, 32 | module: { 33 | rules: [ 34 | { 35 | test: /\.vue$/, 36 | loader: 'vue-loader', 37 | options: vueLoaderConfig 38 | }, 39 | { 40 | test: /\.js$/, 41 | loader: 'babel-loader', 42 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] 43 | }, 44 | { 45 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 46 | loader: 'url-loader', 47 | options: { 48 | limit: 10000, 49 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 50 | } 51 | }, 52 | { 53 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 54 | loader: 'url-loader', 55 | options: { 56 | limit: 10000, 57 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 58 | } 59 | }, 60 | { 61 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 62 | loader: 'url-loader', 63 | options: { 64 | limit: 10000, 65 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 66 | } 67 | } 68 | ] 69 | }, 70 | node: { 71 | // prevent webpack from injecting useless setImmediate polyfill because Vue 72 | // source contains it (although only uses it if it's native). 73 | setImmediate: false, 74 | // prevent webpack from injecting mocks to Node native modules 75 | // that does not make sense for the client 76 | dgram: 'empty', 77 | fs: 'empty', 78 | net: 'empty', 79 | tls: 'empty', 80 | child_process: 'empty' 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /FrontendMobile/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"', 7 | API_ROOT: '"/api"' 8 | }) 9 | -------------------------------------------------------------------------------- /FrontendMobile/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: { 14 | '/api': { 15 | target: 'https://www.lpoj.cn/api', 16 | changeOrigin: true, 17 | pathRewrite:{ 18 | '^/api':'/' 19 | } 20 | } 21 | }, 22 | 23 | // Various Dev Server settings 24 | host: '0.0.0.0', // can be overwritten by process.env.HOST 25 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 26 | autoOpenBrowser: false, 27 | errorOverlay: true, 28 | notifyOnErrors: true, 29 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 30 | 31 | 32 | /** 33 | * Source Maps 34 | */ 35 | 36 | // https://webpack.js.org/configuration/devtool/#development 37 | devtool: 'cheap-module-eval-source-map', 38 | 39 | // If you have problems debugging vue-files in devtools, 40 | // set this to false - it *may* help 41 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 42 | cacheBusting: true, 43 | 44 | cssSourceMap: true 45 | }, 46 | 47 | build: { 48 | // Template for index.html 49 | index: path.resolve(__dirname, '../dist/index.html'), 50 | 51 | // Paths 52 | assetsRoot: path.resolve(__dirname, '../dist'), 53 | assetsSubDirectory: 'static', 54 | assetsPublicPath: '/', 55 | 56 | /** 57 | * Source Maps 58 | */ 59 | 60 | productionSourceMap: false, 61 | // https://webpack.js.org/configuration/devtool/#production 62 | devtool: '#source-map', 63 | 64 | // Gzip off by default as many popular static hosts such as 65 | // Surge or Netlify already gzip all static assets for you. 66 | // Before setting to `true`, make sure to: 67 | // npm install --save-dev compression-webpack-plugin 68 | productionGzip: true, 69 | productionGzipExtensions: ['js', 'css'], 70 | 71 | // Run the build command with an extra argument to 72 | // View the bundle analyzer report after build finishes: 73 | // `npm run build --report` 74 | // Set to `true` or `false` to always turn it on or off 75 | bundleAnalyzerReport: process.env.npm_config_report 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /FrontendMobile/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | API_ROOT: '"/api"' 5 | } 6 | -------------------------------------------------------------------------------- /FrontendMobile/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Welcome to LPOJ 12 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/contest/contestsubmit.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 25 | 26 | 27 | 32 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/main.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 47 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/mainpage/wiki.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 74 | 75 | 76 | 78 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/utils/contestmini.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 66 | 67 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/utils/topuser.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 67 | 68 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/utils/welcomemessage.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 48 | 49 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/utils/wikidetail.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 55 | 56 | 57 | 59 | -------------------------------------------------------------------------------- /FrontendMobile/src/components/wiki/newalgorithm.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | 28 | 29 | 31 | -------------------------------------------------------------------------------- /FrontendMobile/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/FrontendMobile/static/.gitkeep -------------------------------------------------------------------------------- /HomePage/assets/css/owl.theme.default.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Owl Carousel v2.3.4 3 | * Copyright 2013-2018 David Deutsch 4 | * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE 5 | */ 6 | .owl-theme .owl-dots,.owl-theme .owl-nav{text-align:center;-webkit-tap-highlight-color:transparent}.owl-theme .owl-nav{margin-top:10px}.owl-theme .owl-nav [class*=owl-]{color:#FFF;font-size:14px;margin:5px;padding:4px 7px;background:#D6D6D6;display:inline-block;cursor:pointer;border-radius:3px}.owl-theme .owl-nav [class*=owl-]:hover{background:#869791;color:#FFF;text-decoration:none}.owl-theme .owl-nav .disabled{opacity:.5;cursor:default}.owl-theme .owl-nav.disabled+.owl-dots{margin-top:10px}.owl-theme .owl-dots .owl-dot{display:inline-block;zoom:1}.owl-theme .owl-dots .owl-dot span{width:10px;height:10px;margin:5px 7px;background:#D6D6D6;display:block;-webkit-backface-visibility:visible;transition:opacity .2s ease;border-radius:30px}.owl-theme .owl-dots .owl-dot.active span,.owl-theme .owl-dots .owl-dot:hover span{background:#869791} -------------------------------------------------------------------------------- /HomePage/assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /HomePage/assets/img/about/about-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/about/about-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/about/shape-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/about/shape-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/about/shape-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/about/shape-2.png -------------------------------------------------------------------------------- /HomePage/assets/img/about/shape-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/about/shape-3.png -------------------------------------------------------------------------------- /HomePage/assets/img/about/shape-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/about/shape-4.png -------------------------------------------------------------------------------- /HomePage/assets/img/breadcrumb/breadcrumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/breadcrumb/breadcrumb.png -------------------------------------------------------------------------------- /HomePage/assets/img/cta/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/cta/2.jpg -------------------------------------------------------------------------------- /HomePage/assets/img/cta/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/cta/5.png -------------------------------------------------------------------------------- /HomePage/assets/img/cta/cta-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/cta/cta-bg.jpg -------------------------------------------------------------------------------- /HomePage/assets/img/cta/cta-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/cta/cta-bg.png -------------------------------------------------------------------------------- /HomePage/assets/img/faqs/faqs-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/faqs/faqs-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/footer/foot-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/footer/foot-bg.png -------------------------------------------------------------------------------- /HomePage/assets/img/hero/hero-bg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/hero/hero-bg-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/logo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/logo-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/logo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/logo-2.png -------------------------------------------------------------------------------- /HomePage/assets/img/screen/screen-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/screen/screen-1.jpg -------------------------------------------------------------------------------- /HomePage/assets/img/screen/screen-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/screen/screen-2.jpg -------------------------------------------------------------------------------- /HomePage/assets/img/screen/screen-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/screen/screen-3.jpg -------------------------------------------------------------------------------- /HomePage/assets/img/screen/screen-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/screen/screen-4.jpg -------------------------------------------------------------------------------- /HomePage/assets/img/services/icon-1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/icon-1-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/icon-1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/icon-1-2.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/icon-1-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/icon-1-3.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/icon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/icon-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/icon-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/icon-2.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/icon-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/icon-3.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/shape-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/shape-1.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/shape-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/shape-2.png -------------------------------------------------------------------------------- /HomePage/assets/img/services/shape-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/HomePage/assets/img/services/shape-3.png -------------------------------------------------------------------------------- /HomePage/assets/img/top-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /HomePage/assets/js/ajax-form.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // Get the form. 4 | var form = $('#ajax-contact'); 5 | 6 | // Get the messages div. 7 | var formMessages = $('.form-message'); 8 | 9 | // Set up an event listener for the contact form. 10 | $(form).submit(function(e) { 11 | // Stop the browser from submitting the form. 12 | e.preventDefault(); 13 | 14 | // Serialize the form data. 15 | var formData = $(form).serialize(); 16 | 17 | // Submit the form using AJAX. 18 | $.ajax({ 19 | type: 'POST', 20 | url: $(form).attr('action'), 21 | data: formData 22 | }) 23 | .done(function(response) { 24 | // Make sure that the formMessages div has the 'success' class. 25 | $(formMessages).removeClass('error'); 26 | $(formMessages).addClass('success'); 27 | 28 | // Set the message text. 29 | $(formMessages).text(response); 30 | 31 | // Clear the form. 32 | $('#name').val(''); 33 | $('#email').val(''); 34 | $('#message').val(''); 35 | }) 36 | .fail(function(data) { 37 | // Make sure that the formMessages div has the 'error' class. 38 | $(formMessages).removeClass('success'); 39 | $(formMessages).addClass('error'); 40 | 41 | // Set the message text. 42 | if (data.responseText !== '') { 43 | $(formMessages).text(data.responseText); 44 | } else { 45 | $(formMessages).text('*Oops! An error occured and your message could not be sent.'); 46 | } 47 | }); 48 | 49 | }); 50 | 51 | }); -------------------------------------------------------------------------------- /HomePage/assets/js/counterup.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery.counterup.js 1.0 3 | * 4 | * Copyright 2013, Benjamin Intal http://gambit.ph @bfintal 5 | * Released under the GPL v2 License 6 | * 7 | * Date: Nov 26, 2013 8 | */(function(e){"use strict";e.fn.counterUp=function(t){var n=e.extend({time:400,delay:10},t);return this.each(function(){var t=e(this),r=n,i=function(){var e=[],n=r.time/r.delay,i=t.text(),s=/[0-9]+,[0-9]+/.test(i);i=i.replace(/,/g,"");var o=/^[0-9]+$/.test(i),u=/^[0-9]+\.[0-9]+$/.test(i),a=u?(i.split(".")[1]||[]).length:0;for(var f=n;f>=1;f--){var l=parseInt(i/n*f);u&&(l=parseFloat(i/n*f).toFixed(a));if(s)while(/(\d+)(\d{3})/.test(l.toString()))l=l.toString().replace(/(\d+)(\d{3})/,"$1,$2");e.unshift(l)}t.data("counterup-nums",e);t.text("0");var c=function(){t.text(t.data("counterup-nums").shift());if(t.data("counterup-nums").length)setTimeout(t.data("counterup-func"),r.delay);else{delete t.data("counterup-nums");t.data("counterup-nums",null);t.data("counterup-func",null)}};t.data("counterup-func",c);setTimeout(t.data("counterup-func"),r.delay)};t.waypoint(i,{offset:"100%",triggerOnce:!0})})}})(jQuery); -------------------------------------------------------------------------------- /HomePage/assets/js/plugins.js: -------------------------------------------------------------------------------- 1 | // Avoid `console` errors in browsers that lack a console. 2 | (function() { 3 | var method; 4 | var noop = function () {}; 5 | var methods = [ 6 | 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 7 | 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 8 | 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 9 | 'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn' 10 | ]; 11 | var length = methods.length; 12 | var console = (window.console = window.console || {}); 13 | 14 | while (length--) { 15 | method = methods[length]; 16 | 17 | // Only stub undefined methods. 18 | if (!console[method]) { 19 | console[method] = noop; 20 | } 21 | } 22 | }()); 23 | 24 | // Place any jQuery/helper plugins in here. 25 | -------------------------------------------------------------------------------- /Judger/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.5) 2 | project(judger C) 3 | 4 | #set(CMAKE_VERBOSE_MAKEFILE ON) 5 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output) 6 | 7 | set(CMAKE_C_FLAGS "-g -Wall -Werror -O3 -std=c99 -pie -fPIC") 8 | 9 | # make judger lib 10 | file(GLOB SOURCE "src/*.c" "src/rules/*.c") 11 | add_executable(libjudger.so ${SOURCE}) 12 | target_link_libraries(libjudger.so pthread seccomp) 13 | 14 | 15 | install(FILES output/libjudger.so 16 | PERMISSIONS OWNER_EXECUTE OWNER_READ 17 | DESTINATION /usr/lib/judger) 18 | -------------------------------------------------------------------------------- /Judger/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM swift:5.1 2 | MAINTAINER linzecong 3 | ADD . ./Judger 4 | WORKDIR /Judger 5 | RUN apt-get update 6 | RUN mv /usr/lib/python2.7/site-packages /usr/lib/python2.7/dist-packages 7 | RUN ln -s dist-packages /usr/lib/python2.7/site-packages 8 | RUN apt-get install python2.7 -y 9 | RUN apt-get install python3 -y 10 | RUN apt-get install python3-pip -y 11 | # RUN ln -s /usr/bin/python3 /usr/bin/python 12 | # RUN ln -s /usr/bin/pip3 /usr/bin/pip 13 | RUN apt-get install mysql-server -y 14 | RUN apt-get install mysql-client -y 15 | RUN apt-get install libatomic1 -y 16 | RUN apt-get install libssl-dev -y 17 | RUN apt-get install libz-dev -y 18 | RUN apt install pkg-config -y 19 | RUN apt install net-tools -y 20 | RUN apt install nano -y 21 | RUN apt-get install iputils-ping -y 22 | RUN apt-get install libmysqlclient-dev -y 23 | RUN pip3 install -r requirements.txt 24 | RUN apt-get install time -y 25 | RUN apt-get install cmake -y 26 | RUN apt-get install openjdk-8-jdk -y 27 | RUN apt-get install libseccomp-dev -y && mkdir build && cd build && cmake /Judger && make && make install && cd .. && cd JudgerCore && python3 setup.py install 28 | CMD ["python3", "main.py"] 29 | -------------------------------------------------------------------------------- /Judger/JudgerCore/_judger/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Judger/JudgerCore/_judger/__init__.pyc -------------------------------------------------------------------------------- /Judger/JudgerCore/setup.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from distutils.core import setup, Extension 3 | 4 | setup(name='_judger', 5 | version='2.1', 6 | packages=["_judger"]) -------------------------------------------------------------------------------- /Judger/ProblemData/README.md: -------------------------------------------------------------------------------- 1 | # 数据文件夹 2 | 3 | 判题机会自动通过HTTP从后端服务器下载数据并自动解压保存在ProblemData文件夹中,因此不要删除本目录 -------------------------------------------------------------------------------- /Judger/README.md: -------------------------------------------------------------------------------- 1 | 2 | # 感谢 QingdaoU/Judger 3 | 4 | # 原项目链接 https://github.com/QingdaoU/Judger 5 | 6 | 7 | ## Docker部署 8 | 非专业用户不推荐使用Docker单独部署 9 | 10 | 首先修改配置文件,setting.json里的东西都要修改为你的ip 11 | ``` 12 | cd Judger 13 | nano setting.json 14 | ``` 15 | 接着运行容器 16 | ``` 17 | docker build -t lpojjudger . 18 | docker run -d lpojjudger 19 | ``` 20 | 21 | ## 一般部署 22 | 23 | 首先修改配置文件,setting.json里的东西都要修改为你的ip 24 | 25 | 如果你需要Python判题,那么请注意修改python_path 26 | 27 | 你可以使用 whereis python 命名查看python路径 28 | 29 | 30 | ``` 31 | cd Judger 32 | nano setting.json 33 | ``` 34 | 35 | ##### 安装步骤 36 | 1. sudo apt-get install libseccomp-dev 37 | 2. mkdir build && cd build && cmake .. && make && sudo make install 38 | 3. cd .. 39 | 4. cd JudgerCore 40 | 5. sudo python setup.py install 41 | 6. pip install paramiko 42 | 7. pip install mysqlclient 43 | 44 | ###### 运行 45 | 1. sudo python main.py 46 | 47 | # 详细测试 48 | 参考 https://github.com/QingdaoU/Judger 中的 unittest 49 | 50 | # 参数解释 51 | 52 | ## result 53 | WAITING = -6 54 | PRESENTATION_ERROR = -5 55 | COMPILE_ERROR = -4 56 | WRONG_ANSWER = -3 57 | PENDING = -1 58 | JUDGINNG = -2 59 | CPU_TIME_LIMIT_EXCEEDED = 1 60 | REAL_TIME_LIMIT_EXCEEDED = 2 61 | MEMORY_LIMIT_EXCEEDED = 3 62 | RUNTIME_ERROR = 4 63 | SYSTEM_ERROR = 5 64 | 65 | ## error 66 | SUCCESS = 0 67 | INVALID_CONFIG = -1 68 | FORK_FAILED = -2 69 | PTHREAD_FAILED = -3 70 | WAIT_FAILED = -4 71 | ROOT_REQUIRED = -5 72 | LOAD_SECCOMP_FAILED = -6 73 | SETRLIMIT_FAILED = -7 74 | DUP2_FAILED = -8 75 | SETUID_FAILED = -9 76 | EXECVE_FAILED = -10 77 | SPJ_ERROR = -11 (judger module will never return this value, it's used for awswer checker) -------------------------------------------------------------------------------- /Judger/datatime.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } -------------------------------------------------------------------------------- /Judger/output/libjudger.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Linzecong/LPOJ/2f7ce194f1d510d8d006c2a35fdaa272f20ef1f3/Judger/output/libjudger.so -------------------------------------------------------------------------------- /Judger/requirements.txt: -------------------------------------------------------------------------------- 1 | paramiko==2.4.2 2 | mysqlclient==1.4.2.post1 3 | requests==2.20.0 -------------------------------------------------------------------------------- /Judger/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_user":"root", 3 | "db_pass":"504603913", 4 | "db_ip":"localhost", 5 | "db_port":"3306", 6 | "db_database":"LPOJ", 7 | "server_ip":"localhost", 8 | "server_port":9906, 9 | "backend_ip":"localhost", 10 | "backend_port":8000, 11 | "backend_head":"http", 12 | "python3_path": "/usr/bin/python3", 13 | "python2_path": "/usr/bin/python2.7", 14 | "nodownload":"no" 15 | } -------------------------------------------------------------------------------- /Judger/src/child.h: -------------------------------------------------------------------------------- 1 | #ifndef JUDGER_CHILD_H 2 | #define JUDGER_CHILD_H 3 | 4 | #include 5 | #include "runner.h" 6 | 7 | #define CHILD_ERROR_EXIT(error_code)\ 8 | {\ 9 | LOG_FATAL(log_fp, "Error: System errno: %s; Internal errno: "#error_code, strerror(errno)); \ 10 | close_file(input_file); \ 11 | if (output_file == error_file) { \ 12 | close_file(output_file); \ 13 | } else { \ 14 | close_file(output_file); \ 15 | close_file(error_file); \ 16 | } \ 17 | raise(SIGUSR1); \ 18 | exit(EXIT_FAILURE); \ 19 | } 20 | 21 | 22 | void child_process(FILE *log_fp, struct config *_config); 23 | 24 | #endif //JUDGER_CHILD_H 25 | -------------------------------------------------------------------------------- /Judger/src/killer.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_SOURCE 2 | #include 3 | #include 4 | #include 5 | 6 | #include "killer.h" 7 | 8 | 9 | int kill_pid(pid_t pid) { 10 | return kill(pid, SIGKILL); 11 | } 12 | 13 | 14 | void *timeout_killer(void *timeout_killer_args) { 15 | // this is a new thread, kill the process if timeout 16 | pid_t pid = ((struct timeout_killer_args *)timeout_killer_args)->pid; 17 | int timeout = ((struct timeout_killer_args *)timeout_killer_args)->timeout; 18 | // On success, pthread_detach() returns 0; on error, it returns an error number. 19 | if (pthread_detach(pthread_self()) != 0) { 20 | kill_pid(pid); 21 | return NULL; 22 | } 23 | // usleep can't be used, for time args must < 1000ms 24 | // this may sleep longer that expected, but we will have a check at the end 25 | if (sleep((unsigned int)((timeout + 1000) / 1000)) != 0) { 26 | kill_pid(pid); 27 | return NULL; 28 | } 29 | if (kill_pid(pid) != 0) { 30 | return NULL; 31 | } 32 | return NULL; 33 | } -------------------------------------------------------------------------------- /Judger/src/killer.h: -------------------------------------------------------------------------------- 1 | #ifndef JUDGER_KILLER_H 2 | #define JUDGER_KILLER_H 3 | 4 | struct timeout_killer_args { 5 | int pid; 6 | int timeout; 7 | }; 8 | 9 | int kill_pid(pid_t pid); 10 | 11 | void *timeout_killer(void *timeout_killer_args); 12 | 13 | #endif //JUDGER_KILLER_H 14 | -------------------------------------------------------------------------------- /Judger/src/logger.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "logger.h" 10 | 11 | #define log_buffer_size 8192 12 | 13 | 14 | FILE *log_open(const char *filename) { 15 | FILE *log_fp = fopen(filename, "a"); 16 | if (log_fp == NULL) { 17 | fprintf(stderr, "can not open log file %s", filename); 18 | } 19 | return log_fp; 20 | } 21 | 22 | 23 | void log_close(FILE *log_fp) { 24 | if (log_fp != NULL) { 25 | fclose(log_fp); 26 | } 27 | } 28 | 29 | 30 | void log_write(int level, const char *source_filename, const int line, const FILE *log_fp, const char *fmt, ...) { 31 | char LOG_LEVEL_NOTE[][10] = {"FATAL", "WARNING", "INFO", "DEBUG"}; 32 | if (log_fp == NULL) { 33 | fprintf(stderr, "can not open log file"); 34 | return; 35 | } 36 | static char buffer[log_buffer_size]; 37 | static char log_buffer[log_buffer_size]; 38 | static char datetime[100]; 39 | static char line_str[20]; 40 | static time_t now; 41 | now = time(NULL); 42 | 43 | strftime(datetime, 99, "%Y-%m-%d %H:%M:%S", localtime(&now)); 44 | snprintf(line_str, 19, "%d", line); 45 | va_list ap; 46 | va_start(ap, fmt); 47 | vsnprintf(log_buffer, log_buffer_size, fmt, ap); 48 | va_end(ap); 49 | 50 | int count = snprintf(buffer, log_buffer_size, 51 | "%s [%s] [%s:%s]%s\n", 52 | LOG_LEVEL_NOTE[level], datetime, source_filename, line_str, log_buffer); 53 | // fprintf(stderr, "%s", buffer); 54 | int log_fd = fileno((FILE *) log_fp); 55 | if (flock(log_fd, LOCK_EX) == 0) { 56 | if (write(log_fd, buffer, (size_t) count) < 0) { 57 | fprintf(stderr, "write error"); 58 | return; 59 | } 60 | flock(log_fd, LOCK_UN); 61 | } 62 | else { 63 | fprintf(stderr, "flock error"); 64 | return; 65 | } 66 | } -------------------------------------------------------------------------------- /Judger/src/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef JUDGER_LOGGER_H 2 | #define JUDGER_LOGGER_H 3 | 4 | #define LOG_LEVEL_FATAL 0 5 | #define LOG_LEVEL_WARNING 1 6 | #define LOG_LEVEL_INFO 2 7 | #define LOG_LEVEL_DEBUG 3 8 | 9 | 10 | FILE *log_open(const char *); 11 | 12 | void log_close(FILE *); 13 | 14 | void log_write(int level, const char *source_filename, const int line_number, const FILE *log_fp, const char *, ...); 15 | 16 | #ifdef JUDGER_DEBUG 17 | #define LOG_DEBUG(log_fp, x...) log_write(LOG_LEVEL_DEBUG, __FILE__, __LINE__, log_fp, ##x) 18 | #else 19 | #define LOG_DEBUG(log_fp, x...) 20 | #endif 21 | 22 | #define LOG_INFO(log_fp, x...) log_write(LOG_LEVEL_INFO, __FILE__, __LINE__, log_fp, ##x) 23 | #define LOG_WARNING(log_fp, x...) log_write(LOG_LEVEL_WARNING, __FILE__, __LINE__, log_fp, ##x) 24 | #define LOG_FATAL(log_fp, x...) log_write(LOG_LEVEL_FATAL, __FILE__, __LINE__, log_fp, ##x) 25 | 26 | #endif //JUDGER_LOGGER_H 27 | -------------------------------------------------------------------------------- /Judger/src/rules/c_cpp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../runner.h" 8 | 9 | 10 | int c_cpp_seccomp_rules(struct config *_config) { 11 | int syscalls_whitelist[] = {SCMP_SYS(read), SCMP_SYS(fstat), 12 | SCMP_SYS(mmap), SCMP_SYS(mprotect), 13 | SCMP_SYS(munmap), SCMP_SYS(uname), 14 | SCMP_SYS(arch_prctl), SCMP_SYS(brk), 15 | SCMP_SYS(access), SCMP_SYS(exit_group), 16 | SCMP_SYS(close), SCMP_SYS(readlink), 17 | SCMP_SYS(sysinfo), SCMP_SYS(write), 18 | SCMP_SYS(writev), SCMP_SYS(lseek)}; 19 | 20 | int syscalls_whitelist_length = sizeof(syscalls_whitelist) / sizeof(int); 21 | scmp_filter_ctx ctx = NULL; 22 | // load seccomp rules 23 | ctx = seccomp_init(SCMP_ACT_KILL); 24 | if (!ctx) { 25 | return LOAD_SECCOMP_FAILED; 26 | } 27 | for (int i = 0; i < syscalls_whitelist_length; i++) { 28 | if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls_whitelist[i], 0) != 0) { 29 | return LOAD_SECCOMP_FAILED; 30 | } 31 | } 32 | // add extra rule for execve 33 | if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(execve), 1, SCMP_A0(SCMP_CMP_EQ, (scmp_datum_t)(_config->exe_path))) != 0) { 34 | return LOAD_SECCOMP_FAILED; 35 | } 36 | // do not allow "w" and "rw" 37 | if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1, SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) != 0) { 38 | return LOAD_SECCOMP_FAILED; 39 | } 40 | if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 1, SCMP_CMP(2, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) != 0) { 41 | return LOAD_SECCOMP_FAILED; 42 | } 43 | if (seccomp_load(ctx) != 0) { 44 | return LOAD_SECCOMP_FAILED; 45 | } 46 | seccomp_release(ctx); 47 | return 0; 48 | } -------------------------------------------------------------------------------- /Judger/src/rules/general.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../runner.h" 9 | 10 | 11 | int general_seccomp_rules(struct config *_config) { 12 | int syscalls_blacklist[] = {//SCMP_SYS(clone), 13 | SCMP_SYS(fork), SCMP_SYS(vfork), 14 | SCMP_SYS(kill), 15 | #ifdef __NR_execveat 16 | SCMP_SYS(execveat) 17 | #endif 18 | }; 19 | int syscalls_blacklist_length = sizeof(syscalls_blacklist) / sizeof(int); 20 | scmp_filter_ctx ctx = NULL; 21 | // load seccomp rules 22 | ctx = seccomp_init(SCMP_ACT_ALLOW); 23 | if (!ctx) { 24 | return LOAD_SECCOMP_FAILED; 25 | } 26 | for (int i = 0; i < syscalls_blacklist_length; i++) { 27 | if (seccomp_rule_add(ctx, SCMP_ACT_KILL, syscalls_blacklist[i], 0) != 0) { 28 | return LOAD_SECCOMP_FAILED; 29 | } 30 | } 31 | // use SCMP_ACT_KILL for socket, python will be killed immediately 32 | // if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(socket), 0) != 0) { 33 | // return LOAD_SECCOMP_FAILED; 34 | // } 35 | // add extra rule for execve 36 | if (seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 1, SCMP_A0(SCMP_CMP_NE, (scmp_datum_t)(_config->exe_path))) != 0) { 37 | return LOAD_SECCOMP_FAILED; 38 | } 39 | // do not allow "w" and "rw" using open 40 | if (seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(open), 1, SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) != 0) { 41 | return LOAD_SECCOMP_FAILED; 42 | } 43 | if (seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(open), 1, SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) != 0) { 44 | return LOAD_SECCOMP_FAILED; 45 | } 46 | // do not allow "w" and "rw" using openat 47 | if (seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(openat), 1, SCMP_CMP(2, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) != 0) { 48 | return LOAD_SECCOMP_FAILED; 49 | } 50 | if (seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(openat), 1, SCMP_CMP(2, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) != 0) { 51 | return LOAD_SECCOMP_FAILED; 52 | } 53 | 54 | if (seccomp_load(ctx) != 0) { 55 | return LOAD_SECCOMP_FAILED; 56 | } 57 | seccomp_release(ctx); 58 | return 0; 59 | } -------------------------------------------------------------------------------- /Judger/src/rules/seccomp_rules.h: -------------------------------------------------------------------------------- 1 | #ifndef JUDGER_SECCOMP_RULES_H 2 | #define JUDGER_SECCOMP_RULES_H 3 | #include "../runner.h" 4 | 5 | int c_cpp_seccomp_rules(struct config *_config); 6 | int general_seccomp_rules(struct config *_config); 7 | 8 | #endif //JUDGER_SECCOMP_RULES_H 9 | -------------------------------------------------------------------------------- /Judger/src/runner.h: -------------------------------------------------------------------------------- 1 | #ifndef JUDGER_RUNNER_H 2 | #define JUDGER_RUNNER_H 3 | 4 | #include 5 | #include 6 | 7 | // (ver >> 16) & 0xff, (ver >> 8) & 0xff, ver & 0xff -> real version 8 | #define VERSION 0x020101 9 | 10 | #define UNLIMITED -1 11 | 12 | #define LOG_ERROR(error_code) LOG_FATAL(log_fp, "Error: "#error_code); 13 | 14 | #define ERROR_EXIT(error_code)\ 15 | {\ 16 | LOG_ERROR(error_code); \ 17 | _result->error = error_code; \ 18 | log_close(log_fp); \ 19 | return; \ 20 | } 21 | 22 | #define ARGS_MAX_NUMBER 256 23 | #define ENV_MAX_NUMBER 256 24 | 25 | 26 | enum { 27 | SUCCESS = 0, 28 | INVALID_CONFIG = -1, 29 | FORK_FAILED = -2, 30 | PTHREAD_FAILED = -3, 31 | WAIT_FAILED = -4, 32 | ROOT_REQUIRED = -5, 33 | LOAD_SECCOMP_FAILED = -6, 34 | SETRLIMIT_FAILED = -7, 35 | DUP2_FAILED = -8, 36 | SETUID_FAILED = -9, 37 | EXECVE_FAILED = -10, 38 | SPJ_ERROR = -11 39 | }; 40 | 41 | 42 | struct config { 43 | int max_cpu_time; 44 | int max_real_time; 45 | long max_memory; 46 | long max_stack; 47 | int max_process_number; 48 | long max_output_size; 49 | int memory_limit_check_only; 50 | char *exe_path; 51 | char *input_path; 52 | char *output_path; 53 | char *error_path; 54 | char *args[ARGS_MAX_NUMBER]; 55 | char *env[ENV_MAX_NUMBER]; 56 | char *log_path; 57 | char *seccomp_rule_name; 58 | uid_t uid; 59 | gid_t gid; 60 | }; 61 | 62 | 63 | enum { 64 | WRONG_ANSWER = -1, 65 | CPU_TIME_LIMIT_EXCEEDED = 1, 66 | REAL_TIME_LIMIT_EXCEEDED = 2, 67 | MEMORY_LIMIT_EXCEEDED = 3, 68 | RUNTIME_ERROR = 4, 69 | SYSTEM_ERROR = 5 70 | }; 71 | 72 | 73 | struct result { 74 | int cpu_time; 75 | int real_time; 76 | long memory; 77 | int signal; 78 | int exit_code; 79 | int error; 80 | int result; 81 | }; 82 | 83 | 84 | void run(struct config *, struct result *); 85 | #endif //JUDGER_RUNNER_H 86 | -------------------------------------------------------------------------------- /JudgerServer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.2 2 | MAINTAINER linzecong 3 | ADD . ./JudgerServer 4 | WORKDIR /JudgerServer 5 | RUN pip install -r requirements.txt 6 | EXPOSE 9906 7 | CMD ["python", "main.py"] 8 | 9 | -------------------------------------------------------------------------------- /JudgerServer/README.md: -------------------------------------------------------------------------------- 1 | # 判题服务器部署 2 | 3 | ## Docker部署 4 | 非专业用户不推荐使用Docker单独部署 5 | 6 | 首先修改配置文件,setting.json里的东西都要修改为你的ip 7 | ``` 8 | cd JudgerServer 9 | nano setting.json 10 | ``` 11 | 接着运行容器 12 | ``` 13 | docker build -t lpojjudgerserver . 14 | docker run -d -p 9906:9906 lpojjudgerserver 15 | ``` 16 | 17 | ## 一般部署 18 | 首先修改配置文件 19 | ``` 20 | cd JudgeServer 21 | nano setting.json 22 | ``` 23 | 修改对应的数据库IP和端口保存退出 24 | ``` 25 | pip install mysqlclient 26 | sudo python main.py 27 | ``` -------------------------------------------------------------------------------- /JudgerServer/requirements.txt: -------------------------------------------------------------------------------- 1 | mysqlclient==1.4.2.post1 -------------------------------------------------------------------------------- /JudgerServer/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_user":"root", 3 | "db_pass":"504603913", 4 | "db_ip":"localhost", 5 | "db_port":"3306", 6 | "db_database":"LPOJ", 7 | "server_port":9906 8 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-present OnineJudge 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Tools/README.md: -------------------------------------------------------------------------------- 1 | # 这是各种工具文件夹,使用方法详见 [docs.lpoj.cn](https://docs.lpoj.cn) -------------------------------------------------------------------------------- /Tools/RaiseCheck.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | import MySQLdb 6 | from queue import Queue 7 | import socket 8 | import json 9 | from time import sleep 10 | import threading 11 | import os 12 | 13 | 14 | queue = Queue() # 全局判题列表 15 | myjsonfile = open("./setting.json", 'r') 16 | judgerjson = json.loads(myjsonfile.read()) 17 | 18 | if os.environ.get("DB_USER"): 19 | judgerjson["db_ip"] = os.environ.get("DB_HOST") 20 | judgerjson["db_pass"] = os.environ.get("DB_PASSWORD") 21 | judgerjson["db_user"] = os.environ.get("DB_USER") 22 | judgerjson["db_port"] = os.environ.get("DB_PORT") 23 | 24 | try: 25 | db = MySQLdb.connect(judgerjson["db_ip"], judgerjson["db_user"], judgerjson["db_pass"], 26 | judgerjson["db_database"], int(judgerjson["db_port"]), charset='utf8') 27 | except Exception as e: 28 | print(e) 29 | exit(1) 30 | 31 | 32 | cursor = db.cursor() 33 | 34 | cursor.execute("SELECT user, code from judgestatus_judgestatus") 35 | data = cursor.fetchall() 36 | 37 | raisenum = {} 38 | 39 | for d in data: 40 | id = str(d[0]) 41 | code = str(d[1]) 42 | raisenum[id] = 0 43 | 44 | for d in data: 45 | id = str(d[0]) 46 | code = str(d[1]) 47 | raisenum[id] = max(raisenum[id], code.count("raise")) 48 | 49 | li = sorted(raisenum.items(), key=lambda item:item[1],reverse=True) 50 | 51 | file = open("raisenum.txt", "w") 52 | 53 | for l in li: 54 | file.write(l[0]+" "+str(l[1])+'\n') 55 | print(l[0]+" "+str(l[1])) 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Tools/RecoverBoard.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import MySQLdb 4 | import socket 5 | import json 6 | import time 7 | import os 8 | from time import sleep 9 | import datetime 10 | 11 | myjsonfile = open("./setting.json", 'r') 12 | judgerjson = json.loads(myjsonfile.read()) 13 | 14 | try: 15 | db = MySQLdb.connect(judgerjson["db_ip"], judgerjson["db_user"], judgerjson["db_pass"], 16 | judgerjson["db_database"], int(judgerjson["db_port"]), charset='utf8') 17 | except Exception as e: 18 | print(e) 19 | exit(1) 20 | 21 | 22 | source_conntest = 100 # 比赛ID 23 | des_conntest = 101 # 复制到哪个比赛 24 | 25 | cursor = db.cursor() 26 | cursor.execute("SELECT * from judgestatus_judgestatus where contest = %d "%source_conntest) # contest 27 | 28 | datas = cursor.fetchall() 29 | 30 | for data in datas: 31 | 32 | id = data[0] 33 | username = data[1] 34 | cursor.execute("SELECT * from user_user where username=%s",(username,)) 35 | name = cursor.fetchone()[2] 36 | 37 | rank = ord(data[16]) - 65 38 | contestid = des_conntest 39 | 40 | result = data[4] 41 | type = -1 42 | if result == 0: 43 | type = 1 44 | elif type != -4 and type != -1 and type != -6 and type != -2 and type != 5: 45 | type = 0 46 | 47 | 48 | subtime = data[9] 49 | 50 | subtime = int(subtime.timestamp() * 1000) 51 | 52 | print(contestid,username,name,rank,type,subtime,id,1500) # contest 53 | 54 | 55 | #cursor.execute("INSERT INTO contest_contestboard(contestid,username,user,problemrank,type,submittime,submitid,rating) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)",(contestid,username,name,rank,type,subtime,id,1500)) 56 | # (username, totleac, today, username, today)) 57 | 58 | 59 | #db.commit() -------------------------------------------------------------------------------- /Tools/UserImporter.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import requests 3 | from time import sleep 4 | import sys 5 | import hashlib 6 | # 暂时做成txt中导入,后面再加入从表格中读取 7 | 8 | def insertUser(username, password, name, school="unknow", course="unknow", classes="unknow", number="unknow", realname="unknow", qq="unknow", email="unknow", type=1): 9 | 10 | # 待加密信息 11 | # 创建md5对象 12 | hl = hashlib.md5() 13 | hl.update(password.encode(encoding='utf-8')) 14 | password = hl.hexdigest() 15 | print(password) 16 | 17 | userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" 18 | header = { 19 | 'User-Agent': userAgent, 20 | } 21 | 22 | mafengwoSession = requests.session() 23 | 24 | password2 = '123456' 25 | # 创建md5对象 26 | h2 = hashlib.md5() 27 | h2.update(password2.encode(encoding='utf-8')) 28 | password2 = h2.hexdigest() 29 | 30 | loginUrl = "https://www.lpoj.cn/api/login" # 登录 url 31 | loginData = { 32 | "username": "admin", # 管理员用户名和密码 33 | "password": password2, 34 | } 35 | responseRes = mafengwoSession.post( 36 | loginUrl, data=loginData, headers=header, allow_redirects=True) 37 | print(responseRes.text) 38 | 39 | postUrl = "https://www.lpoj.cn/api/register" # 注册 url 40 | postData = { 41 | "username": username, 42 | "password": password, 43 | "name" :name, 44 | "school" : school, 45 | "course" : course, 46 | "classes" : classes, 47 | "number" : number, 48 | "realname" : realname, 49 | "qq" : qq, 50 | "email" :email, 51 | "type" :1 52 | } 53 | responseRes = mafengwoSession.post(postUrl, data=postData, headers=header) 54 | print(responseRes.text) 55 | 56 | if __name__ == "__main__": 57 | file = open(sys.argv[1],"r",encoding='utf-8') 58 | lines = file.readlines() 59 | for line in lines: 60 | items = line.split(" ") 61 | print(items) 62 | insertUser(items[0], items[1], items[2]) 63 | sleep(0.3) 64 | -------------------------------------------------------------------------------- /Tools/setting.json: -------------------------------------------------------------------------------- 1 | { 2 | "db_user":"root", 3 | "db_pass":"504603913", 4 | "db_ip":"localhost", 5 | "db_port":"3306", 6 | "db_database":"LPOJ" 7 | } --------------------------------------------------------------------------------