├── .env.dist ├── .gitignore ├── LICENSE ├── README.md ├── bin ├── console └── phpunit ├── composer.json ├── composer.lock ├── config ├── bundles.php ├── packages │ ├── assets.yaml │ ├── dev │ │ ├── debug.yaml │ │ ├── easy_log_handler.yaml │ │ ├── monolog.yaml │ │ ├── routing.yaml │ │ ├── swiftmailer.yaml │ │ └── web_profiler.yaml │ ├── doctrine.yaml │ ├── doctrine_migrations.yaml │ ├── framework.yaml │ ├── prod │ │ ├── doctrine.yaml │ │ └── monolog.yaml │ ├── routing.yaml │ ├── security.yaml │ ├── sensio_framework_extra.yaml │ ├── swiftmailer.yaml │ ├── test │ │ ├── framework.yaml │ │ ├── monolog.yaml │ │ ├── swiftmailer.yaml │ │ └── web_profiler.yaml │ ├── translation.yaml │ ├── twig.yaml │ └── validator.yaml ├── routes.yaml ├── routes │ ├── annotations.yaml │ └── dev │ │ ├── twig.yaml │ │ └── web_profiler.yaml └── services.yaml ├── package.json ├── phpunit.xml.dist ├── public ├── assets │ ├── css │ │ ├── index.css │ │ └── level.css │ └── js │ │ ├── level.js │ │ └── tablesort.js ├── eula.html ├── index.php └── res │ └── level_base.html.twig ├── src ├── Controller │ ├── .gitignore │ ├── EditorController.php │ ├── IndexController.php │ ├── NazoController.php │ └── UserController.php ├── Entity │ ├── .gitignore │ ├── Level.php │ └── User.php ├── Kernel.php └── Repository │ ├── .gitignore │ ├── LevelRepository.php │ └── UserRepository.php ├── symfony.lock ├── templates ├── base.html.twig ├── editor.html.twig ├── index.html.twig └── levels │ └── level_base.html.twig └── webpack.config.js /.env.dist: -------------------------------------------------------------------------------- 1 | # This file is a "template" of which env vars need to be defined for your application 2 | # Copy this file to .env file for development, create environment variables when deploying to production 3 | # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration 4 | 5 | ###> symfony/framework-bundle ### 6 | APP_ENV=dev 7 | APP_SECRET=a3254a7dabc3c098c4467e895d0d7d7b 8 | #TRUSTED_PROXIES=127.0.0.1,127.0.0.2 9 | #TRUSTED_HOSTS=localhost,example.com 10 | ###< symfony/framework-bundle ### 11 | 12 | ###> doctrine/doctrine-bundle ### 13 | # Format described at http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url 14 | # For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" 15 | # Configure your db driver and server_version in config/packages/doctrine.yaml 16 | DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name 17 | ###< doctrine/doctrine-bundle ### 18 | 19 | ###> symfony/swiftmailer-bundle ### 20 | # For Gmail as a transport, use: "gmail://username:password@localhost" 21 | # For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode=" 22 | # Delivery is disabled by default via "null://localhost" 23 | MAILER_URL=null://localhost 24 | ###< symfony/swiftmailer-bundle ### 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ###> symfony/framework-bundle ### 3 | /.env 4 | /public/bundles/ 5 | /var/ 6 | /vendor/ 7 | ###< symfony/framework-bundle ### 8 | 9 | ###> symfony/webpack-encore-pack ### 10 | /node_modules/ 11 | /public/build/ 12 | npm-debug.log 13 | yarn-error.log 14 | ###< symfony/webpack-encore-pack ### 15 | 16 | ###> symfony/phpunit-bridge ### 17 | .phpunit 18 | /phpunit.xml 19 | ###< symfony/phpunit-bridge ### 20 | 21 | ###> symfony/web-server-bundle ### 22 | /.web-server-pid 23 | ###< symfony/web-server-bundle ### 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Null 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CipherGameFramework 2 | This is the framework that nazo.games uses. It is written in php 7.2 and uses Symfony as its framework. 3 | 4 | It is not recommended to use this framwork directly. 5 | That being said, you have rights to do whatever you want with it 6 | as long as you follow the [LICENSE](https://github.com/harrynull/CipherGameFramework/blob/master/LICENSE). 7 | 8 | ## License 9 | 10 | MIT License 11 | 12 | Copyright (c) 2018 Null 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in all 22 | copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | SOFTWARE. -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | load(__DIR__.'/../.env'); 23 | } 24 | 25 | $input = new ArgvInput(); 26 | $env = $input->getParameterOption(['--env', '-e'], $_SERVER['APP_ENV'] ?? 'dev', true); 27 | $debug = (bool) ($_SERVER['APP_DEBUG'] ?? ('prod' !== $env)) && !$input->hasParameterOption('--no-debug', true); 28 | 29 | if ($debug) { 30 | umask(0000); 31 | 32 | if (class_exists(Debug::class)) { 33 | Debug::enable(); 34 | } 35 | } 36 | 37 | $kernel = new Kernel($env, $debug); 38 | $application = new Application($kernel); 39 | $application->run($input); 40 | -------------------------------------------------------------------------------- /bin/phpunit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | ['all' => true], 5 | Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], 6 | Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], 7 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], 8 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], 9 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], 10 | Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true], 11 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], 12 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], 13 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], 14 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], 15 | Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], 16 | Symfony\Bundle\WebServerBundle\WebServerBundle::class => ['dev' => true], 17 | ]; 18 | -------------------------------------------------------------------------------- /config/packages/assets.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | assets: 3 | json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' 4 | -------------------------------------------------------------------------------- /config/packages/dev/debug.yaml: -------------------------------------------------------------------------------- 1 | debug: 2 | # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. 3 | # See the "server:dump" command to start a new server. 4 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" 5 | -------------------------------------------------------------------------------- /config/packages/dev/easy_log_handler.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | EasyCorp\EasyLog\EasyLogHandler: 3 | public: false 4 | arguments: ['%kernel.logs_dir%/%kernel.environment%.log'] 5 | 6 | #// FIXME: How to add this configuration automatically without messing up with the monolog configuration? 7 | #monolog: 8 | # handlers: 9 | # buffered: 10 | # type: buffer 11 | # handler: easylog 12 | # channels: ['!event'] 13 | # level: debug 14 | # easylog: 15 | # type: service 16 | # id: EasyCorp\EasyLog\EasyLogHandler 17 | -------------------------------------------------------------------------------- /config/packages/dev/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: debug 7 | channels: ["!event"] 8 | # uncomment to get logging in your browser 9 | # you may have to allow bigger header sizes in your Web server configuration 10 | #firephp: 11 | # type: firephp 12 | # level: info 13 | #chromephp: 14 | # type: chromephp 15 | # level: info 16 | console: 17 | type: console 18 | process_psr_3_messages: false 19 | channels: ["!event", "!doctrine", "!console"] 20 | -------------------------------------------------------------------------------- /config/packages/dev/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /config/packages/dev/swiftmailer.yaml: -------------------------------------------------------------------------------- 1 | # See https://symfony.com/doc/current/email/dev_environment.html 2 | swiftmailer: 3 | # send all emails to a specific address 4 | #delivery_addresses: ['me@example.com'] 5 | -------------------------------------------------------------------------------- /config/packages/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: true 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { only_exceptions: false } 7 | -------------------------------------------------------------------------------- /config/packages/doctrine.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Adds a fallback DATABASE_URL if the env var is not set. 3 | # This allows you to run cache:warmup even if your 4 | # environment variables are not available yet. 5 | # You should not need to change this value. 6 | env(DATABASE_URL): '' 7 | 8 | doctrine: 9 | dbal: 10 | # configure these for your database server 11 | driver: 'pdo_mysql' 12 | server_version: '5.7' 13 | charset: utf8mb4 14 | default_table_options: 15 | charset: utf8mb4 16 | collate: utf8mb4_unicode_ci 17 | 18 | url: '%env(resolve:DATABASE_URL)%' 19 | orm: 20 | auto_generate_proxy_classes: '%kernel.debug%' 21 | naming_strategy: doctrine.orm.naming_strategy.underscore 22 | auto_mapping: true 23 | mappings: 24 | App: 25 | is_bundle: false 26 | type: annotation 27 | dir: '%kernel.project_dir%/src/Entity' 28 | prefix: 'App\Entity' 29 | alias: App 30 | -------------------------------------------------------------------------------- /config/packages/doctrine_migrations.yaml: -------------------------------------------------------------------------------- 1 | doctrine_migrations: 2 | dir_name: '%kernel.project_dir%/src/Migrations' 3 | # namespace is arbitrary but should be different from App\Migrations 4 | # as migrations classes should NOT be autoloaded 5 | namespace: DoctrineMigrations 6 | -------------------------------------------------------------------------------- /config/packages/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | secret: '%env(APP_SECRET)%' 3 | #default_locale: en 4 | #csrf_protection: true 5 | #http_method_override: true 6 | 7 | # Enables session support. Note that the session will ONLY be started if you read or write from it. 8 | # Remove or comment this section to explicitly disable session support. 9 | session: 10 | handler_id: ~ 11 | 12 | #esi: true 13 | #fragments: true 14 | php_errors: 15 | log: true 16 | 17 | cache: 18 | # Put the unique name of your app here: the prefix seed 19 | # is used to compute stable namespaces for cache keys. 20 | #prefix_seed: your_vendor_name/app_name 21 | 22 | # The app cache caches to the filesystem by default. 23 | # Other options include: 24 | 25 | # Redis 26 | #app: cache.adapter.redis 27 | #default_redis_provider: redis://localhost 28 | 29 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) 30 | #app: cache.adapter.apcu 31 | -------------------------------------------------------------------------------- /config/packages/prod/doctrine.yaml: -------------------------------------------------------------------------------- 1 | doctrine: 2 | orm: 3 | metadata_cache_driver: 4 | type: service 5 | id: doctrine.system_cache_provider 6 | query_cache_driver: 7 | type: service 8 | id: doctrine.system_cache_provider 9 | result_cache_driver: 10 | type: service 11 | id: doctrine.result_cache_provider 12 | 13 | services: 14 | doctrine.result_cache_provider: 15 | class: Symfony\Component\Cache\DoctrineProvider 16 | public: false 17 | arguments: 18 | - '@doctrine.result_cache_pool' 19 | doctrine.system_cache_provider: 20 | class: Symfony\Component\Cache\DoctrineProvider 21 | public: false 22 | arguments: 23 | - '@doctrine.system_cache_pool' 24 | 25 | framework: 26 | cache: 27 | pools: 28 | doctrine.result_cache_pool: 29 | adapter: cache.app 30 | doctrine.system_cache_pool: 31 | adapter: cache.system 32 | -------------------------------------------------------------------------------- /config/packages/prod/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: fingers_crossed 5 | action_level: error 6 | handler: nested 7 | excluded_404s: 8 | # regex: exclude all 404 errors from the logs 9 | - ^/ 10 | nested: 11 | type: stream 12 | path: "%kernel.logs_dir%/%kernel.environment%.log" 13 | level: debug 14 | console: 15 | type: console 16 | process_psr_3_messages: false 17 | channels: ["!event", "!doctrine"] 18 | -------------------------------------------------------------------------------- /config/packages/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: ~ 4 | -------------------------------------------------------------------------------- /config/packages/security.yaml: -------------------------------------------------------------------------------- 1 | security: 2 | # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers 3 | providers: 4 | in_memory: { memory: ~ } 5 | firewalls: 6 | dev: 7 | pattern: ^/(_(profiler|wdt)|css|images|js)/ 8 | security: false 9 | main: 10 | anonymous: true 11 | 12 | # activate different ways to authenticate 13 | 14 | # http_basic: true 15 | # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate 16 | 17 | # form_login: true 18 | # https://symfony.com/doc/current/security/form_login_setup.html 19 | 20 | # Easy way to control access for large sections of your site 21 | # Note: Only the *first* access control that matches will be used 22 | access_control: 23 | # - { path: ^/admin, roles: ROLE_ADMIN } 24 | # - { path: ^/profile, roles: ROLE_USER } 25 | -------------------------------------------------------------------------------- /config/packages/sensio_framework_extra.yaml: -------------------------------------------------------------------------------- 1 | sensio_framework_extra: 2 | router: 3 | annotations: false 4 | -------------------------------------------------------------------------------- /config/packages/swiftmailer.yaml: -------------------------------------------------------------------------------- 1 | swiftmailer: 2 | url: '%env(MAILER_URL)%' 3 | spool: { type: 'memory' } 4 | -------------------------------------------------------------------------------- /config/packages/test/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | test: true 3 | session: 4 | storage_id: session.storage.mock_file 5 | -------------------------------------------------------------------------------- /config/packages/test/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: debug 7 | channels: ["!event"] 8 | -------------------------------------------------------------------------------- /config/packages/test/swiftmailer.yaml: -------------------------------------------------------------------------------- 1 | swiftmailer: 2 | disable_delivery: true 3 | -------------------------------------------------------------------------------- /config/packages/test/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: false 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { collect: false } 7 | -------------------------------------------------------------------------------- /config/packages/translation.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | default_locale: '%locale%' 3 | translator: 4 | paths: 5 | - '%kernel.project_dir%/translations' 6 | fallbacks: 7 | - '%locale%' 8 | -------------------------------------------------------------------------------- /config/packages/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | paths: ['%kernel.project_dir%/templates'] 3 | debug: '%kernel.debug%' 4 | strict_variables: '%kernel.debug%' 5 | -------------------------------------------------------------------------------- /config/packages/validator.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | validation: 3 | email_validation_mode: html5 4 | -------------------------------------------------------------------------------- /config/routes.yaml: -------------------------------------------------------------------------------- 1 | #index: 2 | # path: / 3 | # controller: App\Controller\DefaultController::index 4 | -------------------------------------------------------------------------------- /config/routes/annotations.yaml: -------------------------------------------------------------------------------- 1 | controllers: 2 | resource: ../../src/Controller/ 3 | type: annotation 4 | -------------------------------------------------------------------------------- /config/routes/dev/twig.yaml: -------------------------------------------------------------------------------- 1 | _errors: 2 | resource: '@TwigBundle/Resources/config/routing/errors.xml' 3 | prefix: /_error 4 | -------------------------------------------------------------------------------- /config/routes/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler_wdt: 2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' 3 | prefix: /_wdt 4 | 5 | web_profiler_profiler: 6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' 7 | prefix: /_profiler 8 | -------------------------------------------------------------------------------- /config/services.yaml: -------------------------------------------------------------------------------- 1 | # This file is the entry point to configure your own services. 2 | # Files in the packages/ subdirectory configure your dependencies. 3 | 4 | # Put parameters here that don't need to change on each machine where the app is deployed 5 | # https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration 6 | parameters: 7 | locale: 'en' 8 | 9 | services: 10 | # default configuration for services in *this* file 11 | _defaults: 12 | autowire: true # Automatically injects dependencies in your services. 13 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. 14 | public: false # Allows optimizing the container by removing unused services; this also means 15 | # fetching services directly from the container via $container->get() won't work. 16 | # The best practice is to be explicit about your dependencies anyway. 17 | 18 | # makes classes in src/ available to be used as services 19 | # this creates a service per class whose id is the fully-qualified class name 20 | App\: 21 | resource: '../src/*' 22 | exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' 23 | 24 | # controllers are imported separately to make sure services can be injected 25 | # as action arguments even if you don't extend any base controller class 26 | App\Controller\: 27 | resource: '../src/Controller' 28 | tags: ['controller.service_arguments'] 29 | 30 | # add more service definitions when explicit configuration is needed 31 | # please note that last definitions always *replace* previous ones 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@symfony/webpack-encore": "^0.19.0", 4 | "webpack-notifier": "^1.6.0" 5 | }, 6 | "license": "UNLICENSED", 7 | "private": true, 8 | "scripts": { 9 | "dev-server": "encore dev-server", 10 | "dev": "encore dev", 11 | "watch": "encore dev --watch", 12 | "build": "encore production" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | tests/ 23 | 24 | 25 | 26 | 27 | 28 | ./src/ 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /public/assets/css/index.css: -------------------------------------------------------------------------------- 1 | .masthead.segment { 2 | min-height: 400px; 3 | padding: 1em 0em; 4 | } 5 | 6 | .masthead h1.ui.header { 7 | margin-top: 1em; 8 | margin-bottom: 0em; 9 | font-size: 4em; 10 | font-weight: normal; 11 | } 12 | 13 | .masthead h2 { 14 | font-size: 1.7em; 15 | font-weight: normal; 16 | } 17 | 18 | .footer.segment { 19 | padding: 5em 0em; 20 | } 21 | 22 | .ui.main.container { 23 | padding: 8em 0em; 24 | } 25 | 26 | .masthead .ui.menu .ui.button { 27 | margin-left: 0.5em; 28 | } 29 | 30 | .right_floated { 31 | float: right; 32 | } 33 | 34 | .tags{ 35 | padding: 0 2px; 36 | } -------------------------------------------------------------------------------- /public/assets/css/level.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f5f5f5; 3 | } 4 | 5 | body>.grid { 6 | height: 100%; 7 | } 8 | 9 | .column { 10 | max-width: 800px; 11 | } 12 | 13 | .ui.card { 14 | width: 430px; 15 | } 16 | 17 | .ui.input { 18 | width: 90%; 19 | } 20 | 21 | .description { 22 | padding-top: 1rem; 23 | } -------------------------------------------------------------------------------- /public/assets/js/level.js: -------------------------------------------------------------------------------- 1 | $("#submit").click(function(){ 2 | $.ajax({ 3 | url: window.location.href+"/submit", type: "POST", data: { answer: $("#answer").val() }, 4 | success: function (result) { 5 | 6 | if(!result["success"]){ 7 | 8 | $("#message_header").text("未知错误"); 9 | $("#message").text("请稍候重试"); 10 | $("#incorrect_answer").fadeIn(); 11 | setTimeout(function(){$("#incorrect_answer").fadeOut()},5000); 12 | return; 13 | } 14 | if(!result["correct"]){ 15 | 16 | $("#message_header").text(result["message_header"]); 17 | $("#message").text(result["message"]); 18 | $("#incorrect_answer").fadeIn(); 19 | setTimeout(function(){$("#incorrect_answer").fadeOut()},5000); 20 | 21 | }else{ 22 | $('.ui.mini.modal').modal('show'); $('.ui.star.rating').rating(); 23 | } 24 | }, error: function (xhr, ajaxOptions, thrownError) { 25 | $("#message_header").text("未知错误"); 26 | $("#message").text("请稍候重试"); 27 | $("#incorrect_answer").fadeIn(); 28 | setTimeout(function(){$("#incorrect_answer").fadeOut()},5000); 29 | } 30 | }); 31 | }); 32 | 33 | $("#next-level").click(function(){ 34 | $.ajax({ 35 | url: window.location.href+"/rate", type: "POST", 36 | data: { rating: $('.ui.rating').rating('get rating') }, 37 | success: function (result) { 38 | console.log(result); 39 | window.location = window.location.href+"/next" 40 | } 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /public/assets/js/tablesort.js: -------------------------------------------------------------------------------- 1 | /* 2 | A simple, lightweight jQuery plugin for creating sortable tables. 3 | https://github.com/kylefox/jquery-tablesort 4 | Version 0.0.11 5 | */ 6 | 7 | (function($) { 8 | $.tablesort = function ($table, settings) { 9 | var self = this; 10 | this.$table = $table; 11 | this.$thead = this.$table.find('thead'); 12 | this.settings = $.extend({}, $.tablesort.defaults, settings); 13 | this.$sortCells = this.$thead.length > 0 ? this.$thead.find('th:not(.no-sort)') : this.$table.find('th:not(.no-sort)'); 14 | this.$sortCells.on('click.tablesort', function() { 15 | self.sort($(this)); 16 | }); 17 | this.index = null; 18 | this.$th = null; 19 | this.direction = null; 20 | }; 21 | 22 | $.tablesort.prototype = { 23 | 24 | sort: function(th, direction) { 25 | var start = new Date(), 26 | self = this, 27 | table = this.$table, 28 | rowsContainer = table.find('tbody').length > 0 ? table.find('tbody') : table, 29 | rows = rowsContainer.find('tr').has('td, th'), 30 | cells = rows.find(':nth-child(' + (th.index() + 1) + ')').filter('td, th'), 31 | sortBy = th.data().sortBy, 32 | sortedMap = []; 33 | 34 | var unsortedValues = cells.map(function(idx, cell) { 35 | if (sortBy) 36 | return (typeof sortBy === 'function') ? sortBy($(th), $(cell), self) : sortBy; 37 | return ($(this).data().sortValue != null ? $(this).data().sortValue : $(this).text()); 38 | }); 39 | if (unsortedValues.length === 0) return; 40 | 41 | //click on a different column 42 | if (this.index !== th.index()) { 43 | this.direction = 'asc'; 44 | this.index = th.index(); 45 | } 46 | else if (direction !== 'asc' && direction !== 'desc') 47 | this.direction = this.direction === 'asc' ? 'desc' : 'asc'; 48 | else 49 | this.direction = direction; 50 | 51 | direction = this.direction == 'asc' ? 1 : -1; 52 | 53 | self.$table.trigger('tablesort:start', [self]); 54 | self.log("Sorting by " + this.index + ' ' + this.direction); 55 | 56 | // Try to force a browser redraw 57 | self.$table.css("display"); 58 | // Run sorting asynchronously on a timeout to force browser redraw after 59 | // `tablesort:start` callback. Also avoids locking up the browser too much. 60 | setTimeout(function() { 61 | self.$sortCells.removeClass(self.settings.asc + ' ' + self.settings.desc); 62 | for (var i = 0, length = unsortedValues.length; i < length; i++) 63 | { 64 | sortedMap.push({ 65 | index: i, 66 | cell: cells[i], 67 | row: rows[i], 68 | value: unsortedValues[i] 69 | }); 70 | } 71 | 72 | sortedMap.sort(function(a, b) { 73 | return self.settings.compare(a.value, b.value) * direction; 74 | }); 75 | 76 | $.each(sortedMap, function(i, entry) { 77 | rowsContainer.append(entry.row); 78 | }); 79 | 80 | th.addClass(self.settings[self.direction]); 81 | 82 | self.log('Sort finished in ' + ((new Date()).getTime() - start.getTime()) + 'ms'); 83 | self.$table.trigger('tablesort:complete', [self]); 84 | //Try to force a browser redraw 85 | self.$table.css("display"); 86 | }, unsortedValues.length > 2000 ? 200 : 10); 87 | }, 88 | 89 | log: function(msg) { 90 | if(($.tablesort.DEBUG || this.settings.debug) && console && console.log) { 91 | console.log('[tablesort] ' + msg); 92 | } 93 | }, 94 | 95 | destroy: function() { 96 | this.$sortCells.off('click.tablesort'); 97 | this.$table.data('tablesort', null); 98 | return null; 99 | } 100 | 101 | }; 102 | 103 | $.tablesort.DEBUG = false; 104 | 105 | $.tablesort.defaults = { 106 | debug: $.tablesort.DEBUG, 107 | asc: 'sorted ascending', 108 | desc: 'sorted descending', 109 | compare: function(a, b) { 110 | if (a > b) { 111 | return 1; 112 | } else if (a < b) { 113 | return -1; 114 | } else { 115 | return 0; 116 | } 117 | } 118 | }; 119 | 120 | $.fn.tablesort = function(settings) { 121 | var table, sortable, previous; 122 | return this.each(function() { 123 | table = $(this); 124 | previous = table.data('tablesort'); 125 | if(previous) { 126 | previous.destroy(); 127 | } 128 | table.data('tablesort', new $.tablesort(table, settings)); 129 | }); 130 | }; 131 | 132 | })(window.Zepto || window.jQuery); 133 | -------------------------------------------------------------------------------- /public/eula.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Nazo.Games EULA 8 | 9 | 10 | 11 |

最终用户协议

12 |

通过访问和/或使用本网站,即代表您同意接受本协议的所有条件和条款。

13 |

本网站有权随时对本协议进行修改。如果用户选择在本协议变更后继续访问或使用本网站,则视为用户已经接受本协议的修改。

14 |

账户

15 |

本网站有权随时在不通知用户的情况下删除用户账户以节省网站资源。

16 |

本网站有责任使用适当的技术保护您的密码原文的安全(包括但不限于散列函数)。

17 |

隐私

18 |

您允许该网站记录并永久保存您使用的用户名、账户数据(如积分,通关数量)、所用的浏览器、操作系统信息等数据,并将其用于统计、分析或其它用途。

19 |

您允许该网站公开显示您注册时所填写的“显示名”和您的分数,若您没有填写“显示名”,您允许网站使用您邮箱前缀作为“显示名”。

20 |

您允许该网站在某些特定情况下使用您的邮箱对您联络。

21 |

其它

22 |

您同意不对此网站进行攻击,并且您同意承担汇报此网站存在的漏洞的责任。

23 | 24 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | load(__DIR__.'/../.env'); 16 | } 17 | 18 | $env = $_SERVER['APP_ENV'] ?? 'dev'; 19 | $debug = (bool) ($_SERVER['APP_DEBUG'] ?? ('prod' !== $env)); 20 | 21 | if ($debug) { 22 | umask(0000); 23 | 24 | Debug::enable(); 25 | } 26 | 27 | if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) { 28 | Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST); 29 | } 30 | 31 | if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) { 32 | Request::setTrustedHosts(explode(',', $trustedHosts)); 33 | } 34 | 35 | $kernel = new Kernel($env, $debug); 36 | $request = Request::createFromGlobals(); 37 | $response = $kernel->handle($request); 38 | $response->send(); 39 | $kernel->terminate($request, $response); 40 | -------------------------------------------------------------------------------- /public/res/level_base.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | {% block title %}Level {{level.id}}: {{level.name}}{% endblock %} 3 | {% block stylesheets %} 4 | {{ parent() }} 5 | 6 | {% endblock %} 7 | {% block main %} 8 | 24 | 25 |
26 |
27 |
28 | {% block pre_block %} 29 | {# 30 |
31 | 32 |
33 | #} 34 | {% endblock %} 35 |
36 |
37 | {{level.name}} 38 |
39 |
40 | {{level.getPassedNum}}/{{level.getTriedNum}} ({{(level.getPassedNum/(level.getTriedNum==0?1:level.getTriedNum))*100//1}}%)人通过了这关 41 |

42 | {% for tag in level.tags %} 43 | {% set tagcolor = tag|split('|') %} 44 | {{tagcolor[1]}} 45 | {% endfor %} 46 |

47 |
48 |
49 | {% block description %} 50 | {# 51 | 52 | 下载附件 53 | 54 | #} 55 | {% endblock %} 56 |
57 |
58 |
59 | {% block submit %} 60 |
61 | 62 | 63 | 64 |
65 | 69 | {% endblock %} 70 |
71 | 72 |
73 |
74 |
75 | 76 | {% endblock %} 77 | 78 | {% block post_body_javascripts %} 79 | 80 | {% endblock %} 81 | -------------------------------------------------------------------------------- /src/Controller/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harrynull/CipherGameFramework/fab828686dd0825b0cae518544224e4bb62f2d62/src/Controller/.gitignore -------------------------------------------------------------------------------- /src/Controller/EditorController.php: -------------------------------------------------------------------------------- 1 | cookies->has('user')) return false; 26 | $user = $this->getDoctrine()->getManager()->getRepository(User::class)->find($request->cookies->get('user')); 27 | return $user && $user->getIsAdmin(); 28 | } 29 | 30 | private function hasProposePermission(Request $request) : bool { 31 | if (!$request->cookies->has('user')) return false; 32 | $user = $this->getDoctrine()->getManager()->getRepository(User::class)->find($request->cookies->get('user')); 33 | return $user && ($user->getScore() >= 500 || $user->getIsAdmin()); 34 | } 35 | 36 | private function editLevel(Level $level, Request $request){ 37 | $level->setName($request->request->get('level-name')); 38 | $level->setUnlockScore($request->request->get('unlock-score')); 39 | $level->setScore($request->request->get('score')); 40 | $level->setAuthor($request->request->get('author')); 41 | $level->setAnswer($request->request->get('answer')); 42 | $level->setTags(explode(",", $request->request->get('tags'))); 43 | } 44 | 45 | /** 46 | * @Route("/new", methods={"GET"}, name="editor") 47 | */ 48 | public function new(Request $request): Response 49 | { 50 | define("DEFAULT_CODE", "{% extends 'levels/level_base.html.twig' %}\n{% block description %}1+1=?{% endblock %}"); 51 | return $this->render('editor.html.twig', ["code" => DEFAULT_CODE, 52 | "can_edit" => $this->hasEditPermission($request), 53 | "can_propose" => $this->hasProposePermission($request)]); 54 | } 55 | 56 | /** 57 | * @Route("/new", methods={"POST"}) 58 | */ 59 | public function submit_new(Request $request): Response 60 | { 61 | if(!$this->hasProposePermission($request)) 62 | throw new UnauthorizedHttpException("Permission Denied"); 63 | $entityManager = $this->getDoctrine()->getManager(); 64 | $level = new Level(); 65 | $this->editLevel($level, $request); 66 | $level->setAuthorUser($entityManager->getRepository(User::class)->find($request->cookies->get('user'))); 67 | $level->setUnderReview(!$this->hasEditPermission($request)); 68 | $entityManager->persist($level); 69 | $entityManager->flush(); 70 | 71 | $id = (int)$level->getId(); 72 | file_put_contents("../templates/levels/level_{$id}.html.twig", $request->request->get('code')); 73 | 74 | return $this->redirect("/nazo/{$id}"); 75 | } 76 | /** 77 | * @Route("/preview", methods={"POST"}) 78 | */ 79 | public function preview(Request $request): Response 80 | { 81 | if(!$this->hasProposePermission($request)) 82 | throw new UnauthorizedHttpException("Permission Denied"); 83 | $level = new Level(); 84 | $this->editLevel($level, $request); 85 | $level->setUnderReview(true); 86 | 87 | //$twig = new \Twig_Environment(new \Twig_Loader_Array(array())); 88 | $twig = clone $this->container->get('twig'); 89 | $template = $twig->createTemplate($request->request->get('code')); 90 | return new Response($template->render(['level'=>$level])); 91 | } 92 | 93 | /** 94 | * @Route("/edit/{id}", methods={"GET"}) 95 | */ 96 | public function edit(Request $request, Level $level): Response 97 | { 98 | if(!$this->hasEditPermission($request)) 99 | throw new UnauthorizedHttpException("Permission Denied"); 100 | $id = $level->getId(); 101 | $code = file_get_contents("../templates/levels/level_{$id}.html.twig"); 102 | return $this->render('editor.html.twig', ["level" => $level, "code" => $code, "can_edit" => true, "can_propose" => true]); 103 | } 104 | 105 | /** 106 | * @Route("/edit/{id}", methods={"POST"}) 107 | */ 108 | public function submit_edit(Request $request, int $id): Response 109 | { 110 | if(!$this->hasEditPermission($request)) 111 | throw new UnauthorizedHttpException("Permission Denied"); 112 | $entityManager = $this->getDoctrine()->getManager(); 113 | $level = $entityManager->getRepository(Level::class)->find($id); 114 | $this->editLevel($level, $request); 115 | if($level->getUnderReview()){ 116 | $level->setUnderReview(false); 117 | $author = $level->getAuthorUser(); 118 | $author->setScore($author->getScore()+$level->getScore()*5); // award the author 119 | } 120 | $entityManager->persist($level); 121 | $entityManager->flush(); 122 | file_put_contents("../templates/levels/level_{$id}.html.twig", $request->request->get('code')); 123 | 124 | return $this->redirect("/"); 125 | } 126 | /** 127 | * @Route("/delete/{id}", methods={"GET"}) 128 | */ 129 | public function submit_delete(Request $request, int $id): Response 130 | { 131 | if(!$this->hasEditPermission($request)) 132 | throw new UnauthorizedHttpException("Permission Denied"); 133 | $entityManager = $this->getDoctrine()->getManager(); 134 | $level = $entityManager->getRepository(Level::class)->find($id); 135 | $entityManager->remove($level); 136 | $entityManager->flush(); 137 | return $this->redirect("/"); 138 | } 139 | 140 | /** 141 | * @Route("/setadmin/{user}/{isadmin}", methods={"GET"}) 142 | */ 143 | public function set_admin_html(Request $request, string $user, bool $isadmin): Response 144 | { 145 | $type = $isadmin?'管理员':'非管理员'; 146 | return new Response("将{$user}设置为{$type},确认?". 147 | '
'); 148 | } 149 | 150 | /** 151 | * @Route("/setadmin/{user}/{isadmin}", methods={"POST"}) 152 | */ 153 | public function set_admin(Request $request, string $user, bool $isadmin): Response 154 | { 155 | if(hash('sha256', 'somesalt'.$request->request->get('password'))!=='') 156 | return new JsonResponse(array('success' => false, 'reason' => 'incorrect password')); 157 | $entityManager = $this->getDoctrine()->getManager(); 158 | $u = $entityManager->getRepository(User::class)->find($user); 159 | if(!$u) return new JsonResponse(array('success' => false, 'reason' => 'incorrect user id')); 160 | $u->setIsAdmin($isadmin); 161 | $entityManager->flush(); 162 | return new JsonResponse(array('success' => true)); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/Controller/IndexController.php: -------------------------------------------------------------------------------- 1 | cookies; 28 | 29 | $entityManager = $this->getDoctrine()->getManager(); 30 | $user = null; 31 | if ($cookies->has('user')) { 32 | $user = $entityManager->getRepository(User::class)->find($cookies->get('user')); 33 | } 34 | 35 | if ($user == null) { // new user or old uid is invalid 36 | $user = new User(); 37 | $entityManager->persist($user); 38 | $entityManager->flush(); 39 | } 40 | 41 | $levels = $entityManager->getRepository(Level::class) 42 | ->getAll($request->query->get('review')==1 && $user->getIsAdmin()); 43 | $rank = $entityManager->getRepository(User::class) 44 | ->getRank($user->getScore()); 45 | $top10 = $entityManager->getRepository(User::class) 46 | ->getTop10Users(); 47 | 48 | $response = $this->render('index.html.twig', 49 | ['user' => $user, 'levels' => $levels, 'rank' => $rank, 'top10' => $top10]); 50 | $response->headers->setCookie(new Cookie("user", $user->getId(), time() + (3600 * 24 * 365 * 10))); 51 | return $response; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/Controller/NazoController.php: -------------------------------------------------------------------------------- 1 | getIsAdmin() || $level->getAuthorUser()->getId()===$user->getId(); 28 | return ($level->getUnlockScore() <= $user->getScore() || $isException) 29 | && (!$level->getUnderReview() || $isException); 30 | } 31 | 32 | private function getUserFromRequest(Request $request) : User{ 33 | return $this->getDoctrine()->getManager()->getRepository(User::class) 34 | ->find($request->cookies->get('user')); 35 | } 36 | 37 | /** 38 | * @Route("/{id}", methods={"GET"}, requirements={"id": "[1-9]\d*"}, name="nazo-levels") 39 | */ 40 | public function level(Request $request, int $id): Response 41 | { 42 | $entityManager = $this->getDoctrine()->getManager(); 43 | $level_data = $entityManager->getRepository(Level::class)->find($id); 44 | if($level_data == null) throw $this->createNotFoundException('This level does not exist'); 45 | $user = $this->getUserFromRequest($request); 46 | if(!$this->permissionCheck($user, $level_data)) return $this->redirect('/'); 47 | 48 | if(!in_array($level_data->getId(), $user->getTriedLevels())){ 49 | $level_data->setTriedNum($level_data->getTriedNum() + 1); 50 | $tried_levels = $user->getTriedLevels(); 51 | $tried_levels[] = $level_data->getId(); 52 | $user->setTriedLevels($tried_levels); 53 | $entityManager->flush(); 54 | } 55 | 56 | 57 | $response = $this->render("levels/level_{$id}.html.twig", ['level'=>$level_data]); 58 | 59 | return $response; 60 | } 61 | /** 62 | * @Route("/{id}/submit", methods={"POST"}, requirements={"id": "[1-9]\d*"}, name="nazo-levels-submit") 63 | */ 64 | public function submit(Request $request, int $id): Response 65 | { 66 | $entityManager = $this->getDoctrine()->getManager(); 67 | $level_data = $entityManager->getRepository(Level::class)->find($id); 68 | if($level_data == null) throw $this->createNotFoundException('This level does not exist'); 69 | $user = $this->getUserFromRequest($request); 70 | 71 | if(!$this->permissionCheck($user, $level_data)) 72 | return new JsonResponse(array('success' => false)); 73 | 74 | if($request->request->get('answer') === $level_data->getAnswer()){ 75 | if(!in_array($level_data->getId(), $user->getPassedLevels())){ 76 | $user->setScore($user->getScore() + $level_data->getScore()); 77 | $level_data->setPassedNum($level_data->getPassedNum() + 1); 78 | $passed_levels = $user->getPassedLevels(); 79 | $passed_levels[] = $level_data->getId(); 80 | $user->setPassedLevels($passed_levels); 81 | } 82 | $entityManager->flush(); 83 | return new JsonResponse(array('success' => true, 'correct' => true)); 84 | } 85 | else 86 | return new JsonResponse(array('success' => true, 'correct' => false, 87 | "message_header" => "答案不正确", "message" => "再试一次吧")); 88 | } 89 | 90 | /** 91 | * @Route("/{id}/rate", methods={"POST"}, requirements={"id": "[1-9]\d*"}) 92 | */ 93 | public function rate(Request $request, int $id): Response 94 | { 95 | $entityManager = $this->getDoctrine()->getManager(); 96 | $level_data = $entityManager->getRepository(Level::class)->find($id); 97 | if($level_data == null) throw $this->createNotFoundException('This level does not exist'); 98 | $user = $this->getUserFromRequest($request); 99 | 100 | if(!$this->permissionCheck($user, $level_data) || 101 | !in_array($level_data->getId(), $user->getPassedLevels())) 102 | return new JsonResponse(array('success' => false)); 103 | 104 | $rating = (int) $request->request->get('rating'); 105 | if($rating >= 1 && $rating <=5){ 106 | $level_data->setTotalRating($level_data->getTotalRating() + $rating); 107 | $level_data->setRatedNum($level_data->getRatedNum() + 1); 108 | $entityManager->flush(); 109 | } 110 | 111 | return new JsonResponse(array('success' => true)); 112 | } 113 | /** 114 | * @Route("/{id}/next", methods={"GET"}, requirements={"id": "[1-9]\d*"}) 115 | */ 116 | public function next(Request $request, int $id): Response 117 | { 118 | $nextid = $id + 1; 119 | $level_data = $this->getDoctrine()->getManager()->getRepository(Level::class)->find($nextid); 120 | $user = $this->getUserFromRequest($request); 121 | if($this->permissionCheck($user, $level_data)) return $this->redirect("/nazo/{$nextid}"); 122 | else return $this->redirect("/"); 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/Controller/UserController.php: -------------------------------------------------------------------------------- 1 | getDoctrine()->getManager(); 30 | $email = $request->request->get('email'); 31 | $display_name = $request->request->get('display_name'); 32 | $password = $request->request->get('password'); 33 | $userRepo = $entityManager->getRepository(User::class); 34 | 35 | $new_guid = $request->cookies->get('user'); 36 | $user = $userRepo->findByEmail($email); 37 | 38 | if ($user) { // existing user 39 | 40 | if (!password_verify($password, $user->getPassword())) 41 | throw new UnauthorizedHttpException("Incorrect username or password!"); 42 | if ($display_name != '') $user->setDisplayName($display_name); 43 | $new_guid = $user->getId(); 44 | 45 | } else { // new user 46 | 47 | $user = $userRepo->find($request->cookies->get('user')); 48 | if ($user == null) throw new BadRequestHttpException(); 49 | $user->setEmail($email); 50 | $user->setDisplayName( ($display_name!='') ? $display_name : (explode('@', $email)[0]) ); 51 | $user->setPassword(password_hash($password, PASSWORD_DEFAULT)); 52 | 53 | } 54 | $entityManager->flush(); 55 | 56 | $response = $this->redirect("/"); 57 | $response->headers->setCookie(new Cookie("user", $new_guid, time() + (3600 * 24 * 365 * 10))); 58 | return $response; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/Entity/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harrynull/CipherGameFramework/fab828686dd0825b0cae518544224e4bb62f2d62/src/Entity/.gitignore -------------------------------------------------------------------------------- /src/Entity/Level.php: -------------------------------------------------------------------------------- 1 | id; 82 | } 83 | 84 | public function getName(): ?string 85 | { 86 | return $this->name; 87 | } 88 | 89 | public function setName(string $name): self 90 | { 91 | $this->name = $name; 92 | 93 | return $this; 94 | } 95 | 96 | public function getUnlockScore(): ?int 97 | { 98 | return $this->unlock_score; 99 | } 100 | 101 | public function setUnlockScore(int $unlock_score): self 102 | { 103 | $this->unlock_score = $unlock_score; 104 | 105 | return $this; 106 | } 107 | 108 | public function getScore(): ?int 109 | { 110 | return $this->score; 111 | } 112 | 113 | public function setScore(int $score): self 114 | { 115 | $this->score = $score; 116 | 117 | return $this; 118 | } 119 | 120 | public function getTriedNum(): ?int 121 | { 122 | return $this->tried_num; 123 | } 124 | 125 | public function setTriedNum(int $tried_num): self 126 | { 127 | $this->tried_num = $tried_num; 128 | 129 | return $this; 130 | } 131 | 132 | public function getTotalRating(): ?int 133 | { 134 | return $this->total_rating; 135 | } 136 | 137 | public function setTotalRating(int $total_rating): self 138 | { 139 | $this->total_rating = $total_rating; 140 | 141 | return $this; 142 | } 143 | 144 | public function getRatedNum(): ?int 145 | { 146 | return $this->rated_num; 147 | } 148 | 149 | public function setRatedNum(int $rated_num): self 150 | { 151 | $this->rated_num = $rated_num; 152 | 153 | return $this; 154 | } 155 | 156 | public function getPassedNum(): ?int 157 | { 158 | return $this->passed_num; 159 | } 160 | 161 | public function setPassedNum(int $passed_num): self 162 | { 163 | $this->passed_num = $passed_num; 164 | 165 | return $this; 166 | } 167 | 168 | public function getTags(): ?array 169 | { 170 | return $this->tags; 171 | } 172 | 173 | public function setTags(?array $tags): self 174 | { 175 | $this->tags = $tags; 176 | 177 | return $this; 178 | } 179 | 180 | public function getAuthor(): ?string 181 | { 182 | return $this->author; 183 | } 184 | 185 | public function setAuthor(string $author): self 186 | { 187 | $this->author = $author; 188 | 189 | return $this; 190 | } 191 | 192 | public function getAnswer(): ?string 193 | { 194 | return $this->answer; 195 | } 196 | 197 | public function setAnswer(string $answer): self 198 | { 199 | $this->answer = $answer; 200 | 201 | return $this; 202 | } 203 | 204 | public function getUnderReview(): ?bool 205 | { 206 | return $this->under_review; 207 | } 208 | 209 | public function setUnderReview(bool $under_review): self 210 | { 211 | $this->under_review = $under_review; 212 | 213 | return $this; 214 | } 215 | 216 | public function getAuthorUser(): ?User 217 | { 218 | return $this->author_user; 219 | } 220 | 221 | public function setAuthorUser(?User $author_user): self 222 | { 223 | $this->author_user = $author_user; 224 | 225 | return $this; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/Entity/User.php: -------------------------------------------------------------------------------- 1 | levels = new ArrayCollection(); 64 | } 65 | 66 | public function getId(): ?string 67 | { 68 | return $this->id; 69 | } 70 | 71 | public function getPassedLevels(): ?array 72 | { 73 | return $this->passed_levels; 74 | } 75 | 76 | public function setPassedLevels(array $passed_levels): self 77 | { 78 | $this->passed_levels = $passed_levels; 79 | 80 | return $this; 81 | } 82 | 83 | public function getScore(): ?int 84 | { 85 | return $this->score; 86 | } 87 | 88 | public function setScore(int $score): self 89 | { 90 | $this->score = $score; 91 | 92 | return $this; 93 | } 94 | 95 | public function getIsAdmin(): ?bool 96 | { 97 | return $this->is_admin; 98 | } 99 | 100 | public function setIsAdmin(?bool $is_admin): self 101 | { 102 | $this->is_admin = $is_admin; 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * @return Collection|Level[] 109 | */ 110 | public function getLevels(): Collection 111 | { 112 | return $this->levels; 113 | } 114 | 115 | public function addLevel(Level $level): self 116 | { 117 | if (!$this->levels->contains($level)) { 118 | $this->levels[] = $level; 119 | $level->setAuthorUser($this); 120 | } 121 | 122 | return $this; 123 | } 124 | 125 | public function removeLevel(Level $level): self 126 | { 127 | if ($this->levels->contains($level)) { 128 | $this->levels->removeElement($level); 129 | // set the owning side to null (unless already changed) 130 | if ($level->getAuthorUser() === $this) { 131 | $level->setAuthorUser(null); 132 | } 133 | } 134 | 135 | return $this; 136 | } 137 | 138 | public function getTriedLevels(): array 139 | { 140 | return $this->tried_levels; 141 | } 142 | 143 | public function setTriedLevels(array $tried_levels): self 144 | { 145 | $this->tried_levels = $tried_levels; 146 | 147 | return $this; 148 | } 149 | 150 | public function getEmail(): ?string 151 | { 152 | return $this->email; 153 | } 154 | 155 | public function setEmail(string $email): self 156 | { 157 | $this->email = $email; 158 | 159 | return $this; 160 | } 161 | 162 | public function getPassword(): ?string 163 | { 164 | return $this->password; 165 | } 166 | 167 | public function setPassword(?string $password): self 168 | { 169 | $this->password = $password; 170 | 171 | return $this; 172 | } 173 | 174 | public function getDisplayName(): ?string 175 | { 176 | return $this->display_name; 177 | } 178 | 179 | public function setDisplayName(?string $display_name): self 180 | { 181 | $this->display_name = $display_name; 182 | 183 | return $this; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/Kernel.php: -------------------------------------------------------------------------------- 1 | getProjectDir().'/var/cache/'.$this->environment; 21 | } 22 | 23 | public function getLogDir() 24 | { 25 | return $this->getProjectDir().'/var/log'; 26 | } 27 | 28 | public function registerBundles() 29 | { 30 | $contents = require $this->getProjectDir().'/config/bundles.php'; 31 | foreach ($contents as $class => $envs) { 32 | if (isset($envs['all']) || isset($envs[$this->environment])) { 33 | yield new $class(); 34 | } 35 | } 36 | } 37 | 38 | protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) 39 | { 40 | $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php')); 41 | // Feel free to remove the "container.autowiring.strict_mode" parameter 42 | // if you are using symfony/dependency-injection 4.0+ as it's the default behavior 43 | $container->setParameter('container.autowiring.strict_mode', true); 44 | $container->setParameter('container.dumper.inline_class_loader', true); 45 | $confDir = $this->getProjectDir().'/config'; 46 | 47 | $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); 48 | $loader->load($confDir.'/{packages}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); 49 | $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); 50 | $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); 51 | } 52 | 53 | protected function configureRoutes(RouteCollectionBuilder $routes) 54 | { 55 | $confDir = $this->getProjectDir().'/config'; 56 | 57 | $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); 58 | $routes->import($confDir.'/{routes}/'.$this->environment.'/**/*'.self::CONFIG_EXTS, '/', 'glob'); 59 | $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Repository/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harrynull/CipherGameFramework/fab828686dd0825b0cae518544224e4bb62f2d62/src/Repository/.gitignore -------------------------------------------------------------------------------- /src/Repository/LevelRepository.php: -------------------------------------------------------------------------------- 1 | createQueryBuilder('u') 25 | ->where('u.under_review = :review') 26 | ->setParameter('review', $underReview) 27 | ->getQuery() 28 | ->getResult(); 29 | } 30 | // /** 31 | // * @return Level[] Returns an array of Level objects 32 | // */ 33 | /* 34 | public function findByExampleField($value) 35 | { 36 | return $this->createQueryBuilder('l') 37 | ->andWhere('l.exampleField = :val') 38 | ->setParameter('val', $value) 39 | ->orderBy('l.id', 'ASC') 40 | ->setMaxResults(10) 41 | ->getQuery() 42 | ->getResult() 43 | ; 44 | } 45 | */ 46 | 47 | /* 48 | public function findOneBySomeField($value): ?Level 49 | { 50 | return $this->createQueryBuilder('l') 51 | ->andWhere('l.exampleField = :val') 52 | ->setParameter('val', $value) 53 | ->getQuery() 54 | ->getOneOrNullResult() 55 | ; 56 | } 57 | */ 58 | } 59 | -------------------------------------------------------------------------------- /src/Repository/UserRepository.php: -------------------------------------------------------------------------------- 1 | getEntityManager() 24 | ->createQuery(' 25 | SELECT COUNT(1) 26 | FROM App:User p 27 | WHERE p.score > :score 28 | ') 29 | ->setParameter('score', $score); 30 | return $q->getResult()[0][1]+1; 31 | } 32 | 33 | public function getTop10Users() 34 | { 35 | return $this->createQueryBuilder('u') 36 | ->andWhere('u.display_name is not null') 37 | ->orderBy('u.score', 'DESC') 38 | ->setMaxResults(10) 39 | ->getQuery() 40 | ->getResult(); 41 | } 42 | public function findByEmail($value): ?User 43 | { 44 | return $this->createQueryBuilder('u') 45 | ->andWhere('u.email = :val') 46 | ->setParameter('val', $value) 47 | ->getQuery() 48 | ->getOneOrNullResult(); 49 | } 50 | // /** 51 | // * @return User[] Returns an array of User objects 52 | // */ 53 | /* 54 | public function findByExampleField($value) 55 | { 56 | return $this->createQueryBuilder('p') 57 | ->andWhere('p.exampleField = :val') 58 | ->setParameter('val', $value) 59 | ->orderBy('p.id', 'ASC') 60 | ->setMaxResults(10) 61 | ->getQuery() 62 | ->getResult() 63 | ; 64 | } 65 | */ 66 | 67 | /* 68 | public function findOneBySomeField($value): ?User 69 | { 70 | return $this->createQueryBuilder('p') 71 | ->andWhere('p.exampleField = :val') 72 | ->setParameter('val', $value) 73 | ->getQuery() 74 | ->getOneOrNullResult() 75 | ; 76 | } 77 | */ 78 | } 79 | -------------------------------------------------------------------------------- /symfony.lock: -------------------------------------------------------------------------------- 1 | { 2 | "doctrine/annotations": { 3 | "version": "1.0", 4 | "recipe": { 5 | "repo": "github.com/symfony/recipes", 6 | "branch": "master", 7 | "version": "1.0", 8 | "ref": "cb4152ebcadbe620ea2261da1a1c5a9b8cea7672" 9 | } 10 | }, 11 | "doctrine/cache": { 12 | "version": "v1.7.1" 13 | }, 14 | "doctrine/collections": { 15 | "version": "v1.5.0" 16 | }, 17 | "doctrine/common": { 18 | "version": "v2.9.0" 19 | }, 20 | "doctrine/dbal": { 21 | "version": "v2.8.0" 22 | }, 23 | "doctrine/doctrine-bundle": { 24 | "version": "1.6", 25 | "recipe": { 26 | "repo": "github.com/symfony/recipes", 27 | "branch": "master", 28 | "version": "1.6", 29 | "ref": "ae205d5114e719deb64d2110f56ef910787d1e04" 30 | } 31 | }, 32 | "doctrine/doctrine-cache-bundle": { 33 | "version": "1.3.3" 34 | }, 35 | "doctrine/doctrine-migrations-bundle": { 36 | "version": "1.2", 37 | "recipe": { 38 | "repo": "github.com/symfony/recipes", 39 | "branch": "master", 40 | "version": "1.2", 41 | "ref": "c1431086fec31f17fbcfe6d6d7e92059458facc1" 42 | } 43 | }, 44 | "doctrine/event-manager": { 45 | "version": "v1.0.0" 46 | }, 47 | "doctrine/inflector": { 48 | "version": "v1.3.0" 49 | }, 50 | "doctrine/instantiator": { 51 | "version": "1.1.0" 52 | }, 53 | "doctrine/lexer": { 54 | "version": "v1.0.1" 55 | }, 56 | "doctrine/migrations": { 57 | "version": "v1.8.1" 58 | }, 59 | "doctrine/orm": { 60 | "version": "v2.6.2" 61 | }, 62 | "doctrine/persistence": { 63 | "version": "v1.0.0" 64 | }, 65 | "doctrine/reflection": { 66 | "version": "v1.0.0" 67 | }, 68 | "easycorp/easy-log-handler": { 69 | "version": "1.0", 70 | "recipe": { 71 | "repo": "github.com/symfony/recipes", 72 | "branch": "master", 73 | "version": "1.0", 74 | "ref": "70062abc2cd58794d2a90274502f81b55cd9951b" 75 | } 76 | }, 77 | "egulias/email-validator": { 78 | "version": "2.1.4" 79 | }, 80 | "fig/link-util": { 81 | "version": "1.0.0" 82 | }, 83 | "jdorn/sql-formatter": { 84 | "version": "v1.2.17" 85 | }, 86 | "monolog/monolog": { 87 | "version": "1.23.0" 88 | }, 89 | "nikic/php-parser": { 90 | "version": "v4.0.3" 91 | }, 92 | "ocramius/proxy-manager": { 93 | "version": "2.1.1" 94 | }, 95 | "phpdocumentor/reflection-common": { 96 | "version": "1.0.1" 97 | }, 98 | "phpdocumentor/reflection-docblock": { 99 | "version": "4.3.0" 100 | }, 101 | "phpdocumentor/type-resolver": { 102 | "version": "0.4.0" 103 | }, 104 | "psr/cache": { 105 | "version": "1.0.1" 106 | }, 107 | "psr/container": { 108 | "version": "1.0.0" 109 | }, 110 | "psr/link": { 111 | "version": "1.0.0" 112 | }, 113 | "psr/log": { 114 | "version": "1.0.2" 115 | }, 116 | "psr/simple-cache": { 117 | "version": "1.0.1" 118 | }, 119 | "sensio/framework-extra-bundle": { 120 | "version": "5.2", 121 | "recipe": { 122 | "repo": "github.com/symfony/recipes", 123 | "branch": "master", 124 | "version": "5.2", 125 | "ref": "fb7e19da7f013d0d422fa9bce16f5c510e27609b" 126 | } 127 | }, 128 | "swiftmailer/swiftmailer": { 129 | "version": "v6.1.2" 130 | }, 131 | "symfony/asset": { 132 | "version": "v4.1.1" 133 | }, 134 | "symfony/browser-kit": { 135 | "version": "v4.1.1" 136 | }, 137 | "symfony/cache": { 138 | "version": "v4.1.1" 139 | }, 140 | "symfony/config": { 141 | "version": "v4.1.1" 142 | }, 143 | "symfony/console": { 144 | "version": "3.3", 145 | "recipe": { 146 | "repo": "github.com/symfony/recipes", 147 | "branch": "master", 148 | "version": "3.3", 149 | "ref": "e3868d2f4a5104f19f844fe551099a00c6562527" 150 | } 151 | }, 152 | "symfony/css-selector": { 153 | "version": "v4.1.1" 154 | }, 155 | "symfony/debug": { 156 | "version": "v4.1.1" 157 | }, 158 | "symfony/debug-bundle": { 159 | "version": "4.1", 160 | "recipe": { 161 | "repo": "github.com/symfony/recipes", 162 | "branch": "master", 163 | "version": "4.1", 164 | "ref": "f8863cbad2f2e58c4b65fa1eac892ab189971bea" 165 | } 166 | }, 167 | "symfony/debug-pack": { 168 | "version": "v1.0.5" 169 | }, 170 | "symfony/dependency-injection": { 171 | "version": "v4.1.1" 172 | }, 173 | "symfony/doctrine-bridge": { 174 | "version": "v4.1.1" 175 | }, 176 | "symfony/dom-crawler": { 177 | "version": "v4.1.1" 178 | }, 179 | "symfony/dotenv": { 180 | "version": "v4.1.1" 181 | }, 182 | "symfony/event-dispatcher": { 183 | "version": "v4.1.1" 184 | }, 185 | "symfony/expression-language": { 186 | "version": "v4.1.1" 187 | }, 188 | "symfony/filesystem": { 189 | "version": "v4.1.1" 190 | }, 191 | "symfony/finder": { 192 | "version": "v4.1.1" 193 | }, 194 | "symfony/flex": { 195 | "version": "1.0", 196 | "recipe": { 197 | "repo": "github.com/symfony/recipes", 198 | "branch": "master", 199 | "version": "1.0", 200 | "ref": "e921bdbfe20cdefa3b82f379d1cd36df1bc8d115" 201 | } 202 | }, 203 | "symfony/form": { 204 | "version": "v4.1.1" 205 | }, 206 | "symfony/framework-bundle": { 207 | "version": "3.3", 208 | "recipe": { 209 | "repo": "github.com/symfony/recipes", 210 | "branch": "master", 211 | "version": "3.3", 212 | "ref": "87c585d24de9f43bca80ebcfd5cf5cb39445d95f" 213 | } 214 | }, 215 | "symfony/http-foundation": { 216 | "version": "v4.1.1" 217 | }, 218 | "symfony/http-kernel": { 219 | "version": "v4.1.1" 220 | }, 221 | "symfony/inflector": { 222 | "version": "v4.1.1" 223 | }, 224 | "symfony/intl": { 225 | "version": "v4.1.1" 226 | }, 227 | "symfony/lts": { 228 | "version": "4-dev" 229 | }, 230 | "symfony/maker-bundle": { 231 | "version": "1.0", 232 | "recipe": { 233 | "repo": "github.com/symfony/recipes", 234 | "branch": "master", 235 | "version": "1.0", 236 | "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" 237 | } 238 | }, 239 | "symfony/monolog-bridge": { 240 | "version": "v4.1.1" 241 | }, 242 | "symfony/monolog-bundle": { 243 | "version": "3.1", 244 | "recipe": { 245 | "repo": "github.com/symfony/recipes", 246 | "branch": "master", 247 | "version": "3.1", 248 | "ref": "51b7a31438c8aeeda7931a0ece98a945c91e7f20" 249 | } 250 | }, 251 | "symfony/options-resolver": { 252 | "version": "v4.1.1" 253 | }, 254 | "symfony/orm-pack": { 255 | "version": "v1.0.5" 256 | }, 257 | "symfony/phpunit-bridge": { 258 | "version": "4.1", 259 | "recipe": { 260 | "repo": "github.com/symfony/recipes", 261 | "branch": "master", 262 | "version": "4.1", 263 | "ref": "2955e26d3818b803d82b5de05d91805df5994d3a" 264 | } 265 | }, 266 | "symfony/polyfill-ctype": { 267 | "version": "v1.8.0" 268 | }, 269 | "symfony/polyfill-intl-icu": { 270 | "version": "v1.8.0" 271 | }, 272 | "symfony/polyfill-mbstring": { 273 | "version": "v1.8.0" 274 | }, 275 | "symfony/polyfill-php72": { 276 | "version": "v1.8.0" 277 | }, 278 | "symfony/process": { 279 | "version": "v4.1.1" 280 | }, 281 | "symfony/profiler-pack": { 282 | "version": "v1.0.3" 283 | }, 284 | "symfony/property-access": { 285 | "version": "v4.1.1" 286 | }, 287 | "symfony/property-info": { 288 | "version": "v4.1.1" 289 | }, 290 | "symfony/routing": { 291 | "version": "4.0", 292 | "recipe": { 293 | "repo": "github.com/symfony/recipes", 294 | "branch": "master", 295 | "version": "4.0", 296 | "ref": "cda8b550123383d25827705d05a42acf6819fe4e" 297 | } 298 | }, 299 | "symfony/security": { 300 | "version": "v4.1.1" 301 | }, 302 | "symfony/security-bundle": { 303 | "version": "3.3", 304 | "recipe": { 305 | "repo": "github.com/symfony/recipes", 306 | "branch": "master", 307 | "version": "3.3", 308 | "ref": "f8a63faa0d9521526499c0a8f403c9964ecb0527" 309 | } 310 | }, 311 | "symfony/serializer": { 312 | "version": "v4.1.1" 313 | }, 314 | "symfony/serializer-pack": { 315 | "version": "v1.0.1" 316 | }, 317 | "symfony/stopwatch": { 318 | "version": "v4.1.1" 319 | }, 320 | "symfony/swiftmailer-bundle": { 321 | "version": "2.5", 322 | "recipe": { 323 | "repo": "github.com/symfony/recipes", 324 | "branch": "master", 325 | "version": "2.5", 326 | "ref": "3db029c03e452b4a23f7fc45cec7c922c2247eb8" 327 | } 328 | }, 329 | "symfony/test-pack": { 330 | "version": "v1.0.2" 331 | }, 332 | "symfony/translation": { 333 | "version": "3.3", 334 | "recipe": { 335 | "repo": "github.com/symfony/recipes", 336 | "branch": "master", 337 | "version": "3.3", 338 | "ref": "6bcd6c570c017ea6ae5a7a6a027c929fd3542cd8" 339 | } 340 | }, 341 | "symfony/twig-bridge": { 342 | "version": "v4.1.1" 343 | }, 344 | "symfony/twig-bundle": { 345 | "version": "3.3", 346 | "recipe": { 347 | "repo": "github.com/symfony/recipes", 348 | "branch": "master", 349 | "version": "3.3", 350 | "ref": "f75ac166398e107796ca94cc57fa1edaa06ec47f" 351 | } 352 | }, 353 | "symfony/validator": { 354 | "version": "4.1", 355 | "recipe": { 356 | "repo": "github.com/symfony/recipes", 357 | "branch": "master", 358 | "version": "4.1", 359 | "ref": "0cdc982334f45d554957a6167e030482795bf9d7" 360 | } 361 | }, 362 | "symfony/var-dumper": { 363 | "version": "v4.1.1" 364 | }, 365 | "symfony/web-link": { 366 | "version": "v4.1.1" 367 | }, 368 | "symfony/web-profiler-bundle": { 369 | "version": "3.3", 370 | "recipe": { 371 | "repo": "github.com/symfony/recipes", 372 | "branch": "master", 373 | "version": "3.3", 374 | "ref": "6bdfa1a95f6b2e677ab985cd1af2eae35d62e0f6" 375 | } 376 | }, 377 | "symfony/web-server-bundle": { 378 | "version": "3.3", 379 | "recipe": { 380 | "repo": "github.com/symfony/recipes", 381 | "branch": "master", 382 | "version": "3.3", 383 | "ref": "dae9b39fd6717970be7601101ce5aa960bf53d9a" 384 | } 385 | }, 386 | "symfony/webpack-encore-pack": { 387 | "version": "1.0", 388 | "recipe": { 389 | "repo": "github.com/symfony/recipes", 390 | "branch": "master", 391 | "version": "1.0", 392 | "ref": "b87dfd249390a7b534caa137450277930901236e" 393 | } 394 | }, 395 | "symfony/yaml": { 396 | "version": "v4.1.1" 397 | }, 398 | "twig/twig": { 399 | "version": "v2.5.0" 400 | }, 401 | "webmozart/assert": { 402 | "version": "1.3.0" 403 | }, 404 | "zendframework/zend-code": { 405 | "version": "3.3.0" 406 | }, 407 | "zendframework/zend-eventmanager": { 408 | "version": "3.2.1" 409 | } 410 | } 411 | -------------------------------------------------------------------------------- /templates/base.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {% block title %}謎.Games{% endblock %} 9 | 10 | {% block javascripts %} 11 | 12 | 13 | {% endblock %} 14 | {% block stylesheets %} 15 | 16 | {% endblock %} 17 | 18 | 19 | 20 | {% block header %}{% endblock %} 21 | {% block main %}{% endblock %} 22 | {% block footer %}{% endblock %} 23 | {% block post_body_javascripts %}{% endblock %} 24 | {% block track_code %} 25 | 26 | 27 | 34 |
35 | 36 |
37 | {% endblock %} 38 | 39 | -------------------------------------------------------------------------------- /templates/editor.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'index.html.twig' %} 2 | {% block stylesheets %} 3 | {{ parent() }} 4 | 10 | {% endblock %} 11 | {% block main %} 12 | 13 |
14 | 15 |

关卡编辑器

16 | 17 | {% if can_propose == false %} 18 |
19 |
积分不足
20 |

您需要至少30积分以解锁关卡提交

21 | {% endif %} 22 | 23 |
24 |
25 |
26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 |
37 |
38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
47 | 48 | 49 |

可用颜色: 50 | red, orange, 51 | yellow, olive, 52 | green, teal, 53 | blue, violet, 54 | purple, pink, 55 | brown, grey, 56 | black

57 |
58 | 59 |
60 | 61 |
{{code|default}}
62 |
63 | 64 |

* 关卡使用 Twig 编写,推荐基于 (extends) level_base.html.twig 模板修改。

65 |

* 您可以使用模板自带的 Semantic UI 框架

66 |

* 我们鼓励您包括关卡的解决思路以供审核(请使用注释表明思路,会在审核时候删去)。

67 |

* 若需要包含 php 代码,请使用注释包括在关卡内,审核时会人工转换成 php。请勿提交恶意 javascript 脚本或 php 代码。

68 |

* 您同意我们在不修改关卡原意的情况下对关卡进行修改(包括但不限于关卡内容,标签,分数等)。

69 |

* 关卡审核通过后作者将获得 {关卡积分*5} 积分作为奖励。

70 |

* 由于关卡都是人工审核的,如果您有任何建议或意见也欢迎一同提交。

71 | 72 | 73 |
74 |
75 | 76 | {% endblock %} 77 | 78 | {% block post_body_javascripts %} 79 | 80 | 88 | {% endblock %} 89 | -------------------------------------------------------------------------------- /templates/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | {% block stylesheets %} 3 | {{ parent() }} 4 | 5 | {% endblock %} 6 | {% block javascripts %} 7 | {{ parent() }} 8 | 9 | {% endblock %} 10 | {% block header %} 11 | 38 |
39 | 40 |
41 | 47 |
48 | 49 |
50 |

51 | 謎.Games 52 |

53 |

解决「謎」题吧

54 |
55 | 56 |
57 | {% endblock %} 58 | 59 | {% block main %} 60 | 61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
关卡进度
71 |
72 |
73 |
74 |
75 |
{{ user.score }}
76 |
积分
77 |
78 |
79 |
80 |
81 |
{{ rank }}
82 |
排名
83 |
84 |
85 |
86 |

关卡列表

87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | {% for level in levels %} 101 | 102 | 108 | 109 | 124 | 125 | 126 | 127 | 128 | 129 | {% endfor %} 130 | 131 |
关卡标题作者积分通过率评价
103 | {% if level.id in user.getPassedLevels %}{% endif %} 104 | {% if level.id not in user.getPassedLevels and user.score < level.unlockScore %} 105 |
106 | {% endif %} 107 |
{{level.id}} 110 | {{level.name}} 111 | 112 | {% if level.underReview %} 113 | (审核) 114 | {% endif %} 115 | {% for tag in level.tags %} 116 | {% if tag!="" %} 117 | {% set tagcolor = tag|split('|') %} 118 | 119 | {{tagcolor[1]}} 120 | 121 | {% endif %} 122 | {% endfor %} 123 | {{level.author}}{{level.score}}{{level.getPassedNum}}/{{level.getTriedNum}}({{(level.getPassedNum/(level.getTriedNum==0?1:level.getTriedNum))*100//1}}%){{level.getRatedNum==0? "--": ((level.getTotalRating/level.getRatedNum)|number_format(1)) }}
132 |
133 |
134 |

排行榜

135 | 136 | 137 | {% for user in top10 %} 138 | 139 | 140 | 141 | 142 | 143 | {% endfor %} 144 | 145 |
{{ loop.index }}{{user.getDisplayName}}{{user.getScore}}
146 |
147 |
148 |
149 | 150 | {% endblock %} 151 | 152 | {% block footer %} 153 | 170 | {% endblock %} 171 | 172 | {% block post_body_javascripts %} 173 | 190 | 191 | {% endblock %} 192 | -------------------------------------------------------------------------------- /templates/levels/level_base.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | {% block title %}Level {{level.id}}: {{level.name}}{% endblock %} 3 | {% block stylesheets %} 4 | {{ parent() }} 5 | 6 | {% endblock %} 7 | {% block main %} 8 | 24 | 25 |
26 |
27 | {% if level.underReview %} 28 |
29 | 30 |
审核中
31 |

您所查看的关卡正在审核中

32 | {% endif %} 33 |
34 | {% block pre_block %} 35 | {# 36 |
37 | 38 |
39 | #} 40 | {% endblock %} 41 |
42 |
43 | {{level.name}} 44 |
45 |
46 | {{level.getPassedNum}}/{{level.getTriedNum}} ({{(level.getPassedNum/(level.getTriedNum==0?1:level.getTriedNum))*100//1}}%)人通过了这关 47 |

48 | {% for tag in level.tags %} 49 | {% if tag!="" %} 50 | {% set tagcolor = tag|split('|') %} 51 | {{tagcolor[1]}} 52 | {% endif %} 53 | {% endfor %} 54 |

55 |
56 | 57 |
58 | {% block description %} 59 | {# 60 | 61 | 下载附件 62 | 63 | #} 64 | {% endblock %} 65 |
66 |
67 |
68 | {% block submit %} 69 |
70 | 71 | 72 | 73 |
74 | 78 | {% endblock %} 79 |
80 | 81 |
82 |
83 |
84 | 85 | {% endblock %} 86 | 87 | {% block post_body_javascripts %} 88 | 89 | {% endblock %} 90 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var Encore = require('@symfony/webpack-encore'); 2 | 3 | Encore 4 | // directory where compiled assets will be stored 5 | .setOutputPath('public/build/') 6 | // public path used by the web server to access the output path 7 | .setPublicPath('/build') 8 | // only needed for CDN's or sub-directory deploy 9 | //.setManifestKeyPrefix('build/') 10 | 11 | /* 12 | * ENTRY CONFIG 13 | * 14 | * Add 1 entry for each "page" of your app 15 | * (including one that's included on every page - e.g. "app") 16 | * 17 | * Each entry will result in one JavaScript file (e.g. app.js) 18 | * and one CSS file (e.g. app.css) if you JavaScript imports CSS. 19 | */ 20 | .addEntry('app', './assets/js/app.js') 21 | //.addEntry('page1', './assets/js/page1.js') 22 | //.addEntry('page2', './assets/js/page2.js') 23 | 24 | /* 25 | * FEATURE CONFIG 26 | * 27 | * Enable & configure other features below. For a full 28 | * list of features, see: 29 | * https://symfony.com/doc/current/frontend.html#adding-more-features 30 | */ 31 | .cleanupOutputBeforeBuild() 32 | .enableBuildNotifications() 33 | .enableSourceMaps(!Encore.isProduction()) 34 | // enables hashed filenames (e.g. app.abc123.css) 35 | .enableVersioning(Encore.isProduction()) 36 | 37 | // enables Sass/SCSS support 38 | //.enableSassLoader() 39 | 40 | // uncomment if you use TypeScript 41 | //.enableTypeScriptLoader() 42 | 43 | // uncomment if you're having problems with a jQuery plugin 44 | //.autoProvidejQuery() 45 | ; 46 | 47 | module.exports = Encore.getWebpackConfig(); 48 | --------------------------------------------------------------------------------