diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3b43e38 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,65 @@ +### IDE files +.idea/ + +### Composer files +auth.json + +### GIT files +.git +# Skipped as it makes build very slow and since it is needed by composer when working on dev branches +#vendor/*/*/.git + +### Symfony template +# Cache and logs (Symfony2) +app/cache/* +app/logs/* +!app/cache/.keep +!app/logs/.keep + +# Email spool folder +app/spool/* + +# Cache, session files and logs (Symfony3) +var/cache/* +var/logs/* +var/sessions/* +!var/cache/.gitkeep +!var/logs/.gitkeep +!var/sessions/.gitkeep + +# Parameters (should be regenerated in container) +app/config/parameters.yml + +# Managed by Composer +app/bootstrap.php.cache +var/bootstrap.php.cache +#bin/* +#!bin/console +#!bin/symfony_requirements + +# Disabled as this is needed for dev setups unless we change dev to execute composer install automatically +#vendor/ + +# Assets and user uploads +web/bundles/ +web/css/ +web/js/ +web/uploads/ +web/fonts/ + +# Assets managed by Bower +web/assets/vendor/ + +# PHPUnit +app/phpunit.xml +phpunit.xml + +# Build data +build/ + +# Composer PHAR +composer.phar + +# Backup entities generated with doctrine:generate:entities command +*/Entity/*~ + diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..74e0e7c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{js,jsx}] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.env b/.env new file mode 100644 index 0000000..5fd64db --- /dev/null +++ b/.env @@ -0,0 +1,32 @@ +# Allows us to set default values of env variables, see: https://docs.docker.com/compose/env-file/ +COMPOSE_FILE=doc/docker/base-dev.yml +COMPOSE_DIR=. + +# You'll need to adjust this for Windows and XDB Linux systems: https://getcomposer.org/doc/03-cli.md#composer-home +COMPOSER_HOME=~/.composer +COMPOSER_MEMORY_LIMIT=4G +DATABASE_USER=ezp +DATABASE_PASSWORD=SetYourOwnPassword +DATABASE_NAME=ezp + +## Docker images (name and version) +PHP_IMAGE=ezsystems/php:7.3-v1 +PHP_IMAGE_DEV=ezsystems/php:7.3-v1-dev +NGINX_IMAGE=nginx:stable +MYSQL_IMAGE=healthcheck/mariadb +SELENIUM_IMAGE=selenium/standalone-chrome-debug:3.141.59-oxygen +REDIS_IMAGE=healthcheck/redis + +APP_DOCKER_FILE=doc/docker/Dockerfile-app + +DATASET_VARDIR=my-ez-app + +# Behat / Selenium config +## web host refer to the tip of the setup, so varnish if that is used. +WEB_HOST=web +SELENIUM_HOST=selenium + +# Enable recommendations by setting valid id, key and uri +#RECOMMENDATIONS_CUSTOMER_ID="" +#RECOMMENDATIONS_LICENSE_KEY="" +#PUBLIC_SERVER_URI="" diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..656767b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,42 @@ +{ + "extends": "airbnb", + "rules": { + "indent": ["error", 2, { "SwitchCase": 1 }], + "max-len": 0, + "no-plusplus": 0, + "func-names": 0, + "no-unused-expressions": ["error", { + "allowShortCircuit": true, + "allowTernary": true + } + ], + "no-param-reassign": ["error", { + "props": false + }], + "comma-dangle": ["error", { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "always-multiline", + "functions": "ignore" + } + ], + "react/require-default-props": 0, + "react/forbid-prop-types": 0, + "react/jsx-filename-extension": 0, + "react/jsx-indent": 0, + "react/jsx-no-bind": 0, + "react/jsx-wrap-multilines": 0, + "react/no-array-index-key": 0, + "jsx-a11y/href-no-hash": 0 + }, + "plugins": [ + "react", + "jsx-a11y", + "import" + ], + "env": { + "browser": true, + "node": true + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..857cce8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +web/build/app.css binary -merge +web/build/app.js binary -merge diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d6af1f --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +.idea/ +.sass-cache/ +.tmp/ +node_modules/ +/bin/* +!bin/.ci/ +!bin/.travis/ +!bin/console +!bin/platformsh_prestart_cacheclear.sh +!bin/vhost.sh +!bin/sync_db_and_var.sh +/app/config/parameters.yml +/app/config/server/local/ +/app/config/server/local.yml +/app/solr +/doc/docker/entrypoint/*/*.sql +/dfsdata +/extension/ +/ezpublish_legacy/ +/phpunit.xml +/var/* +!/var/cache +/var/cache/* +!var/cache/.gitkeep +!/var/logs +/var/logs/* +!var/logs/.gitkeep +!/var/sessions +/var/sessions/* +!var/sessions/.gitkeep +!/var/encore +/var/encore/* +!var/encore/.gitkeep +/vendor/ +/web/assets/app/* +!/web/assets/app/build/ +/web/assets/build/* +/web/assets/ezplatform/* +!/web/assets/ezplatform/build/ +/web/bundles/ +/web/design +/web/extension +/web/share +/web/var +/web/.htaccess +/web/index_treemenu.php +/web/index_rest.php +/web/index_cluster.php +/web/robots.txt +auth.json +behat.yml +composer.phar +ide-twig.json +package-lock.json +studio.json +yarn-error.log +.DS_Store +.php_cs.cache +.phpunit.result.cache +.web-server-pid diff --git a/.php_cs b/.php_cs new file mode 100644 index 0000000..04244d2 --- /dev/null +++ b/.php_cs @@ -0,0 +1,39 @@ +setRiskyAllowed(true) + ->setRules([ + '@PhpCsFixer' => true, + '@PhpCsFixer:risky' => true, + + // Overrides for rules included in PhpCsFixer rule sets + 'concat_space' => ['spacing' => 'one'], + 'method_chaining_indentation' => false, + 'multiline_whitespace_before_semicolons' => false, + 'native_function_invocation' => false, + 'no_superfluous_phpdoc_tags' => false, + 'php_unit_internal_class' => false, + 'php_unit_set_up_tear_down_visibility' => false, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], + 'php_unit_test_class_requires_covers' => false, + 'phpdoc_align' => false, + 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], + 'single_line_comment_style' => false, + 'visibility_required' => ['elements' => ['property', 'method', 'const']], + 'yoda_style' => false, + + // Additional rules + 'date_time_immutable' => true, + 'declare_strict_types' => true, + 'list_syntax' => ['syntax' => 'short'], + 'mb_str_functions' => true, + 'static_lambda' => true, + 'ternary_to_null_coalescing' => true, + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->exclude(['ezpublish_legacy']) + ->in('src') + ->append(['app/AppKernel.php']) + ) +; diff --git a/.platform.app.yaml b/.platform.app.yaml new file mode 100644 index 0000000..05584d0 --- /dev/null +++ b/.platform.app.yaml @@ -0,0 +1,189 @@ +# This file describes an application. You can have multiple applications +# in the same project. + +# Please see doc/platformsh/README.md and doc/platformsh/INSTALL.md for eZ specific getting started instructions. +# Full documentation: https://docs.platform.sh +# Requirements: https://doc.ezplatform.com/en/2.5/getting_started/requirements/#ez-platform-cloud-requirements-and-setup + +# The name of this app. Must be unique within a project. +name: app + +dependencies: + nodejs: + yarn: "*" + +# The type of the application to build. +type: php:7.3 + +build: + # "none" means we're running composer manually, see build hook + # We currently need to do this to install newer version of Node.js + flavor: "none" + +# The relationships of the application with services or other applications. +# The left-hand side is the name of the relationship as it will be exposed +# to the application in the PLATFORM_RELATIONSHIPS variable. The right-hand +# side is in the form `:`. +relationships: + database: 'mysqldb:user' + # Uncomment if you want to store dfs tables in a separate database: + #dfs_database: 'mysqldb:dfs' + rediscache: 'rediscache:redis' + # [Recommended] To have an isolated and persisted Redis instance for sessions, uncomment + # this relationship and the corresponding service in .platform/services.yaml + #redissession: 'redissession:redis' + # If you wish to use solr, uncomment this relationship and the corresponding service in .platform/services.yaml + #solr: 'solrsearch:collection1' + +variables: + php: + # Example of setting php.ini config + #"display_errors": "On" + memory_limit: 512M + env: + # We disable Symfony Proxy (AppCache), as we rather use Varnish + SYMFONY_HTTP_CACHE: 0 + # Warning: Only for Varnish on Platform.sh to workarounbd missing IP. Disable if you use Fastly or Symfony Proxy where this would be a security issue! + SYMFONY_TRUSTED_PROXIES: "TRUST_REMOTE" + # Change this if you use a different env than "prod" + # If you change to "dev" remove "--no-dev" from the `composer install` command. + SYMFONY_ENV: prod + # Uncomment if you want to use DFS clustering: + # NOTE: Recommended on PE Dedicated cluster setup. Required if using Legacy Bridge on PE dedicated cluster setup. + #PLATFORMSH_DFS_NFS_PATH: 'dfsdata' + +# The configuration of app when it is exposed to the web. +web: + locations: + "/": + # The public directory of the app, relative to its root. + root: "web" + # The front-controller script to send non-static requests to. + passthru: "/app.php" + # The number of seconds whitelisted (static) content should be cache + expires: 600 + rules: + # Disable .php(3) and other executable extensions in the var directory + '^/var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$': + allow: false + +# The size of the persistent disk of the application (in MB). +disk: 3072 + +# The mounts that will be performed when the package is deployed. +mounts: +# PE Cluster Note: By default will set all to shared, so if moving to PE dedicated cluster you should ask platform.sh +# Support to make sure at least cache + logs are local, while you can let web/var be shared if you prefer that over DFS. + 'var/cache': + source: local + source_path: cache + 'var/logs': + source: local + source_path: logs + 'var/encore': + source: local + source_path: encore + 'web/var': + source: local + source_path: var + # [PE Cluster] For cluster it's recommended to rather use a performant shared session storage like Redis/Memcached. + 'var/sessions': + source: local + source_path: sessions +# Uncomment if you need to use Kaliop Migrations on your setup and not able to get it to write to "var" dir. +# 'src/AppBundle/MigrationVersions/References': +# source: local +# source_path: MigrationVersionsReferences +# Uncomment if you want to use DFS clustering, required if using Legacy Bridge on PE dedicated cluster setup. +# 'dfsdata': +# # Platform.sh Staff: This MUST be shared on cluster, all others SHOULD be local for performance reasons +# source: local +# source_path: dfsdata + +# The hooks that will be performed when the package is deployed. +hooks: + # Build hook, done before connected to services, disk is still writable here + build: | + set -e + + # Install newer version of Node.js, as current default (v6LTS) does not play well with WebpackEncore + unset NPM_CONFIG_PREFIX + curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | dash + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + nvm current + nvm install 10.15.3 + + if [ -z "$COMPOSER_AUTH" ]; then + echo "TIP: If you need to authenticate against Github/Gitlab/updates.ez.no, use COMPOSER_AUTH env variable" + echo "See: https://docs.platform.sh/tutorials/composer-auth.html#set-the-envcomposerauth-project-variable" + fi + + composer install --no-dev --prefer-dist --no-progress --no-interaction --optimize-autoloader + + # Generic cleanup to remove files we don't want to be deployed to prod (you don't need this for "dev" ENV) + rm web/app_dev.php + + # Deploy hook, access to services & done once (per cluster, not per node), only mounts are writable at this point + # Note: Http traffic is paused while this is running, so for prod code this should finish as fast as possible, < 30s + deploy: | + set -e + + unset NPM_CONFIG_PREFIX + command -v nvm && nvm use 10.15.3 + + # Mainly relevant for eZ Platform demo usage, for own setup adapt this or remove and rely on migrations. + if [ ! -f web/var/.platform.installed ]; then + # To workaround issues with p.sh Varnish we clear container cache & temporary set Symfony Proxy + rm -Rf var/cache/$SYMFONY_ENV/*.* + HTTPCACHE_PURGE_TYPE="local" php -d memory_limit=-1 `which composer` ezplatform-install + touch web/var/.platform.installed + fi + + # Now that mounts are available, clear cache on mount. + # Note: Skip on PE Cluster setup using e.g. "if [$PLATFORM_BRANCH" != 'production']; then" & get p.sh to enable this on internal per node "pre_start" hook + sh bin/platformsh_prestart_cacheclear.sh + + # If you also need to clear Redis cache on every deploy, you can either use this command or redis-cli + # Normally this should only be needed if cached data structures changes (upgrades), or you change data via sql (e.g. restore backup) + ##php bin/console cache:pool:clear cache.redis + + # Example of additional deploy hooks if you use doctrine and/or kaliop migration bundle + ##php bin/console doctrine:migrations:migrate --no-interaction --allow-no-migration + ##php bin/console kaliop:migration:migrate --no-interaction --no-debug + + # When using Solr, there are two cases where you'll need to rebuild indexes: + # - When Solr / search configuration changes + # - On database import/restore + # So in development it might be convenient to rebuild indexes, slowing down deploy time + ##php bin/console ezplatform:reindex --processes=auto + + # Post deploy hook, like deploy but after being deployed and live, for deploy tasks we can do asynchronously + #post_deploy: | + # set -e + +# The configuration of scheduled execution. +# see https://docs.platform.sh/configuration/app/cron.html#cron-jobs +crons: + frequent: + # NOTE: The minimum interval between cron runs is 5 minutes, even if specified as less. + # Except for PE. There crons can be run every minute. + # So if you are not on PE please change specs to "*/5 * * * *" to avoid warning on each deploy. + spec: "* * * * *" + cmd: "php bin/console ezplatform:cron:run" + weekly: + spec: "0 0 * * 0" + cmd: "php bin/console ezplatform:check-urls --quiet" + +runtime: + extensions: + - xsl + - imagick + - readline + - redis + - igbinary + #- apcu + #- name: 'blackfire' + # configuration: + # server_id: 'xxxx-xxx-xxx-xxx-xxxx' + # server_token: 'xxxx' diff --git a/.platform/routes.yaml b/.platform/routes.yaml new file mode 100644 index 0000000..1525d92 --- /dev/null +++ b/.platform/routes.yaml @@ -0,0 +1,11 @@ +"https://{default}/": + type: upstream + upstream: "varnish:http" + cache: + # As this does not support Vary, and purging, we can't use this as Sf Proxy drop in. + # However it is possible to enable this for anonymous traffic when backend sends expiry headers. + enabled: false + +"https://www.{default}/": + type: redirect + to: "https://{default}/" diff --git a/.platform/services.yaml b/.platform/services.yaml new file mode 100644 index 0000000..748038e --- /dev/null +++ b/.platform/services.yaml @@ -0,0 +1,85 @@ +# Default settings in order to set up eZ Platform demo install on Platform.sh dev instances +# +# Note: Like on own servers, make sure to tune Redis/Solr/Varnish/MySQL memory/disk size for your installation to avoid issues. +# Reach out to platform.sh support to get help on this and insight into your disk/memory usage. + +mysqldb: + # Note: If you change this also change DATABASE_VERSION, as used by "doctrine.dbal.server_version" in config.yml. + type: mariadb:10.2 + # Version 10.1 might be a better option when running Legacy Bridge + # For more information see https://doc.ezplatform.com/en/2.1/getting_started/requirements_and_system_configuration/#supported-setups + disk: 1024 + configuration: + schemas: + - main + # Uncomment if you want to store dfs tables in a separate database: + #- dfs + endpoints: + user: + default_schema: main + privileges: + main: admin + # Uncomment if you want to store dfs tables in a separate database: + #dfs: + # default_schema: dfs + # privileges: + # dfs: admin + +# For use by Symfony Cache (used by eZ Platform SPI Persistence Cache) +rediscache: + type: 'redis:5.0' + # For cache you might need to increase the size of your plan if your installation has a sizeable amount of content. + # Check with platform.sh staff if in doubt on this, and if it would make sense to configure larger redis size here. + # size: L + configuration: + # For cache eZ Platform 2.5+ RedisTagAwareAdapter requries one of the 'volatile-*' eviction policies + # https://docs.platform.sh/configuration/services/redis.html#eviction-policy + # https://doc.ezplatform.com/en/2.5/getting_started/requirements/ + maxmemory_policy: volatile-lru + +# If you wish to have a separate Redis instance for sessions, uncomment +# this service and the corresponding relationship in .platform.app.yaml. +#redissession: +# type: 'redis:5.0' +# configuration: +# maxmemory_policy: allkeys-lru +# +# Alternatively if you have a requirement that sessions are persisted across server/redis restarts, +# have storage space to spare for this, and don't mind a bit slower instance type of redis +#redissession: +# type: redis-persistent:5.0 +# Disk size should be bigger than Redis' "maxmemory" setting due to https://redis.io/topics/persistence#log-rewriting. +# The memory given to Redis depends on your plan and "size: ". Adjust "disk: " accordingly. +# disk: 512 +# configuration: +# maxmemory_policy: allkeys-lru + +# If you wish to use solr, uncomment this service and the corresponding relationship in .platform.app.yaml. +# Also, you need to generate the config using: +# vendor/ezsystems/ezplatform-solr-search-engine/bin/generate-solr-config.sh +# Multi core setup is currently not supported on Platform.sh. Sharding does not work as the cores are +# unable to reach each other +#solrsearch: +# type: solr:6.6 +# disk: 512 +# configuration: +# configsets: +# mainconfig: !archive "configsets/solr6" +# cores: +# collection1: +# core_properties: | +# configSet=mainconfig +# schema=schema.xml +# endpoints: +# collection1: +# core: collection1 + +# Due to logic in app/config/env/platformsh.php, do not change the service name to something different than 'varnish' +varnish: + type: 'varnish:6.0' + relationships: + app: "app:http" + configuration: + vcl: !include + type: string + path: varnish.vcl diff --git a/.platform/varnish.vcl b/.platform/varnish.vcl new file mode 100644 index 0000000..9016748 --- /dev/null +++ b/.platform/varnish.vcl @@ -0,0 +1,336 @@ +// Varnish VCL for: +// - Varnish 5.1 or higher (6.0LTS recommended, and is what we mainly test against) +// - Varnish xkey vmod (via varnish-modules package, or via Varnish Plus) +// - eZ Platform 2.5LTS or higher with ezplatform-http-cache (this) bundle +// +// Make sure to at least adjust default parameters.yml, defaults there reflect our testing needs with docker. + +// Not applicable on Platform.sh: +//vcl 4.0; +//import std; +import xkey; + +// For customizing your backend and acl rules see parameters.vcl +// Includes not available on Platform.sh +//include "parameters.vcl"; +acl invalidators { + "127.0.0.1"; + "192.168.0.0"/16; +} + +// ACL for debuggers IP +acl debuggers { + "127.0.0.1"; + "192.168.0.0"/16; +} + +// Called at the beginning of a request, after the complete request has been received +sub vcl_recv { + + // Set the backend + //set req.backend_hint = ezplatform; + // Platform.sh specific: + set req.backend_hint = app.backend(); + + // Add a Surrogate-Capability header to announce ESI support. + set req.http.Surrogate-Capability = "abc=ESI/1.0"; + + // Ensure that the Symfony Router generates URLs correctly with Varnish + if (req.http.X-Forwarded-Proto == "https" ) { + set req.http.X-Forwarded-Port = "443"; + } else { + set req.http.X-Forwarded-Port = "80"; + } + + // Trigger cache purge if needed + call ez_purge; + + // Don't cache requests other than GET and HEAD. + if (req.method != "GET" && req.method != "HEAD") { + return (pass); + } + + // Don't cache Authenticate & Authorization + // You may remove this when using REST API with basic auth. + if (req.http.Authenticate || req.http.Authorization) { + if (client.ip ~ debuggers) { + set req.http.X-Debug = "Not Cached according to configuration (Authorization)"; + } + return (hash); + } + + // Remove all cookies besides Session ID, as JS tracker cookies and so will make the responses effectively un-cached + if (req.http.cookie) { + set req.http.cookie = ";" + req.http.cookie; + set req.http.cookie = regsuball(req.http.cookie, "; +", ";"); + set req.http.cookie = regsuball(req.http.cookie, ";(eZSESSID[^=]*)=", "; \1="); + set req.http.cookie = regsuball(req.http.cookie, ";[^ ][^;]*", ""); + set req.http.cookie = regsuball(req.http.cookie, "^[; ]+|[; ]+$", ""); + + if (req.http.cookie == "") { + // If there are no more cookies, remove the header to get page cached. + unset req.http.cookie; + } + } + + // Do a standard lookup on assets (these don't vary by user context hash) + // Note that file extension list below is not extensive, so consider completing it to fit your needs. + if (req.url ~ "\.(css|js|gif|jpe?g|bmp|png|tiff?|ico|img|tga|wmf|svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|zip|gz|pdf|ttf|eot|wof)$") { + return (hash); + } + + // Sort the query string for cache normalization. + set req.url = std.querysort(req.url); + + // Retrieve client user context hash and add it to the forwarded request. + call ez_user_context_hash; + + // If it passes all these tests, do a lookup anyway. + return (hash); +} + +// Called when a cache lookup is successful. The object being hit may be stale: It can have a zero or negative ttl with only grace or keep time left. +sub vcl_hit { + if (obj.ttl >= 0s) { + // A pure unadulterated hit, deliver it + return (deliver); + } + + if (obj.ttl + obj.grace > 0s) { + // Object is in grace, logic below in this block is what differs from default: + // https://varnish-cache.org/docs/5.2/users-guide/vcl-grace.html#grace-mode + if (!std.healthy(req.backend_hint)) { + // Service is unhealthy, deliver from cache + return (deliver); + } else if (req.http.cookie) { + // Request it by a user with session, refresh the cache to avoid issues for editors and forum users + return (miss); + } + + // By default deliver cache, automatically triggers a background fetch + return (deliver); + } + + // fetch & deliver once we get the result + return (miss); +} + +// Called when the requested object has been retrieved from the backend +sub vcl_backend_response { + + if (bereq.http.accept ~ "application/vnd.fos.user-context-hash" + && beresp.status >= 500 + ) { + return (abandon); + } + + // Check for ESI acknowledgement and remove Surrogate-Control header + if (beresp.http.Surrogate-Control ~ "ESI/1.0") { + unset beresp.http.Surrogate-Control; + set beresp.do_esi = true; + } + + // Make Varnish keep all objects for up to 1 hour beyond their TTL, see vcl_hit for Request logic on this + set beresp.grace = 1h; + + // Compressing the content + if (beresp.http.Content-Type ~ "application/javascript" + || beresp.http.Content-Type ~ "application/json" + || beresp.http.Content-Type ~ "application/vnd.ms-fontobject" + || beresp.http.Content-Type ~ "application/vnd.ez.api" + || beresp.http.Content-Type ~ "application/x-font-ttf" + || beresp.http.Content-Type ~ "image/svg+xml" + || beresp.http.Content-Type ~ "text/css" + || beresp.http.Content-Type ~ "text/plain" + ) { + set beresp.do_gzip = true; + } +} + +// Handle purge +// You may add FOSHttpCacheBundle tagging rules +// See http://foshttpcache.readthedocs.org/en/latest/varnish-configuration.html#id4 +sub ez_purge { + // Retrieve purge token, needs to be here due to restart, match for PURGE method done within + call ez_invalidate_token; + + # Support how purging was done in earlier versions, this is deprecated and here just for BC for code still using it + if (req.method == "BAN") { + call ez_purge_acl; + + if (req.http.X-Location-Id) { + ban("obj.http.X-Location-Id ~ " + req.http.X-Location-Id); + if (client.ip ~ debuggers) { + set req.http.X-Debug = "Ban done for content connected to LocationId " + req.http.X-Location-Id; + } + return (synth(200, "Banned")); + } + } + + if (req.method == "PURGE") { + call ez_purge_acl; + + # If http header "key" is set, we assume purge is on key and you have Varnish xkey installed + if (req.http.key) { + # By default we recommend using soft purge to respect grace time, if you need to hard purge use: + # set req.http.n-gone = xkey.purge(req.http.key); + set req.http.n-gone = xkey.softpurge(req.http.key); + + return (synth(200, "Invalidated "+req.http.n-gone+" objects")); + } + + # if not, then this is a normal purge by url + return (purge); + } +} + +sub ez_purge_acl { + if (req.http.x-invalidate-token) { + if (req.http.x-invalidate-token != req.http.x-backend-invalidate-token) { + return (synth(405, "Method not allowed")); + } + } else if (!client.ip ~ invalidators) { + return (synth(405, "Method not allowed")); + } +} + +// Sub-routine to get client user context hash, used to for being able to vary page cache on user rights. +sub ez_user_context_hash { + + // Prevent tampering attacks on the hash mechanism + if (req.restarts == 0 + && (req.http.accept ~ "application/vnd.fos.user-context-hash" + || req.http.x-user-hash + ) + ) { + return (synth(400, "Bad Request")); + } + + if (req.restarts == 0 && (req.method == "GET" || req.method == "HEAD")) { + // Backup accept header, if set + if (req.http.accept) { + set req.http.x-fos-original-accept = req.http.accept; + } + set req.http.accept = "application/vnd.fos.user-context-hash"; + + // Backup original URL + set req.http.x-fos-original-url = req.url; + set req.url = "/_fos_user_context_hash"; + + // Force the lookup, the backend must tell not to cache or vary on all + // headers that are used to build the hash. + return (hash); + } + + // Rebuild the original request which now has the hash. + if (req.restarts > 0 + && req.http.accept == "application/vnd.fos.user-context-hash" + ) { + set req.url = req.http.x-fos-original-url; + unset req.http.x-fos-original-url; + if (req.http.x-fos-original-accept) { + set req.http.accept = req.http.x-fos-original-accept; + unset req.http.x-fos-original-accept; + } else { + // If accept header was not set in original request, remove the header here. + unset req.http.accept; + } + + // Force the lookup, the backend must tell not to cache or vary on the + // user context hash to properly separate cached data. + + return (hash); + } +} + +// Sub-routine to get invalidate token. +sub ez_invalidate_token { + // Prevent tampering attacks on the token mechanisms + if (req.restarts == 0 + && (req.http.accept ~ "application/vnd.ezplatform.invalidate-token" + || req.http.x-backend-invalidate-token + ) + ) { + return (synth(400, "Bad Request")); + } + + if (req.restarts == 0 && req.method == "PURGE" && req.http.x-invalidate-token) { + set req.http.accept = "application/vnd.ezplatform.invalidate-token"; + + set req.url = "/_ez_http_invalidatetoken"; + + // Force the lookup + return (hash); + } + + // Rebuild the original request which now has the invalidate token. + if (req.restarts > 0 + && req.http.accept == "application/vnd.ezplatform.invalidate-token" + ) { + set req.url = "/"; + set req.method = "PURGE"; + unset req.http.accept; + } +} + +sub vcl_deliver { + // On receiving the invalidate token response, copy the invalidate token to the original + // request and restart. + if (req.restarts == 0 + && resp.http.content-type ~ "application/vnd.ezplatform.invalidate-token" + ) { + set req.http.x-backend-invalidate-token = resp.http.x-invalidate-token; + + return (restart); + } + + // On receiving the hash response, copy the hash header to the original + // request and restart. + if (req.restarts == 0 + && resp.http.content-type ~ "application/vnd.fos.user-context-hash" + ) { + set req.http.x-user-hash = resp.http.x-user-hash; + + return (restart); + } + + // If we get here, this is a real response that gets sent to the client. + + // Remove the vary on user context hash, this is nothing public. Keep all + // other vary headers. + if (resp.http.Vary ~ "X-User-Hash") { + set resp.http.Vary = regsub(resp.http.Vary, "(?i),? *X-User-Hash *", ""); + set resp.http.Vary = regsub(resp.http.Vary, "^, *", ""); + if (resp.http.Vary == "") { + unset resp.http.Vary; + } + + // If we vary by user hash, we'll also adjust the cache control headers going out by default to avoid sending + // large ttl meant for Varnish to shared proxies and such. We assume only session cookie is left after vcl_recv. + if (req.http.cookie) { + // When in session where we vary by user hash we by default avoid caching this in shared proxies & browsers + // For browser cache with it revalidating against varnish, use for instance "private, no-cache" instead + set resp.http.cache-control = "private, no-cache, no-store, must-revalidate"; + } else if (resp.http.cache-control ~ "public") { + // For non logged in users we allow caching on shared proxies (mobile network accelerators, planes, ...) + // But only for a short while, as there is no way to purge them + set resp.http.cache-control = "public, s-maxage=600, stale-while-revalidate=300, stale-if-error=300"; + } + } + + if (client.ip ~ debuggers) { + // Add X-Cache header if debugging is enabled + if (obj.hits > 0) { + set resp.http.X-Cache = "HIT"; + set resp.http.X-Cache-Hits = obj.hits; + set resp.http.X-Cache-TTL = obj.ttl; + } else { + set resp.http.X-Cache = "MISS"; + } + } else { + // Remove tag headers when delivering to non debug client + unset resp.http.xkey; + // Sanity check to prevent ever exposing the hash to a non debug client. + unset resp.http.x-user-hash; + } +} diff --git a/.sass-lint.yml b/.sass-lint.yml new file mode 100644 index 0000000..731f7bb --- /dev/null +++ b/.sass-lint.yml @@ -0,0 +1,19 @@ +# Rule Configuration +rules: + indentation: + - 1 + - + size: 4 + class-name-format: 0 + no-css-comments: 0 + nesting-depth: 0 + no-transition-all: 0 + no-color-literals: 0 + property-sort-order: 0 + empty-line-between-blocks: 0 + no-ids: 0 + no-qualifying-elements: 0 + force-attribute-nesting: 0 + force-pseudo-nesting: 0 + force-element-nesting: 0 + mixins-before-declarations: 0 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7cc1ae9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,112 @@ +dist: trusty +language: php +php: + - 7.1 + +services: + - docker + +env: + global: + - COMPOSE_FILE="doc/docker/base-dev.yml:doc/docker/selenium.yml" + - SYMFONY_ENV=behat + - SYMFONY_DEBUG=1 + +cache: + yarn: true + directories: + - $HOME/.composer/cache/files + +# test only master (+ Pull requests) +branches: + only: + - master + - /^\d.\d+$/ + # build tags (vX.Y.Z) + - /^v\d+.\d+.\d+$/ + +# list of behat arguments to test +matrix: + include: + # TMP disable usage of varnish until we figure out segmentation faulty issue on 2.0 + #- TEST_CMD="--mode=behat --profile=rest --suite=fullJson --tags=~@broken" COMPOSE_FILE="doc/docker/base-dev.yml:doc/docker/varnish.yml:doc/docker/selenium.yml" WEB_HOST="varnish" + - name: "PHP Unit tests" + env: + - TEST_CMD="php bin/phpunit -v vendor/ezsystems/ezpublish-kernel/eZ/Bundle/EzPublishRestBundle/Tests/Functional" + - SYMFONY_CMD="ez:behat:create-language 'pol-PL' 'Polish (polski)'" + - name: "Kernel Rest fullJson tests" + env: BEHAT_OPTS="--mode=behat --profile=rest --suite=fullJson --tags=~@broken --non-strict" + - name: "Kernel Rest fullXML tests" + env: BEHAT_OPTS="--mode=behat --profile=rest --suite=fullXml --tags=~@broken --non-strict" + - name: "Kernel Rest core tests" + env: BEHAT_OPTS="--mode=behat --profile=core --tags=~@broken" + - name: "Behat" + env: BEHAT_OPTS="--mode=behat --profile=behat --tags=~@broken" + - name: "Repository Forms tests on Clean Platform" + env: BEHAT_OPTS="--mode=behat --profile=repository-forms --tags=~@broken --non-strict" + - name: "Admin UI on Clean Platform" + env: BEHAT_OPTS="--profile=adminui --suite=adminui" + - name: "Admin UI on Clean Platform with Varnish and Redis" + env: + - COMPOSE_FILE="doc/docker/base-dev.yml:doc/docker/varnish.yml:doc/docker/redis.yml:doc/docker/selenium.yml" + - BEHAT_OPTS="--profile=adminui --suite=adminui" + - WEB_HOST="varnish" + - if: type in (cron, api) + name: "Admin UI tests using different personas" + env: + - SETUP_BEHAT_OPTS="--profile=setup --suite=personas --tags=@setup" + - BEHAT_OPTS="--profile=adminui --suite=personas" + +# reduce depth (history) of git checkout +git: + depth: 30 + +notifications: + slack: + rooms: + - secure: ESkZY5bzNWua0eHc9rBkuE7AZrCNzLeCV1Rtn97h9KIBeuxsiB3heDUAOi3xZkqO4AyKD5AitAM2k7dTdQKvC8WMooHFWFdjlsSepUvjJISy8keY9kiXywUJ1S/YCwMPwT+HAWB4Qk2zyKmlLmZ8IfAK5aBtndXFQFQCqyeW4PE= + - secure: NlXxYbeVV7mWDTUgeFK0VrUdXGBF4lPVpMLZ3WXYDTUWfFyM8tiChENo/u/9n7tSz6KIxdWpy0j7h8+EjVUVCGxS+4q+kdzkfm1Vwq3ANhMsGBDcwdm7gYWhdd43aXV9ZaZPVUWv5C3yizzmYXeuNtviFDA5DEvrE5Rdp6sBsRE= + on_success: change + on_failure: always + on_pull_requests: false + +before_install: + # Update Docker and Docker Compose + - ./bin/.travis/trusty/update_docker.sh + # Internal auth token dedicated to testing with travis+composer on ezsystems repos, not for reuse! + - echo "{\"github-oauth\":{\"github.com\":\"d0285ed5c8644f30547572ead2ed897431c1fc09\"}}" > auth.json + # Disable XDebug for performance + - phpenv config-rm xdebug.ini + # Get latest composer build + - travis_retry composer selfupdate + # Avoid memory issues on composer install + - echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + +install: + # Setup eZ Platform inside docker container + - /bin/bash ./bin/.travis/trusty/setup_ezplatform.sh "${COMPOSE_FILE}" + +before_script: + # Execute Symfony command if injected into test matrix + - if [ "${SYMFONY_CMD}" != "" ] ; then docker-compose exec --user www-data app sh -c "bin/console ${SYMFONY_CMD}" ; fi + - if [ "${SETUP_BEHAT_OPTS}" != "" ] ; then cd "$HOME/build/ezplatform"; docker-compose exec --user www-data app sh -c "bin/ezbehat $SETUP_BEHAT_OPTS" ; fi + #- docker ps + #- docker-compose logs + +# Execute test command, need to use sh to get right exit code (docker/compose/issues/3379) +# Behat will use behat.yml which is a copy of behat.yml.dist with hostnames update by doc/docker/selenium.yml +script: + - if [ "${TEST_CMD}" != "" ] ; then cd "$HOME/build/ezplatform"; docker-compose exec --user www-data app sh -c "$TEST_CMD" ; fi + - if [ "${BEHAT_OPTS}" != "" ] ; then cd "$HOME/build/ezplatform"; docker-compose exec --user www-data app sh -c "bin/ezbehat $BEHAT_OPTS" ; fi + + +after_failure: + # Will show us the last bit of the log of container's main processes + # (not counting shell process above running php and behat) + # NOTE: errors during docker setup of travis build won't show up here (can't output all as it is too much in debug/verbose mode) + - docker-compose logs -t --tail=15 + # Will show us what is up, and how long it's been up + - docker ps -s + +after_script: + - if [ "${BEHAT_OPTS}" != "" ] ; then bin/ezreport ; fi diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..d79498d --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,16 @@ +COPYRIGHT NOTICE: Copyright (C) 1999-2017 eZ Systems AS +SOFTWARE LICENSE: GNU General Public License v2.0 +NOTICE: > + This program is free software; you can redistribute it and/or + modify it under the terms of version 2.0 of the GNU General + Public License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of version 2.0 of the GNU General + Public License along with this program; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7c94fca --- /dev/null +++ b/LICENSE @@ -0,0 +1,343 @@ +Copyright (C) 1999-2017 eZ Systems AS. All rights reserved. +This source code is provided under the following license: + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3a5babd --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ +# Netgen Media Site + +Netgen Media Site is a blueprint installation of eZ Platform used by Netgen to bootstrap new client projects. +It integrates most of Netgen open source tools and bundles, including [Netgen Layouts](https://github.com/netgen-layouts). + +* [Installation instructions](/doc/netgen/INSTALL.md) +* [Installation with Docker and eZ Launchpad](/doc/netgen/LAUNCHPAD.md) +* [Frontend setup](/doc/netgen/FRONTEND.md) + +# eZ Platform + +[![Build Status](https://img.shields.io/travis/ezsystems/ezplatform.svg?style=flat-square)](https://travis-ci.org/ezsystems/ezplatform) +[![Downloads](https://img.shields.io/packagist/dt/ezsystems/ezplatform.svg?style=flat-square)](https://packagist.org/packages/ezsystems/ezplatform) +[![Latest release](https://img.shields.io/github/release/ezsystems/ezplatform.svg?style=flat-square)](https://github.com/ezsystems/ezplatform/releases) +[![License](https://img.shields.io/packagist/l/ezsystems/ezplatform.svg?style=flat-square)](LICENSE) + +## What is eZ Platform? +*eZ Platform* is a fully open source professional CMS (Content Management System) developed by eZ Systems and the eZ Community. + +Current *eZ Platform v2* is the 7th generation of *eZ Publish*, it is built on top of the Symfony 3.4LTS framework (Full Stack). +It has been in development since 2011, and integral part of the *eZ Publish Platform 5.x* as "Platform stack" since 2012. + +#### Abstract: + +- **Very extensible** — You can extend the application and the content model in many ways. +- **Future and backwards compatible** — Strong backward compatibility policy on data as well as code. +- **Multi-channel by design** — Strong focus on separation between semantic content and design. +- **Scalable** — Easily scale across multiple servers out of the box. +- **Future proof** — Uses architecture designed to allow even more content scalability and performance in the future. +- **Stable** — Built on experience in building CMS that has been gathered since early 2000. +- **Integration friendly** — Numerous events and signals to hook into for advanced needs. + +#### Further information: + +eZ Platform is fully open source and it is the foundation for the commercial *eZ Platform Enterprise Edition* software, which adds advanced features for editorial teams, entirely built on top of *eZ Platform* APIs. + +- eZ Platform Developer Hub: [ezplatform.com](https://ezplatform.com/) +- [eZ Platform Open Source and Enterprise Edition roadmap](http://doc.ez.no/roadmap) +- eZ Systems (commercial products and services): [ez.no](https://ez.no/) + + +## Installation + +**Note:** For simplified installation, consider using community-supported [eZ Launchpad](https://ezsystems.github.io/launchpad/) which takes care of the whole server setup for you. + +Installation instructions below are for installing a clean installation of eZ Platform in latest version with _no_ demo content or demo website. +Full installation documentation is [in the online docs](https://doc.ezplatform.com/en/latest/getting_started/install_using_composer/). +It includes instructions on installing other distributions _(like [ezplatform-demo](https://github.com/ezsystems/ezplatform-demo) and [ezplatform-ee](https://github.com/ezsystems/ezplatform-ee) enterprise edition)_, or other versions. + +#### Prerequisites + +These instructions assume you have already installed: + +- PHP _(7.1 or higher)_ +- Web Server _(Recommeneded: Apache / Nginx. Use of PHP's built-in development server is also possible)_ +- Database server _(MySQL 5.5+ or MariaDB 10.0+)_ +- [Composer](https://doc.ezplatform.com/en/latest/getting_started/about_composer/) +- Git _(for development)_ + +For more details on requirements, see [online documentation](https://doc.ezplatform.com/en/latest/getting_started/requirements_and_system_configuration/). + + +#### Install eZ Platform _(clean distribution)_ + +Assuming you have prerequisites sorted out, you can get the install up and running with the following commands in your terminal: + +``` bash +composer create-project --keep-vcs ezsystems/ezplatform ezplatform ^2 +cd ezplatform +``` + +**Note:** If composer is installed locally instead of globally, the first command will start with `php composer.phar`. + +During the installation process you will be asked to provide database host name, login, password, etc. +The configuration details will be placed in `/app/config/parameters.yml`. + +Next you will receive instructions on how to install data into the database, and how to run a simplified dev server using the `bin/console server:run` command. + +**Tip:** For a more complete and better performing setup using Apache or Nginx, see how to [install eZ Platform manually](https://doc.ezplatform.com/en/latest/getting_started/install_manually/). + +## Issue tracker +Submitting bugs, improvements and stories is possible on [https://jira.ez.no/browse/EZP](https://jira.ez.no/browse/EZP). +If you discover a security issue, please see how to responsibly report such issues in ["Reporting security issues in eZ Systems products"](https://doc.ezplatform.com/en/latest/guide/reporting_issues/#reporting-security-issues-in-ez-systems-products). + +## Backwards compatibility +eZ Platform aims to be **fully content compatible** with eZ Publish 5.x, meaning that the content in these versions of the CMS can be upgraded using +[online documentation](https://doc.ezplatform.com/en/latest/migrating/migrating_from_ez_publish_platform/) to eZ Platform. + +Unlike eZ Publish Platform 5.x, eZ Platform does not ship with eZ Publish Legacy (4.x). But this is available by optional installing [LegacyBridge](https://github.com/ezsystems/LegacyBridge/releases/) to allow eZ Platform and eZ Publish Legacy to run together, this is only recommended for migration use cases and not for new installations. + +## COPYRIGHT +Copyright (C) 1999-2020 eZ Systems AS. All rights reserved. + +## LICENSE +http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 diff --git a/RUNNING_BEHAT.md b/RUNNING_BEHAT.md new file mode 100644 index 0000000..cdfadaf --- /dev/null +++ b/RUNNING_BEHAT.md @@ -0,0 +1,51 @@ +# Running the behat features + +*Note: If you want there is a way to run Behat using Docker setup, where you won't have to install any software other +then Docker. See `doc/docker/README.md` for further info.* + +## Install selenium server +Download the last version of the selenium server on the [download page](http://www.seleniumhq.org/download/). + +*Note: The selenium server must match the version of the browser you are using. Assuming you are using +a recent version of your browser, you should keep the selenium version up to date.* + +Once downloaded, run the server: `java -jar selenium-server-standalone-2.48.2.jar` + +## Create a dedicated vhost +Create a dedicated virtual host on your web server and set the environment to `behat`. + +Once this is done, make sur this virtual hosts works in your browser. + +## Customize the configuration +Behat needs to run HTTP calls on the project. By default, it uses http://localhost. + +You can either create a configuration file, or use environment variables: + +``` +cp behat.yml.dist behat.yml +``` +Edit the file and update the `base_url` and selenium's `wd_host` (if needed) + +Or customize the settings using the BEHAT_PARAMS environment variable: +``` +export BEHAT_PARAMS='{"extensions" : {"Behat\\MinkExtension" : {"base_url" : "https://www.example.com/"}}}' +``` + +See http://docs.behat.org/en/v3.0/guides/6.profiles.html#environment-variable-behat-params. + +## Run the features + +``` +./bin/behat +``` + +### Tags +Features tagged with `common` are executed on every pull request. Other, such as `edge`, are only executed on occasions. + +Add ` --tags='common'` to the behat command line to restrict execution to features tagged as "common". + +### Running all of the PlatformUI features +`./bin/behat --profile=platformui` + +### Running a specific feature +`./bin/behat --profile=platformui ~/ezplatform/vendor/ezsystems/platform-ui-bundle/Features/Users/users.feature` diff --git a/UPGRADE.md b/UPGRADE.md new file mode 100644 index 0000000..7437aea --- /dev/null +++ b/UPGRADE.md @@ -0,0 +1,13 @@ +# Upgrade instructions + +Please visit our online documentation for instructions: +https://doc.ezplatform.com/en/latest/releases/updating_ez_platform/ + +For legacy upgrade procedures, please go to our legacy documentation: +* Go to https://doc.ez.no/display/MAIN +* Click on the version you have +* Go to "Installation and Upgrade Guides" +* Select "Upgrade" + +For instance for 5.2 upgrade go to: +https://doc.ez.no/display/EZP52/Upgrade diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..fb1de45 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,7 @@ + + Require all denied + + + Order deny,allow + Deny from all + diff --git a/app/AppCache.php b/app/AppCache.php new file mode 100644 index 0000000..0957357 --- /dev/null +++ b/app/AppCache.php @@ -0,0 +1,12 @@ +getEnvironment() === 'prod') { + $bundles[] = new Sentry\SentryBundle\SentryBundle(); + } + + switch ($this->getEnvironment()) { + case 'test': + case 'behat': + $bundles[] = new EzSystems\BehatBundle\EzSystemsBehatBundle(); + $bundles[] = new EzSystems\PlatformBehatBundle\EzPlatformBehatBundle(); + // no break, test also needs dev bundles + case 'dev': + $bundles[] = new eZ\Bundle\EzPublishDebugBundle\EzPublishDebugBundle(); + $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); + $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); + $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); + $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); + $bundles[] = new Overblog\GraphiQLBundle\OverblogGraphiQLBundle(); + $bundles[] = new Snc\RedisBundle\SncRedisBundle(); + $bundles[] = new Netgen\Bundle\LayoutsDebugBundle\NetgenLayoutsDebugBundle(); + } + + $bundles[] = new Netgen\Bundle\EzFormsBundle\NetgenEzFormsBundle(); + $bundles[] = new Netgen\Bundle\OpenGraphBundle\NetgenOpenGraphBundle(); + $bundles[] = new Netgen\Bundle\MetadataBundle\NetgenMetadataBundle(); + $bundles[] = new Netgen\Bundle\ContentTypeListBundle\NetgenContentTypeListBundle(); + $bundles[] = new Netgen\Bundle\BirthdayBundle\NetgenBirthdayBundle(); + $bundles[] = new Netgen\TagsBundle\NetgenTagsBundle(); + $bundles[] = new Netgen\Bundle\EnhancedSelectionBundle\NetgenEnhancedSelectionBundle(); + $bundles[] = new Netgen\Bundle\SiteAccessRoutesBundle\NetgenSiteAccessRoutesBundle(); + $bundles[] = new Netgen\Bundle\SiteGeneratorBundle\NetgenSiteGeneratorBundle(); + $bundles[] = new Netgen\Bundle\SiteInstallerBundle\NetgenSiteInstallerBundle(); + $bundles[] = new Netgen\Bundle\SiteBundle\NetgenSiteBundle(); + $bundles[] = new Netgen\Bundle\RichTextDataTypeBundle\NetgenRichTextDataTypeBundle(); + $bundles[] = new Netgen\Bundle\EzPlatformSiteApiBundle\NetgenEzPlatformSiteApiBundle(); + $bundles[] = new Netgen\Bundle\AdminUIBundle\NetgenAdminUIBundle(); + $bundles[] = new Netgen\Bundle\SiteLegacyBundle\NetgenSiteLegacyBundle(); + $bundles[] = new Netgen\Bundle\InformationCollectionBundle\NetgenInformationCollectionBundle(); + $bundles[] = new Netgen\Bundle\EzPlatformSearchExtraBundle\NetgenEzPlatformSearchExtraBundle(); + + $bundles[] = new Netgen\Bundle\ContentBrowserBundle\NetgenContentBrowserBundle(); + $bundles[] = new Netgen\Bundle\ContentBrowserEzPlatformBundle\NetgenContentBrowserEzPlatformBundle(); + $bundles[] = new Netgen\Bundle\ContentBrowserUIBundle\NetgenContentBrowserUIBundle(); + $bundles[] = new Netgen\Bundle\LayoutsBundle\NetgenLayoutsBundle(); + $bundles[] = new Netgen\Bundle\LayoutsStandardBundle\NetgenLayoutsStandardBundle(); + $bundles[] = new Netgen\Bundle\LayoutsUIBundle\NetgenLayoutsUIBundle(); + $bundles[] = new Netgen\Bundle\LayoutsAdminBundle\NetgenLayoutsAdminBundle(); + $bundles[] = new Netgen\Bundle\LayoutsEzPlatformRelationListQueryBundle\NetgenLayoutsEzPlatformRelationListQueryBundle(); + $bundles[] = new Netgen\Bundle\LayoutsEzPlatformTagsQueryBundle\NetgenLayoutsEzPlatformTagsQueryBundle(); + $bundles[] = new Netgen\Bundle\LayoutsEzPlatformBundle\NetgenLayoutsEzPlatformBundle(); + $bundles[] = new Netgen\Bundle\LayoutsEzPlatformSiteApiBundle\NetgenLayoutsEzPlatformSiteApiBundle(); + + $bundles[] = new AppBundle\AppBundle(); + + return $bundles; + } + + public function getRootDir(): string + { + return __DIR__; + } + + public function getCacheDir(): string + { + if (!empty($_SERVER['SYMFONY_TMP_DIR'])) { + return rtrim($_SERVER['SYMFONY_TMP_DIR'], '/') . '/var/cache/' . $this->getEnvironment(); + } + + return dirname(__DIR__) . '/var/cache/' . $this->getEnvironment(); + } + + public function getLogDir(): string + { + if (!empty($_SERVER['SYMFONY_TMP_DIR'])) { + return rtrim($_SERVER['SYMFONY_TMP_DIR'], '/') . '/var/logs'; + } + + return dirname(__DIR__) . '/var/logs'; + } + + public function registerContainerConfiguration(LoaderInterface $loader): void + { + $loader->load($this->getRootDir() . '/config/' . $this->getEnvironment() . '/config.yml'); + + // We save the loader to a variable in order + // not to recreate it later in buildContainer + $this->containerLoader = $loader; + } + + protected function buildContainer(): ContainerBuilder + { + $container = parent::buildContainer(); + + $serverEnvironment = $container->getParameter('server_environment'); + $this->containerLoader->load($this->getRootDir() . '/config/server/' . $serverEnvironment . '.yml'); + + if ($this->getEnvironment() === 'dev' && $container->getParameter('profiler_storage') === 'redis') { + $this->containerLoader->load($this->getRootDir() . '/config/dev/profiler_storage/redis.yml'); + } + + return $container; + } +} diff --git a/app/Resources/TwigBundle/views/Exception/error.html.twig b/app/Resources/TwigBundle/views/Exception/error.html.twig new file mode 100644 index 0000000..62f2744 --- /dev/null +++ b/app/Resources/TwigBundle/views/Exception/error.html.twig @@ -0,0 +1,4 @@ +{% include ezpublish.configResolver.hasParameter('template.errors.' ~ status_code, 'ngsite') ? + ezpublish.configResolver.getParameter('template.errors.' ~ status_code, 'ngsite') : + ezpublish.configResolver.getParameter('template.errors.default', 'ngsite') +ignore missing %} diff --git a/app/config/behat/config.yml b/app/config/behat/config.yml new file mode 100644 index 0000000..2e52040 --- /dev/null +++ b/app/config/behat/config.yml @@ -0,0 +1,23 @@ +imports: + - { resource: ../dev/config.yml } + - { resource: ezplatform.yml } + +framework: + router: + resource: "%kernel.root_dir%/config/behat/routing.yml" + profiler: + collect: false + +web_profiler: + toolbar: false + intercept_redirects: false + +swiftmailer: + disable_delivery: true + +monolog: + handlers: + travis: + type: stream + path: "%kernel.logs_dir%/travis_test.log" + level: error diff --git a/app/config/behat/ezplatform.yml b/app/config/behat/ezplatform.yml new file mode 100644 index 0000000..c2e5d67 --- /dev/null +++ b/app/config/behat/ezplatform.yml @@ -0,0 +1,22 @@ +imports: + - { resource: ../ezplatform.yml } + +ezpublish: + siteaccess: + list: ["site", "other_site"] + groups: + site_group: ["site", "other_site"] + default_siteaccess: "site" + match: + URIElement: 1 + +ezdesign: + phpstorm: + enabled: false + +ez_platform_standard_design: + # for pre eZ Design Engine tests use old template naming + override_kernel_templates: false + +parameters: + ezsettings.default.notifications.success.timeout: 20000 diff --git a/app/config/behat/routing.yml b/app/config/behat/routing.yml new file mode 100644 index 0000000..86b75a4 --- /dev/null +++ b/app/config/behat/routing.yml @@ -0,0 +1,5 @@ +_main: + resource: ../dev/routing.yml + +_ezplatform_behat: + resource: '@EzPlatformBehatBundle/Resources/config/routing.yml' diff --git a/app/config/cache_pool/cache.memcached.yml b/app/config/cache_pool/cache.memcached.yml new file mode 100644 index 0000000..b0439a4 --- /dev/null +++ b/app/config/cache_pool/cache.memcached.yml @@ -0,0 +1,20 @@ +# Reusable service for memcache cache for use in generic.php and plaformsh.php on demand +# +# For further reading on setup with eZ Platform and Memcached: +# https://doc.ezplatform.com/en/latest/guide/persistence_cache/#memcached +services: + cache.memcached: + parent: cache.adapter.memcached + tags: + - name: cache.pool + clearer: cache.app_clearer + # Example from vendor/symfony/symfony/src/Symfony/Component/Cache/Traits/MemcachedTrait.php: + # memcached://user:pass@localhost?weight=33' + provider: 'memcached://%cache_dsn%' + # Cache namespace prefix overriding the one used by Symfony globally + # This makes sure cache is reliably shared across whole cluster and all Symfony env's + # Can be used for blue/green deployment strategies when changes affect content cache. + # For multi db setup adapt this to be unique per pool (one pool per database) + # If you prefer default behaviour set this to null or comment out, and consider for instance: + # https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed + namespace: '%cache_namespace%' diff --git a/app/config/cache_pool/cache.redis.yml b/app/config/cache_pool/cache.redis.yml new file mode 100644 index 0000000..138de0d --- /dev/null +++ b/app/config/cache_pool/cache.redis.yml @@ -0,0 +1,27 @@ +# Optimized Redis cache adapter (from: https://github.com/ezsystems/symfony-tools) +# +# On platform.sh this is setup automatically in env/plaformsh.php. +# For any other kind of use it can be enabled with CACHE_POOL, detected by env/generic.php. +# +# For further reading on setup with eZ Platform and Redis: +# https://doc.ezplatform.com/en/latest/guide/persistence_cache/#redis +services: + cache.redis: + class: Symfony\Component\Cache\Adapter\RedisTagAwareAdapter + parent: cache.adapter.redis + tags: + - name: cache.pool + clearer: cache.app_clearer + # Examples from vendor/symfony/symfony/src/Symfony/Component/Cache/Traits/RedisTrait.php: + # redis://localhost:6379 + # redis://secret@example.com:1234/13 + # redis://secret@/var/run/redis.sock/13?persistent_id=4&class=Redis&timeout=3&retry_interval=3 + # Example using Predis: redis://%cache_dsn%?class=\Predis\Client + provider: 'redis://%cache_dsn%' + # Cache namespace prefix overriding the one used by Symfony by default + # This makes sure cache is reliably shared across whole cluster and all Symfony env's + # Can be used for blue/green deployment strategies when changes affect content cache. + # For multi db setup adapt this to be unique per pool (one pool per database) + # If you prefer default behaviour set this to null or comment out, and consider for instance: + # https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed + namespace: '%cache_namespace%' diff --git a/app/config/cache_pool/cache.tagaware.filesystem.yml b/app/config/cache_pool/cache.tagaware.filesystem.yml new file mode 100644 index 0000000..81837b7 --- /dev/null +++ b/app/config/cache_pool/cache.tagaware.filesystem.yml @@ -0,0 +1,18 @@ +# Optimized File cache adapter (from: https://github.com/ezsystems/symfony-tools) +# +# Loaded by default, for use on single server setups. +# If you are on Windows you would have to use `cache.app` by setting `env(CACHE_POOL): "cache.app"` parameter +services: + cache.tagaware.filesystem: + class: Symfony\Component\Cache\Adapter\FilesystemTagAwareAdapter + parent: cache.adapter.filesystem + tags: + - name: cache.pool + clearer: cache.app_clearer + # Cache namespace prefix overriding the one used by Symfony by default + # This makes sure cache is reliably shared across whole cluster and all Symfony env's + # Can be used for blue/green deployment strategies when changes affect content cache. + # For multi db setup adapt this to be unique per pool (one pool per database) + # If you prefer default behaviour set this to null or comment out, and consider for instance: + # https://symfony.com/doc/current/reference/configuration/framework.html#prefix-seed + namespace: '%cache_namespace%' diff --git a/app/config/config.yml b/app/config/config.yml new file mode 100644 index 0000000..d89a39a --- /dev/null +++ b/app/config/config.yml @@ -0,0 +1,192 @@ +imports: + - { resource: default_parameters.yml } + - { resource: parameters.yml } + - { resource: security.yml } + - { resource: cache_pool/cache.tagaware.filesystem.yml } + - { resource: env/generic.php } + - { resource: env/platformsh.php } + - { resource: services.yml } + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration +parameters: + locale: en + # Identifier used to generate the CSRF token. Commenting this line will result in authentication + # issues both in AdminUI and REST calls + ezpublish_rest.csrf_token_intention: authenticate + +# Switches Netgen Layouts and Netgen Content Browser to use filter search service adapter from Site API +netgen_layouts_ez_platform_site_api: + search_service_adapter: filter + +# Configuration for Database connection, can have several connections used by eZ Repositories in ezplatform.yml +doctrine: + dbal: + connections: + default: + driver: '%database_driver%' + host: '%database_host%' + port: '%database_port%' + dbname: '%database_name%' + user: '%database_user%' + password: '%database_password%' + charset: '%database_charset%' + # Needs to be set to avoid Doctrine opening connection to database to get version info during situation where + # database is not ready yet. See: https://symfony.com/doc/current/reference/configuration/doctrine.html + server_version: '%database_version%' + orm: + auto_generate_proxy_classes: '%kernel.debug%' + naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware + auto_mapping: true + +# If you are not using MySQL, you can comment-out this section +ez_doctrine_schema: + tables: + options: + charset: '%database_charset%' + collate: '%database_collation%' + +# Base configuration for Solr, for more options see: https://doc.ezplatform.com/en/latest/guide/search/#solr-bundle +# Can have several connections used by each eZ Repositories in ezplatform.yml +ez_search_engine_solr: + endpoints: + endpoint0: + dsn: '%solr_dsn%' + core: '%solr_core%' + connections: + default: + entry_endpoints: + - endpoint0 + mapping: + default: endpoint0 + +framework: + esi: ~ + translator: { fallback: '%locale_fallback%' } + secret: '%secret%' + router: + resource: '%kernel.project_dir%/app/config/routing.yml' + strict_requirements: ~ + csrf_protection: ~ + form: ~ + validation: { enable_annotations: true } + #serializer: { enable_annotations: true } + # Place "eztpl" engine first intentionally if you setup use with legacy bridge. + # This is to avoid template name parsing with Twig engine, refusing specific characters + # which are valid with legacy tpl files. + templating: + engines: ['eztpl', 'twig'] + #assets_version: SomeVersionScheme + default_locale: '%locale_fallback%' + trusted_hosts: ~ + session: + # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id + # if handler_id set to null will use default session handler from php.ini + handler_id: '%ezplatform.session.handler_id%' + save_path: '%ezplatform.session.save_path%' + # Note: eZ Platform also allows session name and session cookie configuration to be per SiteAccess, by + # default session name will be set to "eZSESSID{siteaccess_hash}" (unique session name per siteaccess) + # Further reading on sessions: http://doc.ezplatform.com/en/latest/guide/sessions/ + cookie_httponly: true + fragments: ~ + http_method_override: true + assets: + packages: + app: + json_manifest_path: '%kernel.project_dir%/web/assets/app/build/manifest.json' + ezplatform: + json_manifest_path: '%kernel.project_dir%/web/assets/ezplatform/build/manifest.json' + php_errors: + log: true + +# Twig Configuration +twig: + debug: '%kernel.debug%' + strict_variables: '%kernel.debug%' + +# Webpack Encore Configuration +webpack_encore: + output_path: false + builds: + # The path where Encore is building the assets - i.e. Encore.setOutputPath() + app: '%kernel.project_dir%/web/assets/app/build' + ezplatform: '%kernel.project_dir%/web/assets/ezplatform/build' + +# Swiftmailer Configuration +swiftmailer: + transport: '%mailer_transport%' + host: '%mailer_host%' + port: '%mailer_port%' + username: '%mailer_user%' + password: '%mailer_password%' + spool: { type: memory } + +# FOSHttpCache Configuration +fos_http_cache: + cache_control: + rules: + # Make sure already cacheable (fresh) responses from eZ Platform which are errors/redirect gets lower ttl (then default_ttl) + - + match: + attributes: + _route: "^(?!nglayouts_app_api_|ngcb_api_)" + match_response: "response.isFresh() && ( response.isServerError() || response.isClientError() || response.isRedirect() )" + headers: + overwrite: true + cache_control: + max_age: 5 + s_maxage: 20 + # Example of performance tuning, force TTL on 404 pages to avoid crawlers / ... taking to much load + # Should not be set to high, as cached 404's can cause issues for future routes, url aliases, wildcards, .. + - + match: + attributes: + _route: "^(?!nglayouts_app_api_|ngcb_api_)" + match_response: "!response.isFresh() && response.isNotFound()" + headers: + overwrite: true + cache_control: + public: true + max_age: 0 + s_maxage: 20 + +jms_translation: + source_language: en + locales: [en] + dumper: + add_references: false + add_date: false + configs: + admin: + dirs: + - '%kernel.root_dir%/../vendor/ezsystems/ezplatform-admin-ui/src' + output_dir: '%kernel.root_dir%/../vendor/ezsystems/ezplatform-admin-ui/src/bundle/Resources/translations/' + excluded_dirs: [Behat, Tests, node_modules] + extractor: + - ez_policy + output_format: "xliff" + admin_modules: + dirs: + - '%kernel.root_dir%/../vendor/ezsystems/ezplatform-admin-ui-modules/src' + output_dir: '%kernel.root_dir%/../vendor/ezsystems/ezplatform-admin-ui-modules/Resources/translations/' + excluded_dirs: [Behat, Tests, node_modules] + output_format: "xliff" + +# Liip Imagine Configuration +liip_imagine: + # valid drivers options include "gd" or "gmagick" or "imagick" + driver: "%liip_imagine_driver%" + +# Sensio Framework Extra Configuration +sensio_framework_extra: + router: + annotations: false + +# Httplug configuration +httplug: + plugins: + logger: ~ + clients: + default: + factory: httplug.factory.curl + plugins: [httplug.plugin.logger] diff --git a/app/config/default_parameters.yml b/app/config/default_parameters.yml new file mode 100644 index 0000000..5e3760a --- /dev/null +++ b/app/config/default_parameters.yml @@ -0,0 +1,151 @@ +# This file contains defaults for optional parameters, which you can override in parameters.yml +parameters: + locale_fallback: en + + # A secret key that's used to generate certain security-related tokens + secret: '%env(SYMFONY_SECRET)%' + + # Settings for database backend used by Doctrine DBAL + # In turn used for default storage engine & default search engine (if legacy is configured as search engine) + database_driver: '%env(DATABASE_DRIVER)%' + database_host: '%env(DATABASE_HOST)%' + database_port: '%env(DATABASE_PORT)%' + database_name: '%env(DATABASE_NAME)%' + database_user: '%env(DATABASE_USER)%' + database_password: '%env(DATABASE_PASSWORD)%' + database_charset: '%env(DATABASE_CHARSET)%' + # collation currently has effect on MySQL only + database_collation: '%env(DATABASE_COLLATION)%' + # Needed by Doctrine Bundle / ORM to avoid it opening connection during situations where there is no service yet. + # See: https://symfony.com/doc/current/reference/configuration/doctrine.html + database_version: '%env(DATABASE_VERSION)%' + + # Setting for mail system, used by SwiftMailer + mailer_host: '%env(MAILER_HOST)%' + mailer_port: '%env(MAILER_PORT)%' + mailer_user: '%env(MAILER_USER)%' + mailer_password: '%env(MAILER_PASSWORD)%' + + collected_info_sender: '%env(COLLECTED_INFO_SENDER)%' + collected_info_recipient: '%env(COLLECTED_INFO_RECIPIENT)%' + + # One of `legacy` (default) or `solr` + search_engine: '%env(SEARCH_ENGINE)%' + + # Solr root endpoint, relevant if `solr` is set as search_engine + solr_dsn: '%env(SOLR_DSN)%' + solr_core: '%env(SOLR_CORE)%' + + # Sentry endpoint + sentry_dsn: '%env(SENTRY_DSN)%' + + # Log path, where to store the log files. php://stderr may be used in order to log to standard error + log_path: '%env(LOG_PATH)%' + + # Settings for Cache pool, to change add own cache service and optionally inject own arguments + # predefined pools: see symfony config and the optional pools in app/config/cache_pool/ + # Use "cache.app" for filesystem based cache pool. + cache_pool: '%env(CACHE_POOL)%' + + # Cache DSN, see app/config/services/cache.yml for examples: + cache_dsn: '%env(CACHE_DSN)%' + + # Cache namespace prefix for use with Redis/Memcached, 'ez' by default. + # For further info incl alternatives for "blue/green deployment" and multi repo installs, see: app/config/cache_pool/*.yml + cache_namespace: '%env(CACHE_NAMESPACE)%' + + # Settings for HttpCache + purge_server: '%env(HTTPCACHE_PURGE_SERVER)%' + + # By default cache ttl is set to 24h, when using Varnish you can set a much higher value. High values depends on + # using EzSystemsPlatformHttpCacheBundle (default as of v1.12) which by design expires affected cache on changes + httpcache_default_ttl: '%env(HTTPCACHE_DEFAULT_TTL)%' + + # Session save path as used by symfony session handlers (eg. used for dsn with redis) + ezplatform.session.save_path: '%env(SESSION_SAVE_PATH)%' + + # Recommendation Bundle params + ez_recommendation.default.yoochoose.customer_id: '%env(RECOMMENDATIONS_CUSTOMER_ID)%' + ez_recommendation.default.yoochoose.license_key: '%env(RECOMMENDATIONS_LICENSE_KEY)%' + ez_recommendation.default.server_uri: '%env(PUBLIC_SERVER_URI)%' + + # Fallback values for when environment variables do not exist + + env(MAILER_HOST): 127.0.0.1 + env(MAILER_PORT): ~ + env(MAILER_USER): ~ + env(MAILER_PASSWORD): ~ + + env(COLLECTED_INFO_SENDER): info@netgen.io + env(COLLECTED_INFO_RECIPIENT): test@netgen.io + + env(SEARCH_ENGINE): legacy + + env(SOLR_DSN): http://localhost:8983/solr + env(SOLR_CORE): collection1 + + env(SENTRY_DSN): ~ + + env(LOG_PATH): "%kernel.logs_dir%/%kernel.environment%.log" + + # NOTE: For Windows usage you can use Symfony's `cache.app`, for eZ provided services see: app/config/cache_pool/* + env(CACHE_POOL): "cache.tagaware.filesystem" + + env(CACHE_DSN): localhost + + env(CACHE_NAMESPACE): ez + + env(HTTPCACHE_PURGE_SERVER): "http://localhost:80" + + env(HTTPCACHE_DEFAULT_TTL): 86400 + + env(SESSION_SAVE_PATH): '%kernel.project_dir%/var/sessions/%kernel.environment%' + + env(RECOMMENDATIONS_CUSTOMER_ID): ~ + env(RECOMMENDATIONS_LICENSE_KEY): ~ + env(PUBLIC_SERVER_URI): ~ + + # set here for BC reasons, change them in parameters.yml + env(DATABASE_CHARSET): utf8mb4 + env(DATABASE_COLLATION): utf8mb4_unicode_520_ci + env(DATABASE_VERSION): mariadb-10.2.26 + + # Compile time handlers + ## These are defined at compile time, and hence can't be set at runtime using env() + ## app/config/env/generic.php takes care about letting you set them by env variables + + ## Log type is one of "stream", "error_log" or other types supported by monolog + # env: LOG_TYPE + log_type: stream + + ## Mail transport used by SwiftMailer + # env: MAILER_TRANSPORT + mailer_transport: smtp + + ## Purge type used by HttpCache system ("local", "varnish"/"http", and on ee also "fastly") + # env: HTTPCACHE_PURGE_TYPE + purge_type: local + + ## Session handler, by default set to file based (instead of ~) in order to be able to use %ezplatform.session.save_path% + # env: SESSION_HANDLER_ID + ezplatform.session.handler_id: session.handler.native_file + + # Admin siteaccess group name + admin_group_name: admin_group + + # Varnish invalidation/purge token (for use on platform.sh, eZ Platform Cloud and other places you can't use IP for ACL) + varnish_invalidate_token: '%env(HTTPCACHE_VARNISH_INVALIDATE_TOKEN)%' + env(HTTPCACHE_VARNISH_INVALIDATE_TOKEN): ~ + + # LiipImagineBundle - imagine driver + liip_imagine_driver: 'imagick' + + # Settings used to control the profiler storage in development + + ## Available options: local (for filesystem storage), redis + profiler_storage: local + ## Available options for redis: predis (uses predis/predis) and phpredis (uses redis PHP extension) + profiler_storage_driver: predis + profiler_storage_dsn: localhost + profiler_storage_namespace: app + profiler_storage_ttl: 120 diff --git a/app/config/dev/config.yml b/app/config/dev/config.yml new file mode 100644 index 0000000..1f9a9f2 --- /dev/null +++ b/app/config/dev/config.yml @@ -0,0 +1,67 @@ +imports: + - { resource: ../config.yml } + - { resource: ezplatform.yml } + +framework: + router: + resource: '%kernel.project_dir%/app/config/dev/routing.yml' + strict_requirements: true + profiler: + only_exceptions: false + # Optional: Skips generating profiles for subrequests by default due to dev performance + only_master_requests: true + assets: + packages: + app: + json_manifest_path: '%kernel.project_dir%/web/assets/app/build_dev/manifest.json' + +webpack_encore: + output_path: false + builds: + # The path where Encore is building the assets - i.e. Encore.setOutputPath() + app: '%kernel.project_dir%/web/assets/app/build_dev' + +snc_redis: + clients: + symfony_profiler: + type: '%profiler_storage_driver%' + alias: symfony_profiler + dsn: 'redis://%profiler_storage_dsn%' + options: + prefix: '%profiler_storage_namespace%' + +web_profiler: + toolbar: true + intercept_redirects: false + # By default disable showing of Admin UI "notifications/count" in web debug toolbar AJAX calls list to make it more manageable. + excluded_ajax_paths: '(^/(app(_[\\w]+)?\\.php/)?_wdt)|/notifications/count' + +monolog: + handlers: + main: + type: '%log_type%' + path: '%log_path%' + level: debug + channels: ['!event', '!doctrine'] + console: + type: console + process_psr_3_messages: false + channels: ['!event', '!doctrine', '!console'] + # To follow logs in real time, execute the following command: + # `bin/console server:log -vv` + server_log: + type: server_log + process_psr_3_messages: false + host: 127.0.0.1:9911 + + # uncomment to get logging in your browser + # you may have to allow bigger header sizes in your Web server configuration + #firephp: + # type: firephp + # level: info + #chromephp: + # type: chromephp + # level: info + +#swiftmailer: +# delivery_addresses: ['me@example.com'] diff --git a/app/config/dev/ezplatform.yml b/app/config/dev/ezplatform.yml new file mode 100644 index 0000000..a1031a4 --- /dev/null +++ b/app/config/dev/ezplatform.yml @@ -0,0 +1,2 @@ +imports: + - { resource: ../ezplatform.yml } diff --git a/app/config/dev/profiler_storage/redis.yml b/app/config/dev/profiler_storage/redis.yml new file mode 100644 index 0000000..eed532c --- /dev/null +++ b/app/config/dev/profiler_storage/redis.yml @@ -0,0 +1,4 @@ +snc_redis: + profiler_storage: + client: symfony_profiler + ttl: '%profiler_storage_ttl%' diff --git a/app/config/dev/routing.yml b/app/config/dev/routing.yml new file mode 100644 index 0000000..283c630 --- /dev/null +++ b/app/config/dev/routing.yml @@ -0,0 +1,17 @@ +_wdt: + resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' + prefix: /_wdt + +_profiler: + resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' + prefix: /_profiler + +_errors: + resource: '@TwigBundle/Resources/config/routing/errors.xml' + prefix: /_error + +_main: + resource: ../routing.yml + +overblog_graphql_graphiql: + resource: "@OverblogGraphiQLBundle/Resources/config/routing.xml" diff --git a/app/config/dfs/dfs.yml b/app/config/dfs/dfs.yml new file mode 100644 index 0000000..3908ac1 --- /dev/null +++ b/app/config/dfs/dfs.yml @@ -0,0 +1,38 @@ +# new doctrine connection for the dfs legacy_dfs_cluster metadata handler. +doctrine: + dbal: + connections: + dfs: + driver: "%dfs_database_driver%" + host: "%dfs_database_host%" + port: "%dfs_database_port%" + user: "%dfs_database_user%" + password: "%dfs_database_password%" + dbname: "%dfs_database_name%" + charset: utf8mb4 + +# define the flysystem handler +oneup_flysystem: + adapters: + nfs_adapter: + local: + directory: "/%dfs_nfs_path%/$var_dir$/$storage_dir$" + +# define the ez handlers +ez_io: + binarydata_handlers: + nfs: + flysystem: + adapter: nfs_adapter + metadata_handlers: + dfs: + legacy_dfs_cluster: + connection: doctrine.dbal.dfs_connection + +# set the application handlers +ezpublish: + system: + default: + io: + metadata_handler: dfs + binarydata_handler: nfs diff --git a/app/config/env/generic.php b/app/config/env/generic.php new file mode 100644 index 0000000..ee0a14c --- /dev/null +++ b/app/config/env/generic.php @@ -0,0 +1,77 @@ +setParameter('dfs_nfs_path', $dfsNfsPath); + + if ($value = getenv('DFS_DATABASE_DRIVER')) { + $container->setParameter('dfs_database_driver', $value); + } else { + $container->setParameter('dfs_database_driver', $container->getParameter('database_driver')); + } + + if ($value = getenv('DFS_DATABASE_HOST')) { + $container->setParameter('dfs_database_host', $value); + } else { + $container->setParameter('dfs_database_host', $container->getParameter('database_host')); + } + + if ($value = getenv('DFS_DATABASE_PORT')) { + $container->setParameter('dfs_database_port', $value); + } else { + $container->setParameter('dfs_database_port', $container->getParameter('database_port')); + } + + if ($value = getenv('DFS_DATABASE_NAME')) { + $container->setParameter('dfs_database_name', $value); + } else { + $container->setParameter('dfs_database_name', $container->getParameter('database_name')); + } + + if ($value = getenv('DFS_DATABASE_USER')) { + $container->setParameter('dfs_database_user', $value); + } else { + $container->setParameter('dfs_database_user', $container->getParameter('database_user')); + } + + if ($value = getenv('DFS_DATABASE_PASSWORD')) { + $container->setParameter('dfs_database_password', $value); + } else { + $container->setParameter('dfs_database_password', $container->getParameter('database_password')); + } + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../dfs')); + $loader->load('dfs.yml'); +} + +// Cache settings +// If CACHE_POOL env variable is set, check if there is a yml file that needs to be loaded for it +if (($pool = getenv('CACHE_POOL')) && file_exists(__DIR__ . "/../cache_pool/${pool}.yml")) { + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../cache_pool')); + $loader->load($pool . '.yml'); +} + +// Params that needs to be set at compile time and thus can't use Symfony's env() +if ($purgeType = getenv('HTTPCACHE_PURGE_TYPE')) { + $container->setParameter('purge_type', $purgeType); +} + +if ($value = getenv('MAILER_TRANSPORT')) { + $container->setParameter('mailer_transport', $value); +} + +if ($value = getenv('LOG_TYPE')) { + $container->setParameter('log_type', $value); +} + +if ($value = getenv('SESSION_HANDLER_ID')) { + $container->setParameter('ezplatform.session.handler_id', $value); +} + +if ($value = getenv('SESSION_SAVE_PATH')) { + $container->setParameter('ezplatform.session.save_path', $value); +} diff --git a/app/config/env/platformsh.php b/app/config/env/platformsh.php new file mode 100644 index 0000000..699dfef --- /dev/null +++ b/app/config/env/platformsh.php @@ -0,0 +1,170 @@ +setParameter('ezdesign.phpstorm.enabled', false); +} + +// Will not be executed on build step +$relationships = getenv('PLATFORM_RELATIONSHIPS'); +if (!$relationships) { + return; +} +$routes = getenv('PLATFORM_ROUTES'); + +$relationships = json_decode(base64_decode($relationships), true); +$routes = json_decode(base64_decode($routes), true); + +foreach ($relationships['database'] as $endpoint) { + if (empty($endpoint['query']['is_master'])) { + continue; + } + + $container->setParameter('database_driver', 'pdo_' . $endpoint['scheme']); + $container->setParameter('database_host', $endpoint['host']); + $container->setParameter('database_port', $endpoint['port']); + $container->setParameter('database_name', $endpoint['path']); + $container->setParameter('database_user', $endpoint['username']); + $container->setParameter('database_password', $endpoint['password']); + + // 'cluster_database_name' is deprecated in eZ Platform 1.13.1/2.1 + // Cluster DB name is hardcoded. It will have no any effect if cluster is disabled + $container->setParameter('cluster_database_name', 'cluster'); +} + +// If mailer_host has default value, then set it to platform.sh' default instead +if ($container->getParameter('mailer_host') === '127.0.0.1') { + $container->setParameter('mailer_host', getenv('PLATFORM_SMTP_HOST')); +} + +// PLATFORMSH_DFS_NFS_PATH is different compared to DFS_NFS_PATH in the sense that it is relative to ezplatform dir +// DFS_NFS_PATH is an absolute path +if ($dfsNfsPath = getenv('PLATFORMSH_DFS_NFS_PATH')) { + $container->setParameter('dfs_nfs_path', sprintf('%s/%s', dirname($container->getParameter('kernel.root_dir')), $dfsNfsPath)); + + if (array_key_exists('dfs_database', $relationships)) { + foreach ($relationships['dfs_database'] as $endpoint) { + if (empty($endpoint['query']['is_master'])) { + continue; + } + + $container->setParameter('dfs_database_driver', 'pdo_' . $endpoint['scheme']); + $container->setParameter('dfs_database_host', $endpoint['host']); + $container->setParameter('dfs_database_port', $endpoint['port']); + $container->setParameter('dfs_database_name', $endpoint['path']); + $container->setParameter('dfs_database_user', $endpoint['username']); + $container->setParameter('dfs_database_password', $endpoint['password']); + } + } else { + // If dfs_database endpoint is not defined, we'll use the default database for DFS too + $container->setParameter('dfs_database_driver', $container->getParameter('database_driver')); + $container->setParameter('dfs_database_host', $container->getParameter('database_host')); + $container->setParameter('dfs_database_port', $container->getParameter('database_port')); + $container->setParameter('dfs_database_name', $container->getParameter('database_name')); + $container->setParameter('dfs_database_user', $container->getParameter('database_user')); + $container->setParameter('dfs_database_password', $container->getParameter('database_password')); + } + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../dfs')); + $loader->load('dfs.yml'); +} +// Use Redis-based caching if possible. +if (isset($relationships['rediscache'])) { + foreach ($relationships['rediscache'] as $endpoint) { + if ($endpoint['scheme'] !== 'redis') { + continue; + } + + $container->setParameter('cache_pool', 'cache.redis'); + $container->setParameter('cache_dsn', sprintf('%s:%d', $endpoint['host'], $endpoint['port']) . '?retry_interval=3'); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../cache_pool')); + $loader->load('cache.redis.yml'); + } +} elseif (isset($relationships['cache'])) { + // Fallback to memcached if here (deprecated, we will only handle redis here in the future) + foreach ($relationships['cache'] as $endpoint) { + if ($endpoint['scheme'] !== 'memcached') { + continue; + } + + @trigger_error('Usage of Memcached is deprecated, redis is recommended', E_USER_DEPRECATED); + + $container->setParameter('cache_pool', 'cache.memcached'); + $container->setParameter('cache_dsn', sprintf('%s:%d', $endpoint['host'], $endpoint['port'])); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../cache_pool')); + $loader->load('cache.memcached.yml'); + } +} + +// Use Redis-based sessions if possible. If a separate Redis instance +// is available, use that. If not, share a Redis instance with the +// Cache. (That should be safe to do except on especially high-traffic sites.) +if (isset($relationships['redissession'])) { + foreach ($relationships['redissession'] as $endpoint) { + if ($endpoint['scheme'] !== 'redis') { + continue; + } + + $container->setParameter('ezplatform.session.handler_id', 'ezplatform.core.session.handler.native_redis'); + $container->setParameter('ezplatform.session.save_path', sprintf('%s:%d', $endpoint['host'], $endpoint['port'])); + } +} elseif (isset($relationships['rediscache'])) { + foreach ($relationships['rediscache'] as $endpoint) { + if ($endpoint['scheme'] !== 'redis') { + continue; + } + + $container->setParameter('ezplatform.session.handler_id', 'ezplatform.core.session.handler.native_redis'); + $container->setParameter('ezplatform.session.save_path', sprintf('%s:%d', $endpoint['host'], $endpoint['port'])); + } +} + +if (isset($relationships['solr'])) { + foreach ($relationships['solr'] as $endpoint) { + if ($endpoint['scheme'] !== 'solr') { + continue; + } + + $container->setParameter('search_engine', 'solr'); + $container->setParameter('solr_dsn', sprintf('http://%s:%d/%s', $endpoint['host'], $endpoint['port'], 'solr')); + // To set solr_core parameter we assume path is in form like: "solr/collection1" + $container->setParameter('solr_core', substr($endpoint['path'], 5)); + } +} + +// We will pick a varnish route by the following prioritization: +// - The first route found that has upstream: varnish +// - if primary route has upstream: varnish, that route will be prioritised +// If no route is found with upstream: varnish, then purge_server will not be set +$route = null; +foreach ($routes as $host => $info) { + if ($route === null && $info['type'] === 'upstream' && $info['upstream'] === 'varnish') { + $route = $host; + } + if ($info['type'] === 'upstream' && $info['upstream'] === 'varnish' && $info['primary'] === true) { + $route = $host; + break; + } +} + +if ($route !== null && !getenv('HTTPCACHE_PURGE_TYPE')) { + $container->setParameter('purge_type', 'varnish'); + $container->setParameter('purge_server', rtrim($route, '/')); +} + +// Setting default value for HTTPCACHE_VARNISH_INVALIDATE_TOKEN if it is not explicitly set +if (!getenv('HTTPCACHE_VARNISH_INVALIDATE_TOKEN')) { + $container->setParameter('varnish_invalidate_token', getenv('PLATFORM_PROJECT_ENTROPY')); +} + +// Adapt config based on enabled PHP extensions +// Get imagine to use imagick if enabled, to avoid using php memory for image convertions +if (extension_loaded('imagick')) { + $container->setParameter('liip_imagine_driver', 'imagick'); +} diff --git a/app/config/ezplatform.yml b/app/config/ezplatform.yml new file mode 100644 index 0000000..437d426 --- /dev/null +++ b/app/config/ezplatform.yml @@ -0,0 +1,56 @@ +imports: + - { resource: 'ezplatform_siteaccess.yml' } + - { resource: '@NetgenAdminUIBundle/Resources/config/ezplatform.yml' } + - { resource: '@AppBundle/Resources/config/ezplatform.yml' } + +ezpublish: + http_cache: + purge_type: '%purge_type%' + + imagemagick: + enabled: true + path: '%imagemagick_path%' + + repositories: + default: + fields_groups: + list: [content, meta, extras] + storage: ~ + search: + engine: '%search_engine%' + connection: default + + # System settings, read in following order: `default`, , , and `global` + # TIP: For multisite installations organize shared config into SiteAccess groups, + # on single-site you can place shared config under "default" for simplicity as shown below. + system: + default: + repository: default + # Cache pool service, needs to be different per repository (database) on multi repository install. + cache_service_name: '%cache_pool%' + # These reflect the current installers, complete installation before you change them. For changing var_dir + # it is recommended to install clean, then change setting before you start adding binary content, otherwise you'll + # need to manually modify your database data to reflect this to avoid exceptions. + var_dir: var/site + content: + # As we by default enable EzSystemsPlatformHttpCacheBundle which is designed to expire all affected cache + # on changes, and as error / redirects now have separate ttl, we easier allow ttl to be greatly increased + default_ttl: '%httpcache_default_ttl%' + # HttpCache purge server(s) setting, eg Varnish, for when ezpublish.http_cache.purge_type is set to 'http'. + http_cache: + purge_servers: ['%purge_server%'] + varnish_invalidate_token: '%varnish_invalidate_token%' + admin_group: + content_tree_module: + contextual_tree_root_location_ids: + - 2 # Home (Content structure) + - 5 # Users + - 43 # Media + - 48 # Setup + subtree_paths: + content: /1/2/ + media: /1/43/ + + url_alias: + slug_converter: + transformation: 'urlalias_lowercase' diff --git a/app/config/ezplatform_siteaccess.yml b/app/config/ezplatform_siteaccess.yml new file mode 100644 index 0000000..7f6b026 --- /dev/null +++ b/app/config/ezplatform_siteaccess.yml @@ -0,0 +1,63 @@ +ezpublish: + siteaccess: + default_siteaccess: eng + list: + - eng + - ngadminui + - admin + - legacy_admin + groups: + frontend_group: + - eng + ngadmin_group: + - ngadminui + - legacy_admin + admin_group: + - admin + system: + frontend_group: + translation_siteaccesses: + - eng + eng: + design: app + languages: + - eng-GB + session: + name: eZSESSID + ngadminui: + design: ngadminui + languages: + - eng-GB + session: + name: eZSESSID + admin: + languages: + - eng-GB + session: + name: eZSESSID + legacy_admin: + languages: + - eng-GB +netgen_layouts: + design_list: + app: + - app + system: + frontend_group: + design: app +ezdesign: + design_list: + app: + - app + - common + admin: + - admin + - standard + - common + ngadminui: + - ngadminui + - common +ez_publish_legacy: + system: + legacy_admin: + legacy_mode: true diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist new file mode 100644 index 0000000..942afe6 --- /dev/null +++ b/app/config/parameters.yml.dist @@ -0,0 +1,32 @@ +# This file is a "template" of what your parameters.yml file should look like +# +# NB!: Some parameters are on purpose placed in default_parameters.yml to not +# prompt on all possible parameters during install with no info to go with it. +# (This will change once we move to use Symfony flex) +parameters: + # A secret key that's used to generate certain security-related tokens + env(SYMFONY_SECRET): ThisEzPlatformTokenIsNotSoSecret_PleaseChangeIt + + # Settings for database backend used by Doctrine DBAL + # In turn used for default storage engine & default search engine (if legacy is configured as search engine) + env(DATABASE_DRIVER): pdo_mysql + env(DATABASE_HOST): localhost + env(DATABASE_PORT): ~ + env(DATABASE_NAME): ezplatform + env(DATABASE_USER): root + env(DATABASE_PASSWORD): ~ + env(DATABASE_CHARSET): utf8mb4 + env(DATABASE_COLLATION): utf8mb4_unicode_520_ci + env(DATABASE_VERSION): mariadb-10.2.26 + + env(SEARCH_ENGINE): legacy + env(SOLR_DSN): http://localhost:8983/solr + env(SENTRY_DSN): ~ + env(HTTPCACHE_PURGE_SERVER): http://localhost:80 + + purge_type: local + server_environment: dev + imagemagick_path: /usr/bin/convert + + ngsite.default.site_domain: localhost + ngsite.default.locations.site_info.id: 65 diff --git a/app/config/prod/config.yml b/app/config/prod/config.yml new file mode 100644 index 0000000..9a32234 --- /dev/null +++ b/app/config/prod/config.yml @@ -0,0 +1,40 @@ +imports: + - { resource: ../config.yml } + - { resource: ezplatform.yml } + +# Example below would make sure some of the symfony caches are written to apc / redis instead of disk +# Make sure to verify if cache clearing is done as you expect when doing such changes. + +#framework: +# validation: +# cache: validator.mapping.cache.doctrine.apc +# serializer: +# cache: serializer.mapping.cache.apc +#doctrine: +# orm: +# metadata_cache_driver: apc +# query_cache_driver: apc +## Result (& the experimental Second level) cache needs to be shared among servers so should use for instance Redis +# result_cache_driver: +# type: redis +# host: +# port: + + +sentry: + dsn: '%sentry_dsn%' + +monolog: + handlers: + main: + type: fingers_crossed + # eZ Platform sets this to critical instead of error to avoid too verbose logs in prod + action_level: critical + handler: nested + nested: + type: '%log_type%' + path: '%log_path%' + level: debug + console: + type: console + process_psr_3_messages: false diff --git a/app/config/prod/ezplatform.yml b/app/config/prod/ezplatform.yml new file mode 100644 index 0000000..a1031a4 --- /dev/null +++ b/app/config/prod/ezplatform.yml @@ -0,0 +1,2 @@ +imports: + - { resource: ../ezplatform.yml } diff --git a/app/config/routing.yml b/app/config/routing.yml new file mode 100644 index 0000000..19ed2ba --- /dev/null +++ b/app/config/routing.yml @@ -0,0 +1,83 @@ +login: + path: /login + defaults: { _controller: ezpublish.security.controller:loginAction } + +login_check: + path: /login_check + +logout: + path: /logout + +kernel.internal: + resource: '@EzPublishCoreBundle/Resources/config/routing/internal.yml' + +kernel.rest: + resource: '@EzPublishRestBundle/Resources/config/routing.yml' + prefix: '%ezpublish_rest.path_prefix%' + +kernel.rest.options: + resource: '@EzPublishRestBundle/Resources/config/routing.yml' + prefix: '%ezpublish_rest.path_prefix%' + type: rest_options + +ezplatform.admin_ui: + resource: '@EzPlatformAdminUiBundle/Resources/config/routing.yml' + defaults: + siteaccess_group_whitelist: ['%admin_group_name%', 'ngadmin_group'] + +ezplatform.admin_ui.rest: + resource: '@EzPlatformAdminUiBundle/Resources/config/routing_rest.yml' + prefix: '%ezpublish_rest.path_prefix%' + +ezplatform.user: + resource: '@EzPlatformUserBundle/Resources/config/routing.yml' + +_ezplatformRepositoryFormsRoutes: + resource: '@EzSystemsRepositoryFormsBundle/Resources/config/routing.yml' + +fos.js_routing: + resource: '@FOSJsRoutingBundle/Resources/config/routing/routing.xml' + +ezplatform.httpcache: + resource: '@EzSystemsPlatformHttpCacheBundle/Resources/config/routing.yml' + +# +# GraphQL +# + +overblog_graphql: + resource: "@OverblogGraphQLBundle/Resources/config/routing/graphql.yml" + +overblog_graphql_endpoint: + path: /graphql + defaults: + _controller: Overblog\GraphQLBundle\Controller\GraphController::endpointAction + _format: json + +ezpublish_legacy: + resource: '@EzPublishLegacyBundle/Resources/config/routing.yml' + +netgen_tags: + resource: '@NetgenTagsBundle/Resources/config/routing.yml' + +netgen_information_collection: + resource: '@NetgenInformationCollectionBundle/Resources/config/routing.yml' + +netgen_layouts: + resource: '@NetgenLayoutsBundle/Resources/config/routing.yaml' + prefix: '%netgen_layouts.route_prefix%' + +netgen_content_browser: + resource: '@NetgenContentBrowserBundle/Resources/config/routing.yaml' + prefix: '%netgen_content_browser.route_prefix%' + +# Netgen Site routes follow. It is recommended to keep them at the end of file + +netgen_site: + resource: '@NetgenSiteBundle/Resources/config/routing.yml' + +netgen_admin_ui: + resource: '@NetgenAdminUIBundle/Resources/config/routing.yml' + +app: + resource: '@AppBundle/Resources/config/routing.yml' diff --git a/app/config/security.yml b/app/config/security.yml new file mode 100644 index 0000000..527ae80 --- /dev/null +++ b/app/config/security.yml @@ -0,0 +1,40 @@ +# To get started with security, check out the documentation: +# https://symfony.com/doc/current/security.html +security: + # https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded + providers: + ezpublish: + id: ezpublish.security.user_provider +#! in_memory: +#! memory: ~ + + firewalls: + # disables authentication for assets and the profiler, adapt it according to your needs + dev: + pattern: ^/(_(profiler|wdt)|css|images|js)/ + security: false + + ezpublish_forgot_password: + pattern: /user/(forgot-password|reset-password) + security: false + + ezpublish_front: + pattern: ^/ + anonymous: ~ + ezpublish_rest_session: ~ + form_login: + require_previous_session: false + csrf_token_generator: security.csrf.token_manager + logout_on_user_change: true + logout: ~ + + main: + anonymous: ~ + logout_on_user_change: true + # activate different ways to authenticate + + # https://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate + #http_basic: ~ + + # https://symfony.com/doc/current/security/form_login_setup.html + #form_login: ~ diff --git a/app/config/server/dev.yml b/app/config/server/dev.yml new file mode 100644 index 0000000..e6adab5 --- /dev/null +++ b/app/config/server/dev.yml @@ -0,0 +1,3 @@ +imports: + - + resource: dev/ezplatform_siteaccess.yml diff --git a/app/config/server/dev/ezplatform_siteaccess.yml b/app/config/server/dev/ezplatform_siteaccess.yml new file mode 100644 index 0000000..0eb0cf0 --- /dev/null +++ b/app/config/server/dev/ezplatform_siteaccess.yml @@ -0,0 +1,4 @@ +ezpublish: + siteaccess: + match: + URIElement: '1' diff --git a/app/config/services.yml b/app/config/services.yml new file mode 100644 index 0000000..63dc7a1 --- /dev/null +++ b/app/config/services.yml @@ -0,0 +1,15 @@ +# Learn more about services, parameters and containers at +# https://symfony.com/doc/current/service_container.html +parameters: + #parameter_name: value + +services: + # default configuration for services in *this* file + _defaults: + # automatically injects dependencies in your services + autowire: true + # automatically registers your services as commands, event subscribers, etc. + autoconfigure: true + # this means you cannot fetch services directly from the container via $container->get() + # if you need to do this, you can override this setting on individual services + public: false diff --git a/app/config/test/config.yml b/app/config/test/config.yml new file mode 100644 index 0000000..55e2038 --- /dev/null +++ b/app/config/test/config.yml @@ -0,0 +1,17 @@ +imports: + - { resource: ../dev/config.yml } + - { resource: ezplatform.yml } + +framework: + test: ~ + session: + storage_id: session.storage.mock_file + profiler: + collect: false + +web_profiler: + toolbar: false + intercept_redirects: false + +swiftmailer: + disable_delivery: true diff --git a/app/config/test/ezplatform.yml b/app/config/test/ezplatform.yml new file mode 100644 index 0000000..a1031a4 --- /dev/null +++ b/app/config/test/ezplatform.yml @@ -0,0 +1,2 @@ +imports: + - { resource: ../ezplatform.yml } diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..4e59d37 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,14 @@ +module.exports = function (api) { + api.cache(true); + + const presets = [ + ['@babel/preset-env', { + useBuiltIns: 'entry', + corejs: 3, + }], + ]; + + return { + presets, + }; +}; diff --git a/behat.yml.dist b/behat.yml.dist new file mode 100644 index 0000000..998b7ba --- /dev/null +++ b/behat.yml.dist @@ -0,0 +1,57 @@ +default: + calls: + error_reporting: -1 # Report all PHP errors + formatters: + pretty: true + allure: + output_path: %paths.base%/build/allure + extensions: + Behat\MinkExtension: + base_url: 'http://localhost' + goutte: ~ + javascript_session: selenium2 + selenium2: + browser: chrome + wd_host: 'http://localhost:4444/wd/hub' + capabilities: + extra_capabilities: + chromeOptions: + args: + - "--window-size=1440,1080" + - "--no-sandbox" + # problem with different iframe host - https://bugs.chromium.org/p/chromedriver/issues/detail?id=2758 + - "--disable-features=site-per-process" + + Behat\Symfony2Extension: + kernel: + bootstrap: vendor/autoload.php + path: app/AppKernel.php + class: AppKernel + env: behat + debug: true + + EzSystems\PlatformBehatBundle\ServiceContainer\EzBehatExtension: ~ + + Liuggio\Fastest\Behat\ListFeaturesExtension\Extension: ~ + + Bex\Behat\ScreenshotExtension: + active_image_drivers: cloudinary + image_drivers: + cloudinary: + screenshot_directory: /tmp/behat-screenshot/ + cloud_name: ezplatformtravis + preset: ezplatform + mode: normal + limit: 10 + + Allure\Behat\AllureFormatterExtension: + image_attachment_limit: 5 + + suites: ~ + +imports: + - vendor/ezsystems/ezpublish-kernel/eZ/Bundle/EzPublishCoreBundle/behat_suites.yml + - vendor/ezsystems/ezpublish-kernel/eZ/Bundle/EzPublishRestBundle/behat_suites.yml + - vendor/ezsystems/repository-forms/behat_suites.yml + - vendor/ezsystems/ezplatform-admin-ui/behat_suites.yml + - vendor/ezsystems/behatbundle/EzSystems/BehatBundle/behat_suites.yml diff --git a/bin/.ci/make_tag.sh b/bin/.ci/make_tag.sh new file mode 100755 index 0000000..f447623 --- /dev/null +++ b/bin/.ci/make_tag.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# Script used to make eZ Platform/Enterprise meta tags +# +# Only aims to: +# - prepare code for project use +# - check some things to validate if we are ready for making tag +# - make the tag +# +# Arguments: +# - tag: v3.4.2 +# - composer args: arguments to pass to composer update (optional) + +# Vendors we watch for stability (and potentially more). +PACKAGE_WATCH_REGEX='/^(doctrine|ezsystems|silversolutions|symfony)\//'; + +UNSTAGED_CHANGES=`git status | grep 'Changes not staged for commit'` +if (( ${#UNSTAGED_CHANGES} > 0 )); then + echo -e "\033[31m You have unstaged changes. Please commit or stash them. \033[0m" + exit +fi + +set -e + +TAG=$1 +if [[ $TAG =~ ^v[0-9]+(\.[0-9]+){2,3}(-[a-z]+[0-9]*)?$ ]]; then + echo -e "\033[36m Start work on making tag $TAG \033[0m" +else + echo -e "\033[31m Tag argument did not look correct, should be v1.2.33 or v2.3.4-beta1 \033[0m" + exit +fi +TMP_BRANCH="tmp_release_$TAG" + +shift +COMPOSER_ARGS="$@" + +CURRENT_BRANCH_LINE=`git branch | grep '*'` +#* 2.5|master +if [[ $CURRENT_BRANCH_LINE =~ ^\*[[:space:]]([^[:space:]]+)$ ]]; then + CURRENT_BRANCH=${BASH_REMATCH[1]} +#* (detached from v2.5.0) +elif [[ $CURRENT_BRANCH_LINE =~ ^\*[[:space:]]\(detached[[:space:]]from[[:space:]]([^[:space:]]+)\)$ ]]; then + CURRENT_BRANCH=${BASH_REMATCH[1]} +#* (HEAD detached at v2.5.0) +elif [[ $CURRENT_BRANCH_LINE =~ ^\*[[:space:]]\(HEAD[[:space:]]detached[[:space:]]at[[:space:]]([^[:space:]]+)\)$ ]]; then + CURRENT_BRANCH=${BASH_REMATCH[1]} +#* (no branch) +else + echo -e "\033[31m Can't detect current branch/tag. \033[0m" + exit +fi + +devPackageScanPhp=$(cat < \$version) { + if (preg_match('$PACKAGE_WATCH_REGEX', \$package) === 1 && is_int(strpos(\$version, "@dev"))) { + echo " \$package \$version\n"; + } +} +HEREDOC) + +devPackages=$(php -r "$devPackageScanPhp") +if (( ${#devPackages} > 0 )); then + echo -e "\033[31m There are unwanted dev packages in composer.json: \033[0m" + printf "$devPackages\n" + exit +fi + +# TODO: Add help text, display help on errors + +# After this we want to be able to cleanup things on exit (clean and error) +clean_up () { + ARG=$? + git reset -q --hard HEAD + git checkout -q $CURRENT_BRANCH + git branch -q -D $TMP_BRANCH + exit $ARG +} +trap clean_up EXIT + + + +# Let's start! + +git checkout -b $TMP_BRANCH + +echo -e "\033[36m Comment out *.lock files in .gitignore \033[0m" +perl -pi -e 's/^(.*)\.lock$/#$1.lock/g' .gitignore + +minimumPHP=$(php -r '$hash = json_decode(file_get_contents("composer.json"), true); $php = str_replace(["^", "~"], "", $hash["require"]["php"]); echo explode("|", $php)[0];') +echo -e "\033[36m Set minimum php version in composer.json (temporary to get vendor capable of working with it) to $minimumPHP \033[0m" +composer config platform.php "$minimumPHP" + +echo -e "\033[36m Update composer packages to generate lock files \033[0m" +php -d memory_limit=-1 `which composer` update --no-interaction --prefer-dist $COMPOSER_ARGS + +echo -e "\033[36m Revert composer.json minimum php version changes, and update composer lock file hash to avoid warning \033[0m" +git checkout composer.json +php -d memory_limit=-1 `which composer` update --lock --no-scripts --no-interaction --prefer-dist $COMPOSER_ARGS + +echo -e "\033[36m Add changes, commit and tag \033[0m" +git add -f *.lock .gitignore +git commit -m "Configure $TAG for release" +git tag -f $TAG + +echo -e "\033[36m \nReady to push the tag once you have checked it to be correct, once ready:\033[0m" +echo -e "\033[33m git push $TAG\n \033[0m" + +echo -e "\033[2m After this it's possible to: \033[0m" +echo -e "\033[2m - Make release notes: https://github.com/yannickroger/release-notes-generator \033[0m" +echo -e "\033[2m - Checkout tag and make archive for upload: ./bin/.ci/prepare_archive.sh \n \033[0m" diff --git a/bin/.ci/prepare_archive.sh b/bin/.ci/prepare_archive.sh new file mode 100755 index 0000000..fc4bf5b --- /dev/null +++ b/bin/.ci/prepare_archive.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Script used to prepare for eZ Platform/Enterprise archives +# +# Pre-requirement for LTS (EE) archives: +# auth.json needs to be placed in either root directory or COMPOSER_HOME. +# If auth.json is placed in COMPOSER_HOME, it needs to be for same user as the one executing script. + + +# Install all composer deps non-interactivly, skip scripts as they will be executed install +composer install --no-interaction --prefer-dist --no-dev --no-scripts --optimize-autoloader + +# Rename .gitignore to make it optional as it is optimized for kernel development and not project development +mv .gitignore .gitignore.dist + +# Archive: Remove cache (wrong paths), logs (generated by composer call above) & zeta tests (too big) +rm -Rf var/cache/*/* var/logs/* vendor/zetacomponents/*/tests + +# Remove .git folder from archives +rm -Rf .git/ + +echo << EOF +Ready to archive the result + +Assuming current folder is build/ezplatform this can be accomplished in the following way: + cd ../.. + tar czf dist/ezplatform-\$version-ee-gpl-full.tar.gz --directory=build ezplatform +EOF diff --git a/bin/.travis/apache2/php5-fcgi b/bin/.travis/apache2/php5-fcgi new file mode 100644 index 0000000..aa6e881 --- /dev/null +++ b/bin/.travis/apache2/php5-fcgi @@ -0,0 +1,12 @@ + + AddHandler php5-fcgi .php + Action php5-fcgi /php5-fcgi + Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi + FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -pass-header Authorization -idle-timeout 300 + + + Order deny,allow + Deny from all + Allow from env=REDIRECT_STATUS + + diff --git a/bin/.travis/composer-auth.json b/bin/.travis/composer-auth.json new file mode 100644 index 0000000..3416c4f --- /dev/null +++ b/bin/.travis/composer-auth.json @@ -0,0 +1,8 @@ +{ + "github-oauth": { + "github.com": "PLEASE DO NOT USE THIS TOKEN IN YOUR OWN PROJECTS/FORKS", + "github.com": "This token is reserved for testing with ezsystems repositories", + "github.com": "NB: You create your own token without(!) any scope to use same approach", + "github.com": "d0285ed5c8644f30547572ead2ed897431c1fc09" + } +} diff --git a/bin/.travis/configure_apache2.sh b/bin/.travis/configure_apache2.sh new file mode 100755 index 0000000..eb97c1a --- /dev/null +++ b/bin/.travis/configure_apache2.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# vhost & fastcgi setup +./bin/vhost.sh \ + --basedir=$TRAVIS_BUILD_DIR \ + --sf-env=behat \ + --sf-debug=1 \ + --template-file=doc/apache2/vhost.template \ + | sudo tee /etc/apache2/sites-available/behat > /dev/null + +sudo cp bin/.travis/apache2/php5-fcgi /etc/apache2/conf.d/php5-fcgi + +# modules enabling +sudo a2enmod rewrite actions fastcgi alias + +# sites disabling & enabling +sudo a2dissite default +sudo a2ensite behat + +# FPM +USER=$(whoami) + +sudo echo " +[global] + +[www] +user = $USER +group = $USER +listen = 127.0.0.1:9000 +pm = static +pm.max_children = 2 + +php_admin_value[memory_limit] = 256M +" > ~/.phpenv/versions/$(phpenv version-name)/etc/php-fpm.conf + +sudo echo 'date.timezone = "Europe/Oslo"' >> ~/.phpenv/versions/$TRAVIS_PHP_VERSION/etc/conf.d/travis.ini +sudo echo "cgi.fix_pathinfo = 1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini + +# restart +echo "> restart FPM" +sudo ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm +echo "> restart apache2" +sudo service apache2 restart diff --git a/bin/.travis/configure_mysql.sh b/bin/.travis/configure_mysql.sh new file mode 100755 index 0000000..86c1d13 --- /dev/null +++ b/bin/.travis/configure_mysql.sh @@ -0,0 +1,4 @@ +#! /bin/bash + +echo "> Create database and grant premissions to user 'ezp'" +mysql -uroot -e "CREATE DATABASE IF NOT EXISTS behattestdb CHARACTER SET utf8; GRANT ALL ON behattestdb.* TO ezp@localhost IDENTIFIED BY 'ezp';" diff --git a/bin/.travis/disable_xdebug.sh b/bin/.travis/disable_xdebug.sh new file mode 100755 index 0000000..c3749c3 --- /dev/null +++ b/bin/.travis/disable_xdebug.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +if [[ "$SYMFONY_DEBUG" == "" && "$TRAVIS_PHP_VERSION" != "" && "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then + echo "> Disable xdebug"; + phpenv config-rm xdebug.ini ; +fi diff --git a/bin/.travis/get_behat_features.sh b/bin/.travis/get_behat_features.sh new file mode 100755 index 0000000..d37625e --- /dev/null +++ b/bin/.travis/get_behat_features.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Fastest option 'list-features' gives us the list of all features from given context in random order, which are later +# run in this order in few threads and dynamically distributed between these threads. That gives us different test build +# times each build, often non optimal. To make this optimal we sort features by the number of scenarios in them +# (ascending because Fastest reverse the queue order, and we want this queue to run descending) and run them in that order, +# to minimize final time gap between the threads. +PROFILE='' +SUITE='' +TAGS='' + +while getopts p:s:t: option +do +case "${option}" +in +p) PROFILE="--profile=${OPTARG}";; +s) SUITE="--suite=${OPTARG}";; +t) TAGS="--tags=${OPTARG}";; +esac +done + +bin/behat ${PROFILE} ${SUITE} ${TAGS} --list-scenarios | awk '{ gsub(/:[0-9]+/,"",$1); print $1 }' | uniq -c | sort | awk '{ print $2 }' diff --git a/bin/.travis/parameters.yml b/bin/.travis/parameters.yml new file mode 100644 index 0000000..b047a67 --- /dev/null +++ b/bin/.travis/parameters.yml @@ -0,0 +1,5 @@ +# Only settings different then parameters.yml.dist, buildParameters will inject those we don't define from there! +parameters: + env(DATABASE_NAME): behattestdb + env(DATABASE_USER): ezp + env(DATABASE_PASSWORD): ezp diff --git a/bin/.travis/prepare_selenium2.sh b/bin/.travis/prepare_selenium2.sh new file mode 100755 index 0000000..8bf71c0 --- /dev/null +++ b/bin/.travis/prepare_selenium2.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +echo "> Prepare X and start Selenium" +export DISPLAY=:99.0 +sh -e /etc/init.d/xvfb start +wget http://selenium-release.storage.googleapis.com/2.47/selenium-server-standalone-2.47.1.jar +java -jar selenium-server-standalone-2.47.1.jar -log /tmp/selenium.log & +cd - + +# Give Selenium some time to start, otherwise tests will fail under high load on test servers +sleep 8 diff --git a/bin/.travis/prepare_system.sh b/bin/.travis/prepare_system.sh new file mode 100755 index 0000000..3e28313 --- /dev/null +++ b/bin/.travis/prepare_system.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Script to do tasks before install, can install system packages / software +## See http://about.travis-ci.org/docs/user/build-configuration/ +## +## @todo Initial setup (before_install+before_scripts) currently takes about 3 minutes, +## can be reduced if needed by using parallel download techniques as found in: +## https://github.com/facebook/hiphop-php/commit/4add8586c5d9e4eee20fe15ccd78db9e9c6b56aa +## https://github.com/facebook/hiphop-php/commit/0b2dfdf4492eb06a125b068e939d092ec0588e5c + +./bin/.travis/disable_xdebug.sh + +# Remove php memory limit +echo 'memory_limit = -1' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + +# Install needed packages +echo "> Installing needed packages"; +sudo apt-get update +sudo apt-get install -q -y --force-yes apache2 libapache2-mod-fastcgi + +# Http Server +echo "> Configure apache server" +./bin/.travis/configure_apache2.sh + +./bin/.travis/configure_mysql.sh diff --git a/bin/.travis/router_behat.php b/bin/.travis/router_behat.php new file mode 100644 index 0000000..a7378ba --- /dev/null +++ b/bin/.travis/router_behat.php @@ -0,0 +1,10 @@ + Modify composer.json to point to local checkout" +sed -i '$d' composer.json +echo ', "repositories": [{"type":"git","url":"'$REPO_DIR'"}]}' >> composer.json + +if [ -n "$COMPOSER_REQUIRE" ]; then + echo "> Updating packages ($COMPOSER_REQUIRE)" + composer require --no-update "$COMPOSER_REQUIRE" +fi + +cat composer.json +./bin/.travis/prepare_ezpublish.sh + +echo "> Warm up cache, using curl to make sure everything is warmed up, incl class, http & spi cache" +curl -sSLI "http://localhost" diff --git a/bin/.travis/trigger_regression_build.sh b/bin/.travis/trigger_regression_build.sh new file mode 100755 index 0000000..3448897 --- /dev/null +++ b/bin/.travis/trigger_regression_build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +SYMFONY_ENV=behat ./vendor/ezsystems/behatbundle/EzSystems/BehatBundle/bin/.travis/trigger_ci.sh diff --git a/bin/.travis/trusty/setup_ezplatform.sh b/bin/.travis/trusty/setup_ezplatform.sh new file mode 100755 index 0000000..5a415f1 --- /dev/null +++ b/bin/.travis/trusty/setup_ezplatform.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# This script provides setup steps needed to build eZ Platform docker containers ready to execute +# functional and acceptance (behat) tests. +# +# Example usage: +# $ ./bin/.travis/trusty/setup_ezplatform.sh "${COMPOSE_FILE}" "${INSTALL_TYPE}" ["${DEPENDENCY_PACKAGE_DIR}"] +# +# Arguments: +# - ${COMPOSE_FILE} compose file(s) paths +# - ${INSTALL_TYPE} *Not in use* +# - ${DEPENDENCY_PACKAGE_DIR} optional, directory containing existing eZ Platform dependency package + +# Determine eZ Platform Build dir as relative to current script path +EZPLATFORM_BUILD_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../.." && pwd )" + +DEPENDENCY_PACKAGE_DIR=$3 + +if [[ -z "${1}" ]]; then + # If not set, read default from .env file + export $(grep "COMPOSE_FILE" ${EZPLATFORM_BUILD_DIR}/.env) +else + COMPOSE_FILE=$1 +fi + +if [[ -n "${DEPENDENCY_PACKAGE_DIR}" ]]; then + # Get details about dependency package + DEPENDENCY_PACKAGE_NAME=`php -r "echo json_decode(file_get_contents('${DEPENDENCY_PACKAGE_DIR}/composer.json'))->name;"` + + if [[ -z "${DEPENDENCY_PACKAGE_NAME}" ]]; then + echo 'Missing composer package name of tested dependency' >&2 + exit 2 + fi +fi + +echo '> Preparing eZ Platform container using the following setup:' +echo "- EZPLATFORM_BUILD_DIR=${EZPLATFORM_BUILD_DIR}" +echo "- COMPOSE_FILE=${COMPOSE_FILE}" +if [[ -n "${DEPENDENCY_PACKAGE_NAME}" ]]; then + echo "- DEPENDENCY_PACKAGE_NAME=${DEPENDENCY_PACKAGE_NAME}" +fi + +echo '> Remove XDebug PHP extension' +phpenv config-rm xdebug.ini + +# Handle dependency if needed +if [[ -n "${DEPENDENCY_PACKAGE_NAME}" ]]; then + # get dependency branch alias + BRANCH_ALIAS=`php -r "echo json_decode(file_get_contents('${DEPENDENCY_PACKAGE_DIR}/composer.json'))->extra->{'branch-alias'}->{'dev-tmp_ci_branch'};"` + if [[ $? -ne 0 || -z "${BRANCH_ALIAS}" ]]; then + echo 'Failed to determine branch alias. Add extra.branch-alias.dev-tmp_ci_branch config key to your tested dependency composer.json' >&2 + exit 3 + fi + + # move dependency to directory available for docker volume + BASE_PACKAGE_NAME=`basename ${DEPENDENCY_PACKAGE_NAME}` + echo "> Move ${DEPENDENCY_PACKAGE_DIR} to ${EZPLATFORM_BUILD_DIR}/${BASE_PACKAGE_NAME}" + mv ${DEPENDENCY_PACKAGE_DIR} ${EZPLATFORM_BUILD_DIR}/${BASE_PACKAGE_NAME} + cd ${EZPLATFORM_BUILD_DIR}/${BASE_PACKAGE_NAME} + + # perform full checkout to allow using as local Composer depenency + git fetch --unshallow + + echo "> Create temporary branch in ${DEPENDENCY_PACKAGE_NAME}" + # reuse HEAD commit id for better knowledge about what got checked out + TMP_TRAVIS_BRANCH=tmp_`git rev-parse --short HEAD` + git checkout -b ${TMP_TRAVIS_BRANCH} + + # go back to previous directory + cd - + + # use local checkout path relative to docker volume + echo "> Make composer use tested dependency local checkout ${TMP_TRAVIS_BRANCH} of ${BASE_PACKAGE_NAME}" + composer config repositories.localDependency git /var/www/${BASE_PACKAGE_NAME} + + echo "> Require ${DEPENDENCY_PACKAGE_NAME}:dev-${TMP_TRAVIS_BRANCH} as ${BRANCH_ALIAS}" + if ! composer require --no-update "${DEPENDENCY_PACKAGE_NAME}:dev-${TMP_TRAVIS_BRANCH} as ${BRANCH_ALIAS}"; then + echo 'Failed requiring dependency' >&2 + exit 3 + fi + +fi + +echo "> Install DB and dependencies" +docker-compose -f doc/docker/install-dependencies.yml up --abort-on-container-exit + +echo "> Start docker containers specified by ${COMPOSE_FILE}" +docker-compose up -d + +# for behat builds to work +echo '> Change ownership of files inside docker container' +docker-compose exec app sh -c 'chown -R www-data:www-data /var/www' + +echo '> Install data' +docker-compose exec --user www-data app sh -c "php /scripts/wait_for_db.php; composer ezplatform-install" + +echo '> Done, ready to run tests' diff --git a/bin/.travis/trusty/setup_from_external_repo.sh b/bin/.travis/trusty/setup_from_external_repo.sh new file mode 100755 index 0000000..a776471 --- /dev/null +++ b/bin/.travis/trusty/setup_from_external_repo.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +# @deprecated since 2.0, use ./bin/.travis/trusty/setup_ezplatform.sh +# +# This script is meant to be reused from other repos that needs to run behat tests. +# +# It assumes you have already checked pout ezplatform (to get access to this script) and +# moved original package into tmp_travis_folder under ezplatform folder so it is accessible +# from inside Docker images. +# +## Example use: +# +# env: +# - COMPOSE_FILE="doc/docker/prod.yml:doc/docker/selenium.yml" +# +# before_install: +# - git fetch --unshallow && git checkout -b tmp_travis_branch +# - export BRANCH_BUILD_DIR=$TRAVIS_BUILD_DIR TRAVIS_BUILD_DIR="$HOME/build/ezplatform" +# - cd "$HOME/build" +# - git clone --depth 1 --single-branch --branch master https://github.com/ezsystems/ezplatform.git +# - cd ezplatform +# - ./bin/.travis/trusty/setup_from_external_repo.sh $BRANCH_BUILD_DIR "ezsystems/demobundle:dev-tmp_travis_branch" +# +# script: docker-compose run -u www-data --rm behatphpcli bin/behat --profile=rest --suite=fullJson --tags=~@broken + +echo 'The script setup_from_external_repo is deprecated. Use ./bin/.travis/trusty/setup_ezplatform.sh instead.' >&2 + +REPO_DIR=$1 +COMPOSER_REQUIRE=${@:2} + +if [ "$COMPOSE_FILE" = "" ] ; then + echo "No COMPOSE_FILE defined, exiting " + exit 1 +fi + +echo "> Move '$REPO_DIR' to 'tmp_travis_folder'" +mv $REPO_DIR tmp_travis_folder +ls -al tmp_travis_folder +ls -al . + +./bin/.travis/trusty/update_docker.sh + +echo "> Modify composer.json to point to local checkout" +composer config repositories.tmp_travis_folder git ${HOME}/build/ezplatform/tmp_travis_folder + + +# Setup symlink for doc/docker-compose folder for compatibility with older package branches using this +ln -s docker doc/docker-compose + +if [ "$RUN_INSTALL" = "1" ] ; then + # TODO: avoid using composer on host so image don't need to be PHP image, needed atm as . + # TODO: dockerignore or something strips info needed for composer to be able to find tmp_travis_branch + if [ ! -f auth.json ]; then + cp bin/.travis/composer-auth.json auth.json + fi + echo 'memory_limit = -1' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + phpenv config-rm xdebug.ini + if [ -n "$COMPOSER_REQUIRE" ] ; then + # TODO: avoid using composer on host so image don't need to be PHP image + echo "> Updating packages ($COMPOSER_REQUIRE)" + composer require --no-update "$COMPOSER_REQUIRE" + cat composer.json + fi + echo "> Run composer install (try 3 times)" + for i in $(seq 1 3); do composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader && s=0 && break || s=$? && sleep 1; done; (exit $s) + mkdir -p web/var + rm -Rf var/logs/* var/cache/*/* + sudo chown -R www-data:www-data var web/var + find var web/var -type d | xargs chmod -R 775 + find var web/var -type f | xargs chmod -R 664 + # Do NOT use this for your prod setup, this is done like this for behat + sudo chown -R www-data:www-data app/config src + #docker-compose -f doc/docker/install.yml up --abort-on-container-exit +fi + +echo "> Start containers and install data" +docker-compose up -d +docker-compose exec --user www-data app sh -c "php /scripts/wait_for_db.php; composer ezplatform-install" + +echo "> Done, ready to run behatphpcli container" diff --git a/bin/.travis/trusty/update_docker.sh b/bin/.travis/trusty/update_docker.sh new file mode 100755 index 0000000..4e4001e --- /dev/null +++ b/bin/.travis/trusty/update_docker.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Update Docker, if needed +d_full=`docker version --format '{{.Server.Version}}'` +d=`echo $d_full | ( IFS="." ; read a b c && echo $a.$b)` +if (( $(echo "$d < 18.06" |bc -l) )); then + echo "Updating Docker from ${d} (${d_full}) to newest community edition" + # Update package info and selectively update docker-engine (and keep old travis specific config file) + sudo apt-get update + sudo apt-get --reinstall -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install docker-ce + docker -v +else + echo "Skip updating Docker ${d} (${d_full})" +fi + +# If we need to pin it to a given version: +# sudo apt-get --reinstall -y [...] install docker-engine=1.11.0-0~jessie +# http://apt.dockerproject.org/repo/dists/debian-jessie/main/binary-amd64/Packages + +# Update Docker Compose, if needed +dc_full=`docker-compose version --short` +dc=`echo $dc_full | ( IFS="." ; read a b c && echo $a.$b)` +if (( $(echo "$dc < 1.23" |bc -l) )); then + DOCKER_COMPOSE_VERSION="1.23.2" + echo "Updating Docker Compose from ${dc} (${dc_full}) to ${DOCKER_COMPOSE_VERSION}" + sudo rm -f /usr/local/bin/docker-compose + curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose + chmod +x docker-compose + sudo mv docker-compose /usr/local/bin +else + echo "Skip updating Docker Compose ${dc} (${dc_full})" +fi diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..fbc8ce4 --- /dev/null +++ b/bin/console @@ -0,0 +1,36 @@ +#!/usr/bin/env php +getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev'); +$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod'; + +if ($debug) { + Debug::enable(); +} + +$kernel = new AppKernel($env, $debug); +$application = new Application($kernel); +$application->run($input); diff --git a/bin/platformsh_prestart_cacheclear.sh b/bin/platformsh_prestart_cacheclear.sh new file mode 100755 index 0000000..7addfe0 --- /dev/null +++ b/bin/platformsh_prestart_cacheclear.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh +# This script is run as part of the .platform.app.yaml deployment step +# On PE Cluster (usually just production) this should be setup by platform.sh team as part of pre_start event + +set -e + +#date +echo "removing var/cache/${SYMFONY_ENV-dev}/*.* to avoid Symfony container issues on interface changes" +rm -Rf var/cache/${SYMFONY_ENV-dev}/*.* +#date +echo "clearing application cache" +php bin/console cache:clear +#date +echo "done executing pre_start cache clear" diff --git a/bin/sync_db_and_var.sh b/bin/sync_db_and_var.sh new file mode 100755 index 0000000..67ed379 --- /dev/null +++ b/bin/sync_db_and_var.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +if [ -z "$1" ] || [ -z "$2" ]; then + echo 'Please provide SSH login data and remote path to website!' + echo 'USAGE:' $0 'user@host ~/remote/path/' + echo '' + exit 0 +fi + + +SSH_LOGIN=$1 +REMOTE_PATH=$2 + +DBSYNC_FOLDER='web/var/dbsync' +DATABASE_NAME='db.sql' +STORAGE_FOLDER='web/var/site/storage' + +mkdir -p $DBSYNC_FOLDER +mkdir -p $STORAGE_FOLDER + + +echo "REMOTE =========================================" + + +ssh -T $SSH_LOGIN <<-ENDSSH + + cd $REMOTE_PATH + + php bin/console ngsite:database:dump $DBSYNC_FOLDER/$DATABASE_NAME + +ENDSSH + + +echo "SYNC DOWN DATABASE =============================" + + +rsync -av "$SSH_LOGIN:$REMOTE_PATH/$DBSYNC_FOLDER/" $DBSYNC_FOLDER/ +php bin/console doctrine:database:import $DBSYNC_FOLDER/$DATABASE_NAME + + +echo "SYNC DOWN VAR ==================================" + + +rsync -av --delete "$SSH_LOGIN:$REMOTE_PATH/$STORAGE_FOLDER/" $STORAGE_FOLDER/ + + +php bin/console cache:clear diff --git a/bin/vhost.sh b/bin/vhost.sh new file mode 100755 index 0000000..c2d8458 --- /dev/null +++ b/bin/vhost.sh @@ -0,0 +1,278 @@ +#!/bin/bash +# Script to generate virtual host config based on template containing variables among the ones defined below. +# For help text, execute: ./bin/vhost.sh -h + +# Available option variables, configurable by user +declare -a option_vars=( + %BASEDIR% + %IP_ADDRESS% + %PORT% + %HOST_NAME% + %HOST_ALIAS% + %SYMFONY_ENV% + %SYMFONY_DEBUG% + %SYMFONY_HTTP_CACHE% + %SYMFONY_TRUSTED_PROXIES% + %BODY_SIZE_LIMIT% + %TIMEOUT% + %FASTCGI_PASS% + %BINARY_DATA_HANDLER% +) + +# Available template variables +declare -a template_vars +# copy option_vars +template_vars=(${option_vars[*]}) +# The additional vars are calculated by script +template_vars+=("%BODY_SIZE_LIMIT_M%") +template_vars+=("%TIMEOUT_S%") +template_vars+=("%HOST_LIST%") + +# Default options +declare -a template_values=( + "" + '*' + "80" + "localhost" + "*.localhost" + "prod" + "" + "" + "" + "50331648" + "90" + "unix:/var/run/php5-fpm.sock" + "" + "48m" + "90s" + "localhost *.localhost" +) + +function show_help +{ + local env_list + # Errors + if [[ "$1" != "" ]] ; + then + if [[ "$2" != "" ]] ; then + echo "ERROR: Argument '${1}' is required" + else + echo "ERROR: Argument '${1}' is invalid" + fi + echo "" + fi + + env_list="${option_vars[@]//\%/}" + env_list="${env_list// /, }" + + # General help text + cat << EOF +Script for generating httpd config based on simplified templates + +Help (this text): +./bin/vhost.sh [-h|--help] + +Usage: +./bin/vhost.sh --basedir=/var/www/ezplatform \\ + --template-file=doc/apache2/vhost.template \\ + | sudo tee /etc/apache2/sites-enabled/my-site > /dev/null + +Default values will be fetched from the environment variables $env_list, but may be overridden using the arguments listed below. + +Arguments: + --template-file= : The file to use as a template for the generated output file + [--basedir=] : Root path to eZ installation, auto detected if command is run from root + [--host-name=localhost] : Primary host name, default "localhost" + [--host-alias=*.localhost] : Space separated list of host aliases, default "*.localhost" + [--ip=*|127.0.0.1] : IP address web server should accept traffic on. + [--port=80] : Port number web server should listen to. + [--sf-env=prod|dev|..] : Symfony environment used for the virtual host, default is "prod" + [--sf-debug=0|1] : Set if Symfony debug should be on, by default on if env is "dev" + [--sf-trusted-proxies=127.0.0.1,....] : Comma separated trusted proxies (e.g. Varnish), that we can get client ip from + [--sf-http-cache=0|1] : To disable Symfony HTTP cache Proxy for using a different reverse proxy + By default disabled when evn is "dev", enabled otherwise. + [--body-size-limit=] : Limit in megabytes for max size of request body, 0 value disables limit. + [--request-timeout=] : Limit in seconds before timeout of request, 0 value disables timeout limit. + [--binary-data-handler=dfs|] : Name of handler in user. Specify "dfs" if you are using the dfs io handler. + [-h|--help] : Help text, this one more or less + +EOF +} + +# This function checks if variables like BASEDIR, CLASSLOADER_FILE, etc. exist ( checks all variables defined in option_vars ) +# If environment variable exists, its value is used as default when parsing template +function inject_environment_variables +{ + local current_env_variable + local option_value + local env_var + local i + + i=0; + for env_var in "${option_vars[@]}"; do + # Remove "%" from from env_var.... + current_env_variable=${env_var//%/} + # Get value of variable referenced to by $current_env_variable. If env variable does not exist, value is set to "" + option_value=${!current_env_variable:-SomeDefault} + if [ "$option_value" != "SomeDefault" ]; then + template_values[$i]="$option_value"; + if [ "$current_env_variable" == "BODY_SIZE_LIMIT" ]; then + let template_values[9]="$option_value"*1024 + template_values[13]="${option_value}m" + fi + if [ "$current_env_variable" == "TIMEOUT" ]; then + template_values[10]="$option_value" + template_values[14]="${option_value}s" + fi + fi + let i=$i+1; + done +} + +inject_environment_variables + +## Parse arguments +for i in "$@" +do +case $i in + -b=*|--basedir=*) + template_values[0]="${i#*=}" + ;; + --ip=*) + template_values[1]="${i#*=}" + ;; + -p=*|--port=*) + template_values[2]="${i#*=}" + ;; + --host-name=*) + template_values[3]="${i#*=}" + ;; + --host-alias=*) + template_values[4]="${i#*=}" + ;; + -e=*|--sf-env=*) + template_values[5]="${i#*=}" + ;; + -d=*|--sf-debug=*) + template_values[6]="${i#*=}" + ;; + --sf-http-cache=*) + template_values[7]="${i#*=}" + ;; + --sf-trusted-proxies=*) + template_values[8]="${i#*=}" + ;; + --binary-data-handler=*) + template_values[12]="${i#*=}" + ;; + --body-size-limit=*) + let template_values[9]="${i#*=}"*1024*1024 + template_values[13]="${i#*=}m" + ;; + --request-timeout=*) + template_values[10]="${i#*=}" + template_values[14]="${i#*=}s" + ;; + -t=*|--template-file=*) + template_file="${i#*=}" + ;; + -h|--help) + show_help + exit 0 + ;; + *) + show_help "${i}" + exit 1 + ;; +esac +done + + +## Validation +if [ "$template_file}" == "" ] ; then + show_help "--template-file=$template_file" + exit 1 +fi + + +if [ ! -f "$template_file" ] ; then + show_help "--template-file=$template_file" + exit 1 +fi + +if [[ "${template_values[0]}" == "" ]] ; then + if [ -d web/ ] ; then + template_values[0]=`pwd` + else + show_help "--basedir=" true + exit 1 + fi +fi + +## Option specific logic + +# For httpd servers having just one host config we provide HOST_LIST +template_values[15]="${template_values[3]}" +if [[ "${template_values[4]}" != "" ]] ; then + tmp="${template_values[15]} ${template_values[4]}" + template_values[15]=$tmp +fi + + +## Generate template result and output + +template=$(<$template_file) +COUNTER=0 +while [ "${template_vars[$COUNTER]}" != "" ]; do + current_var=${template_vars[$COUNTER]} + current_value=${template_values[$COUNTER]} + + # Replace %VAR% with the actual value + tmp=${template//${current_var}/${current_value}} + + # Remove "%" from VAR for further use + current_var=${current_var//%/} + + # If variable has a value then do further replacement logic + if [ "$current_value" != "" ] ; then + + # Change "#if[VAR] " comments conditionally to uncommented lines + tmp=${tmp//"#if[${current_var}] "/""} + + # Change #if[VAR=current_value] comments conditionally to uncommented lines + tmp=${tmp//"#if[${current_var}=${current_value}] "/""} + + # Change remaining #if[VARIABLE=wrong_value] comments to conventional comment lines + regex="if\[${current_var}=([^]]*)\] " + while [[ $tmp =~ $regex ]] ; do + tmp=${tmp//"#if[${current_var}=${BASH_REMATCH[1]}] "/"#"} + done + + # Search for "#if[VARIABLE!=correct_value]" and enable line if found ( or transform to conventional comment lines ) + regex="if\[${current_var}!=([^]]*)\] " + while [[ $tmp =~ $regex ]] ; do + if [ "${BASH_REMATCH[1]}" != $current_value ] ; then + # Change "#if[VARIABLE!=wrong_value]" comment to uncommented line + tmp=${tmp//"#if[${current_var}!=${BASH_REMATCH[1]}] "/""} + else + # Change "#if[VARIABLE!=wrong_value]" comment to conventional comment line + tmp=${tmp//"#if[${current_var}!=${BASH_REMATCH[1]}] "/"#"} + fi + done + else + # Change "#if[!VAR] " comments conditionally to uncommented lines + tmp=${tmp//"#if[!${current_var}] "/""} + + # Change #if[VARIABLE[...]] comments to conventional comment lines + regex="if\[${current_var}([^]]*)\] " + while [[ $tmp =~ $regex ]] ; do + tmp=${tmp//"#if[${current_var}${BASH_REMATCH[1]}] "/"#"} + done + fi + + # Set result on template var + template=$tmp + let COUNTER=COUNTER+1 +done + +echo "$template" diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..1e5f299 --- /dev/null +++ b/composer.json @@ -0,0 +1,159 @@ +{ + "name": "netgen/media-site", + "description": "Netgen Media Site (Powered by Netgen Layouts & eZ Platform)", + "homepage": "https://netgen.io", + "license": "GPL-2.0-only", + "type": "project", + "authors": [ + { + "name": "Netgen", + "homepage": "https://netgen.io" + }, + { + "name": "eZ dev team & eZ Community", + "homepage": "https://github.com/ezsystems/ezplatform/contributors" + } + ], + "autoload": { + "psr-0": { "": "src/" }, + "classmap": [ "app/AppKernel.php", "app/AppCache.php" ] + }, + "autoload-dev": { + "psr-4": { "Tests\\": "tests/" }, + "files": [ "vendor/symfony/symfony/src/Symfony/Component/VarDumper/Resources/functions/dump.php" ] + }, + "require": { + "php": "^7.2", + "doctrine/doctrine-bundle": "^1.9.1", + "doctrine/orm": "^2.6.3", + "ezsystems/doctrine-dbal-schema": "^0.1.2", + "ezsystems/ez-support-tools": "^1.0.4", + "ezsystems/ezplatform-admin-ui": "~1.5.9", + "ezsystems/ezplatform-admin-ui-assets": "^4.2.0", + "ezsystems/ezplatform-admin-ui-modules": "~1.5.7", + "ezsystems/ezplatform-core": "^1.0.3", + "ezsystems/ezplatform-cron": "^2.0.1", + "ezsystems/ezplatform-design-engine": "^2.0.0", + "ezsystems/ezplatform-graphql": "^1.0.5", + "ezsystems/ezplatform-http-cache": "^1.0.0", + "ezsystems/ezplatform-matrix-fieldtype": "^1.0.3", + "ezsystems/ezplatform-richtext": "^1.1.6", + "ezsystems/ezplatform-solr-search-engine": "^1.7.3", + "ezsystems/ezplatform-standard-design": "^0.2.1", + "ezsystems/ezplatform-user": "^1.0.5", + "ezsystems/ezpublish-kernel": "~7.5.7", + "ezsystems/repository-forms": "~2.5.6", + "ezsystems/symfony-tools": "^1.1.0", + "friendsofsymfony/jsrouting-bundle": "^1.6.3", + "incenteev/composer-parameter-handler": "^2.1.3", + "knplabs/knp-menu-bundle": "^2.2.1 || ^3.0", + "monolog/monolog": "^1.25.2", + "overblog/graphql-bundle": "^0.11.11", + "scssphp/scssphp": "~1.0", + "sensio/distribution-bundle": "^5.0.23", + "sensiolabs/security-checker": "^5.0", + "symfony/monolog-bundle": "^3.3.1", + "symfony/swiftmailer-bundle": "^3.2.4", + "symfony/symfony": "^3.4.35", + "symfony/thanks": "^1.1.0", + "twig/extensions": "^1.5.3", + "white-october/pagerfanta-bundle": "^1.2.2", + "willdurand/js-translation-bundle": "^2.6.6", + + "ezsystems/ezplatform-xmltext-fieldtype": "^1.9.2", + "ezsystems/ezpublish-legacy": ">=2019.03.4", + + "guzzlehttp/psr7": "^1.6.1", + "php-http/curl-client": "^1.7.1", + "php-http/httplug-bundle": "^1.15.2", + "sentry/sentry-symfony": "^3.4.4", + "symfony/webpack-encore-bundle": "^1.7.3", + + "netgen/media-site-data": "~1.4.0", + "netgen/site-bundle": "~1.3.0", + "netgen/site-generator-bundle": "~1.2.0", + "netgen/site-legacy-bundle": "^1.2", + "netgen/site-installer-bundle": "^1.1", + "netgen/information-collection-bundle": "^1.9", + "netgen/ezplatform-site-api": "^3.4.1", + "netgen/ezplatform-search-extra": "^1.11", + "netgen/admin-ui-bundle": "^2.6.6", + + "netgen/layouts-standard": "~1.1.0", + "netgen/layouts-ezplatform": "~1.1.0", + "netgen/layouts-ezplatform-site-api": "~1.1.0", + "netgen/layouts-ezplatform-relation-list-query": "^1.0", + "netgen/layouts-ezplatform-tags-query": "^1.0" + }, + "require-dev": { + "behat/behat": "^3.5.0", + "behat/mink-extension": "^2.3.1", + "behat/mink-goutte-driver": "^1.2.1", + "behat/mink-selenium2-driver": "^1.3.1", + "behat/symfony2-extension": "^2.1.5", + "bex/behat-screenshot": "^1.2.7", + "ezsystems/allure-behat": "^2.0", + "ezsystems/behat-screenshot-image-driver-cloudinary": "^1.1.1", + "ezsystems/behatbundle": "^7.0.3", + "liuggio/fastest": "^1.6", + "overblog/graphiql-bundle": "^0.1.2", + "phpunit/phpunit": "^8.5 || ^9.1", + "sensio/generator-bundle": "^3.1.7", + "symfony/phpunit-bridge": "^5.0", + "snc/redis-bundle": "^3.2.1", + "predis/predis": "^1.1.1", + "franzl/studio": "*" + }, + "conflict": { + "doctrine/dbal": "2.7.0", + "doctrine/persistence": "1.3.2", + "twig/twig": "2.6.1" + }, + "scripts": { + "symfony-scripts": [ + "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", + "eZ\\Bundle\\EzPublishCoreBundle\\Composer\\ScriptHandler::clearCache", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", + "eZ\\Bundle\\EzPublishLegacyBundle\\Composer\\ScriptHandler::installAssets", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", + "eZ\\Bundle\\EzPublishLegacyBundle\\Composer\\ScriptHandler::installLegacyBundlesExtensions", + "Netgen\\Bundle\\SiteBundle\\Composer\\ScriptHandler::installProjectSymlinks", + "Netgen\\Bundle\\SiteLegacyBundle\\Composer\\ScriptHandler::installLegacySymlinks", + "eZ\\Bundle\\EzPublishLegacyBundle\\Composer\\ScriptHandler::generateAutoloads", + "@php bin/security-checker security:check" + ], + "post-install-cmd": [ + "@symfony-scripts" + ], + "post-update-cmd": [ + "@symfony-scripts" + ], + "ezplatform-install": [ + "@php bin/console ezplatform:install netgen-media" + ], + "ezplatform-assets": [ + "@php bin/console bazinga:js-translation:dump web/assets --merge-domains", + "yarn ezplatform" + ] + }, + "config": { + "bin-dir": "bin", + "preferred-install": "dist" + }, + "extra": { + "symfony-app-dir": "app", + "symfony-bin-dir": "bin", + "symfony-var-dir": "var", + "symfony-web-dir": "web", + "symfony-tests-dir": "tests", + "ezpublish-legacy-dir": "ezpublish_legacy", + "symfony-assets-install": "relative", + "incenteev-parameters": { + "keep-outdated": true, + "file": "app/config/parameters.yml" + }, + "branch-alias": { + "dev-master": "1.5.x-dev" + } + } +} diff --git a/doc/apache2/Readme.md b/doc/apache2/Readme.md new file mode 100644 index 0000000..b76c7f0 --- /dev/null +++ b/doc/apache2/Readme.md @@ -0,0 +1,165 @@ +Apache 2.4 configuration +======================== + +For recommended versions of [Apache](https://httpd.apache.org/), see [online eZ requirements](https://doc.ezplatform.com/en/latest/getting_started/requirements/). + + +Prerequisites +------------- +- Some general knowledge of how to install and configure Apache +- Apache 2.4 must be installed using one of the following Multi-Processing Modules (MPM): + - [Event](https://httpd.apache.org/docs/2.4/mod/event.html), or alternatively [Worker](https://httpd.apache.org/docs/2.4/mod/worker.html), for use with `php-fpm` over FastCGI. + - [Prefork](https://httpd.apache.org/docs/2.4/mod/prefork.html), together with `mod_php`, running PHP as an Apache module. + - Useful for Backwards compatibility or simple needs. For better performance _(less memory usage)_ pick a setup with `Event` MPM instead. +- Apache modules installed and enabled: + - required: `mod_rewrite`, `mod_env` + - recommended: `mod_setenvif`, `mod_expires` + - If you use "Apache MPM Prefork": `mod_php` + + +Configure +--------- +These examples are simplified to get you up and running, see [Virtual host template](#virtual-host-template) for more options and details on best practice. + +#### Virtual Host + +1. Place virtualhost config *(example below)* in a suitable Apache config folder, typically: + - Debian/Ubuntu: `/etc/apache2/sites-enabled/.conf` + - RHEL/CentOS/Amazon-Linux: `/etc/httpd/conf.d/.conf` +2. Adjust the basics to your setup: + - [VirtualHost](https://httpd.apache.org/docs/2.4/en/mod/core.html#virtualhost): IP and port number to listen to. + - [ServerName](https://httpd.apache.org/docs/2.4/en/mod/core.html#servername): Your host name, example `ez.no`. + - Or for local dev for instance `ezinstall.localhost`, with corresponding entry in your [hosts file](https://en.wikipedia.org/wiki/Hosts_file). + - [ServerAlias](https://httpd.apache.org/docs/2.4/en/mod/core.html#serveralias): Optional host alias list, example `www.ez.no login.ez.no`, or `*.ez.no`. + - [DocumentRoot](https://httpd.apache.org/docs/2.4/en/mod/core.html#documentroot): Point this and *Directory* to `web` directory of eZ installation. + - If you can't install `mod_setenvif`, adjust the "Environment" section like described inline. +3. Restart Apache, as follows: + - Debian/Ubuntu: `sudo service apache2 restart` + - RHEL/CentOS/Amazon-Linux: `sudo service httpd restart` + +Example config for Apache 2.4 in prefork mode: + + + ServerName localhost + #ServerAlias *.localhost + DocumentRoot /var/www/ezinstall/web + DirectoryIndex app.php + + # Set default timeout to 90s, and max upload to 48mb + TimeOut 90 + LimitRequestBody 50331648 + + + Options FollowSymLinks + AllowOverride None + # Depending on your global Apache settings, you may need to comment this: + Require all granted + + + # As we require ´mod_rewrite´ this is on purpose not placed in a block + RewriteEngine On + + # Environment. + # Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration + # Defaults to "prod" if omitted. If Apache complains about this line and you can't install `mod_setenvif` then + # comment out "%{ENV:SYMFONY_ENV}" line below, and comment this out or set via: SetEnv SYMFONY_ENV "prod" + SetEnvIf Request_URI ".*" SYMFONY_ENV=prod + + # Sets the HTTP_AUTHORIZATION header sometimes removed by Apache + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Disable .php(3) and other executable extensions in the var directory + RewriteRule ^var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ - [F] + + # Access to repository images in single server setup + RewriteRule ^/var/([^/]+/)?storage/images(-versioned)?/.* - [L] + + # Makes it possible to placed your favicon and robots.txt at the root of your web folder + RewriteRule ^/favicon\.ico - [L] + RewriteRule ^/robots\.txt - [L] + + # The following rules are needed to correctly display bundle and project assets + RewriteRule ^/bundles/ - [L] + RewriteRule ^/assets/ - [L] + + # Additional Assetic rules for environments different from dev, + # remember to run php bin/console assetic:dump --env=prod + RewriteCond %{ENV:SYMFONY_ENV} !^(dev) + RewriteRule ^/(css|js|fonts?)/.*\.(css|js|otf|eot|ttf|svg|woff) - [L] + + RewriteRule .* /app.php + + + +#### .htaccess + +If you do not have an access to use virtualhost config, use the `.htaccess` file in a simplified form. It must be placed in the `web/` folder to make it running. *This will not work if Apache is configured with the `AllowOverride None` for this directory.* + + DirectoryIndex app.php + + # Set default timeout to 90s, and max upload to 48mb + TimeOut 90 + LimitRequestBody 50331648 + + # Disabling MultiViews prevents unwanted negotiation, e.g. "/app" should not resolve + # to the front controller "/app.php" but be rewritten to "/app.php/app". + + Options -MultiViews + + + # As we require ´mod_rewrite´ this is on purpose not placed in a block + RewriteEngine On + + # Environment. + # Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration + # Defaults to "prod" if omitted. + SetEnv SYMFONY_ENV "prod" + + # Sets the HTTP_AUTHORIZATION header sometimes removed by Apache + RewriteCond %{HTTP:Authorization} . + RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Disable .php(3) and other executable extensions in the var directory + RewriteRule ^var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ - [F] + + # Makes it possible to placed your favicon and robots.txt at the root of your web folder + RewriteRule ^favicon\.ico - [L] + RewriteRule ^robots\.txt - [L] + + # To display assets from eZ / Symfony bundles + RewriteRule ^bundles/ - [L] + + # Access to repository images in single server setup + RewriteRule ^var/([^/]+/)?storage/images(-versioned)?/.* - [L] + + # Additional Assetic rules for prod environments + # ! Remember to run php ezpublish/console assetic:dump --env=prod on changes + # ! Or if SYMFONY_ENV is set to "dev", comment this out! + RewriteRule ^(css|js|fonts?)/.*\.(css|js|otf|eot|ttf|svg|woff) - [L] + + # Rewrite all other queries to the front controller. + RewriteRule .* app.php + + +Virtual host template +--------------------- +This folder contains `vhost.template` which provides more features you can enable in your virtual host configuration. +You may also use this file as a `.htaccess` config. However, +you will need to adjust rewrite rules to remove `/` like in the example above. + +*Note: vhost.template uses `mod_setenvif`, adapt it as indicated inline if you can't install it.* + +Bash script *(Unix/Linux/OS X)* exists to be able to generate the configuration. To display help text, execute the +following from the eZ installation root: +```bash +./bin/vhost.sh -h +``` + +#### Common issues + +##### NameVirtualHost conflicts + +The `NameVirtualHost` setting might already exist in the default configuration. Defining a new one will result in a +conflict. If Apache reports errors such as `NameVirtualHost [IP_ADDRESS] has no VirtualHosts` or `Mixing * ports and +non-* ports with a NameVirtualHost address is not supported`, try removing the `NameVirtualHost` line. +For more details, see [NameVirtualHost directive](http://httpd.apache.org/docs/2.4/mod/core.html#namevirtualhost) section in Apache documentation. diff --git a/doc/apache2/netgen-site-vhost.conf b/doc/apache2/netgen-site-vhost.conf new file mode 100644 index 0000000..591f188 --- /dev/null +++ b/doc/apache2/netgen-site-vhost.conf @@ -0,0 +1,120 @@ +# NameVirtualHost *:80 + + + ServerName localhost + + DocumentRoot /var/www/netgensite/web + ErrorLog /var/log/apache2/netgensite-error.log + CustomLog /var/log/apache2/netgensite-common.log common + + + Options +FollowSymLinks + Options -Indexes + AllowOverride None + + + ## eZ Platform/Symfony ENVIRONMENT variables, for customizing app.php* execution + # * Only SYMFONY_ENV and SYMFONY_DEBUG supported by console command, rest are eZ Platform features in app.php. + + # Environment. + # Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration + # Defaults to "prod" if omitted (uses SetEnvIf so value can be used in rewrite rules) + #SetEnvIf Request_URI ".*" SYMFONY_ENV=prod + + # Optional: Whether to use debugging. + # Possible values: 0, 1 or "" + # Defaults to enabled if SYMFONY_ENV is set to "dev" if env value is omitted or empty + #SetEnv SYMFONY_DEBUG "0" + + # Optional: Whether to use Symfony's builtin HTTP Caching Proxy. + # Disable it if you are using an external reverse proxy (e.g. Varnish) + # Possible values: 0, 1 or "" + # Defaults to disabled if SYMFONY_ENV is set to "dev" or SYMFONY_TRUSTED_PROXIES is set, + # and if this env value is omitted or empty + #SetEnv SYMFONY_HTTP_CACHE "1" + + # Optional: Defines the proxies to trust + # Needed when using Varnish as proxy, if so disable SYMFONY_HTTP_CACHE. + # Separate entries by a comma, example: "ip1,ip2" + # Defaults to not be set if env value is omitted or empty + #SetEnv SYMFONY_TRUSTED_PROXIES "127.0.0.1" + + # TIP: There are many more environment variables supported by eZ Platform. However unlike those listed above + # they should in most cases rather be set in the environment then in vhost config to make sure cronjobs + # and cli command usage takes them into account as well. + + + # NOTE: Using gzip on text/html can be a security issue. See http://breachattack.com. + # AddOutputFilterByType DEFLATE text/html + AddOutputFilterByType DEFLATE text/plain + AddOutputFilterByType DEFLATE text/xml + AddOutputFilterByType DEFLATE text/css + AddOutputFilterByType DEFLATE application/xml + AddOutputFilterByType DEFLATE application/json + AddOutputFilterByType DEFLATE application/xhtml+xml + AddOutputFilterByType DEFLATE application/rss+xml + AddOutputFilterByType DEFLATE application/javascript + AddOutputFilterByType DEFLATE application/x-javascript + + + AddDefaultCharset UTF-8 + + DirectoryIndex app.php + + + RewriteEngine On + + # For FastCGI mode or when using PHP-FPM, to get basic auth working. + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + RewriteCond %{ENV:REDIRECT_STATUS} ^$ + RewriteRule ^/app\.php(/(.*)|$) /$2 [R=301,L] + + # Let's Encrypt support + RewriteRule ^/\.well-known/acme-challenge/ - [L] + + # START: Multisite rewrite rules for robots.txt + + # RewriteRule ^robots_site1.txt$ - [L] + # RewriteCond %{HTTP_HOST} ^site1.example.com$ [NC] + # RewriteRule ^robots.txt$ robots_site1.txt [L] + + # RewriteRule ^robots_site2.txt$ - [L] + # RewriteCond %{HTTP_HOST} ^site2.example.com$ [NC] + # RewriteRule ^robots.txt$ robots_site2.txt [L] + + # END: Multisite rewrite rules for robots.txt + + # START: Maintenance mode + + # RewriteRule ^/offline_eng.html$ - [L] + + # RewriteRule .* /offline_eng.html [R=503,L] + # ErrorDocument 503 /offline_eng.html + + # END: Maintenance mode + + # Disable .php(3) and other executable extensions in the var directory + RewriteRule ^/var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ - [F] + + RewriteRule ^/var/([^/]+/)?storage/images(-versioned)?/.* - [L] + RewriteRule ^/var/([^/]+/)?storage/original/image/(.*)\.svg - [L] + RewriteRule ^/var/([^/]+/)?cache/(texttoimage|public)/.* - [L] + RewriteRule ^/design/[^/]+/(stylesheets|images|fonts|javascript)/.* - [L] + RewriteRule ^/share/icons/.* - [L] + RewriteRule ^/extension/[^/]+/design/[^/]+/(stylesheets|flash|images|fonts|lib|javascripts?)/.* - [L] + + # Makes it possible to placed your favicon and robots.txt at the root of your web folder + RewriteRule ^/favicon\.ico - [L] + RewriteRule ^/robots\.txt - [L] + + # The following rules are needed to correctly display bundle and project assets + RewriteRule ^/bundles/ - [L] + RewriteRule ^/assets/ - [L] + + # Prevent access to website with direct usage of app.php in URL + RewriteRule ^/([^/]+/)?app\.php([/?#]|$) - [R=404,L] + + RewriteRule .* /app\.php + + diff --git a/doc/apache2/netgen-site.conf b/doc/apache2/netgen-site.conf new file mode 100644 index 0000000..94d47af --- /dev/null +++ b/doc/apache2/netgen-site.conf @@ -0,0 +1,39 @@ +# NameVirtualHost *:80 + + + ServerName localhost + + DocumentRoot /var/www/netgensite/web + ErrorLog /var/log/apache2/netgensite-error.log + CustomLog /var/log/apache2/netgensite-common.log common + + + Options +FollowSymLinks + Options -Indexes + AllowOverride All + + +# +# +# +# ExpiresActive on +# ExpiresDefault "now plus 2 years" +# +# +# +# ExpiresActive on +# ExpiresDefault "now plus 30 days" +# +# +# +# ExpiresActive on +# ExpiresDefault "now plus 30 days" +# +# +# +# ExpiresActive on +# ExpiresDefault "now plus 30 days" +# +# +# + diff --git a/doc/apache2/vhost.template b/doc/apache2/vhost.template new file mode 100644 index 0000000..25348bd --- /dev/null +++ b/doc/apache2/vhost.template @@ -0,0 +1,124 @@ +# Official VirtualHost configuration for Apache 2.4 template +# See Readme.md for how to generate your config manually, or in automated deployments. +# Note: This is meant to be manually tailored for your needs, expires headers might for instance not work for your dev setup. + +# NameVirtualHost %IP_ADDRESS% + + + ServerName %HOST_NAME% + ServerAlias %HOST_ALIAS% + DocumentRoot %BASEDIR%/web + DirectoryIndex app.php + + # Request size limit in bytes, 0 to disable + LimitRequestBody %BODY_SIZE_LIMIT% + + # Request timeout limit in seconds, 0 to disable + TimeOut %TIMEOUT% + + # Enabled for Dev environment + #LogLevel debug + + # "web" folder is what we expose to the world, all rewrite rules further down is relative to it. + + + # For serving php files configure mod_proxy to talk to php-fpm using Apache 2.4.10 and higher. + # See: https://wiki.apache.org/httpd/PHP-FPM#apache_httpd_2.4 + + # For best performance, prefer socket use. This requires Linux, and that both Apache and PHP has access to + # the socket file `/var/run/php5-fpm.sock` via local file system and hence run on the same machine. + #SetHandler "proxy:unix:/var/run/php5-fpm.sock|fcgi://localhost/" + # For TCP usage, if you're not on Linux, or Apache and PHP are on separate machines, instead use fcgi: form. + # (Optionally hint php-fpm processes count using: https://wiki.apache.org/httpd/PHP-FPM#Proxy_via_handler) + #SetHandler "proxy:fcgi://localhost/:9000" + + SetHandler "proxy:%FASTCGI_PASS%|fcgi://localhost/" + + + Options FollowSymLinks + AllowOverride None + Require all granted + + + ## eZ Platform/Symfony ENVIRONMENT variables, for customizing app.php* execution + # * Only SYMFONY_ENV and SYMFONY_DEBUG supported by console command, rest are eZ Platform features in app.php. + + # Environment. + # Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration + # Defaults to "prod" if omitted (uses SetEnvIf so value can be used in rewrite rules) + #if[SYMFONY_ENV] SetEnvIf Request_URI ".*" SYMFONY_ENV=%SYMFONY_ENV% + + # Optional: Whether to use debugging. + # Possible values: 0, 1 or "" + # Defaults to enabled if SYMFONY_ENV is set to "dev" if env value is omitted or empty + #if[SYMFONY_DEBUG] SetEnv SYMFONY_DEBUG "%SYMFONY_DEBUG%" + + # Optional: Whether to use Symfony's builtin HTTP Caching Proxy. + # Disable it if you are using an external reverse proxy (e.g. Varnish) + # Possible values: 0, 1 or "" + # Defaults to disabled if SYMFONY_ENV is set to "dev" or SYMFONY_TRUSTED_PROXIES is set, + # and if this env value is omitted or empty + #if[SYMFONY_HTTP_CACHE] SetEnv SYMFONY_HTTP_CACHE "%SYMFONY_HTTP_CACHE%" + + # Optional: Defines the proxies to trust + # Needed when using Varnish as proxy, if so disable SYMFONY_HTTP_CACHE. + # Separate entries by a comma, example: "ip1,ip2" + # Defaults to not be set if env value is omitted or empty + #if[SYMFONY_TRUSTED_PROXIES] SetEnv SYMFONY_TRUSTED_PROXIES "%SYMFONY_TRUSTED_PROXIES%" + + # TIP: There are many more environment variables supported by eZ Platform. However unlike those listed above + # they should in most cases rather be set in the environment then in vhost config to make sure cronjobs + # and cli command usage takes them into account as well. + + + RewriteEngine On + + # For FastCGI mode or when using PHP-FPM, to get basic auth working. + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Disable .php(3) and other executable extensions in the var directory + RewriteRule ^var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ - [F] + + # Cluster/streamed files rewrite rules. Enable on cluster with DFS as a binary data handler + RewriteCond %{ENV:BINARY_DATA_HANDLER} "dfs" + RewriteRule ^/var/([^/]+/)?storage/images(-versioned)?/.* /app.php [L] + + RewriteRule ^/var/([^/]+/)?storage/images(-versioned)?/.* - [L] + + # Makes it possible to placed your favicon and robots.txt at the root of your web folder + RewriteRule ^/favicon\.ico - [L] + RewriteRule ^/robots\.txt - [L] + + # The following rules are needed to correctly display bundle and project assets + RewriteRule ^/bundles/ - [L] + RewriteRule ^/assets/ - [L] + + # Additional Assetic rules for environments different from dev, + # remember to run php bin/console assetic:dump --env=prod + RewriteCond %{ENV:SYMFONY_ENV} !^(dev) + RewriteRule ^/(css|js|fonts?)/.*\.(css|js|otf|eot|ttf|svg|woff) - [L] + + # Prevent access to website with direct usage of app.php in URL + RewriteRule ^/([^/]+/)?app\.php([/?#]|$) - [R=404,L] + + RewriteRule .* /app.php + + + # Everything below is optional to improve performance by forcing + # clients to cache image and design files, change the expires time + # to suite project needs. + + + # eZ Platform appends the version number to image URL (ezimage + # datatype) so when an image is updated, its URL changes too + ExpiresActive on + ExpiresDefault "now plus 10 years" + + + + # Enable gzip encoding + + AddOutputFilterByType DEFLATE text/plain text/css application/json text/javascript application/javascript text/xml application/xml application/xml+rss + # NOTE: Using gzip on text/html can be a security issue. See http://breachattack.com. + + diff --git a/doc/docker/Dockerfile-app b/doc/docker/Dockerfile-app new file mode 100644 index 0000000..2ea4f08 --- /dev/null +++ b/doc/docker/Dockerfile-app @@ -0,0 +1,41 @@ +ARG PHP_IMAGE=ezsystems/php:7.3-v1 +FROM ${PHP_IMAGE}-node as builder + +# This is prod image (for dev use just mount your application as host volume into php image we extend here) +ENV SYMFONY_ENV=prod + +# Copy in project files into work dir +COPY . /var/www + +# Check for ignored folders to avoid layer issues, ref: https://github.com/docker/docker/issues/783 +RUN if [ -d .git ]; then echo "ERROR: .dockerignore folders detected, exiting" && exit 1; fi + +# Install and prepare install +RUN mkdir -p web/var +# For now, only run composer in order to generate parameters.yml +RUN composer run-script post-install-cmd --no-interaction +RUN composer dump-autoload --optimize + +# Next, remove everything we don't want to be copied to next build stage +# Clear cache again so env variables are taken into account on startup +RUN rm -Rf var/logs/* var/cache/*/* + +# Looks like we need to keep web/bundles ( like web/bundles/ezstudioui/js/views/ezs-landingpageview.js ) or else +# urls like http://localhost:8080/_ezcombo?/bundles/ezstudioui/js/views/ezs-landingpageview.js&/tpl/handlebars/studiolandingpageconfigview-ez-template.js&/bundles/ezstudioui/js/views/ezs-landingpageconfigview.js&/tpl/handlebars/studiolayoutselectorview-ez-template.js&/bundles/ezstudioui/js/views/ezs-layoutselectorview.js&/tpl/handlebars/studiolandingpageconfigpopupformview-ez-template.js&/bundles/ezstudioui/js/views/forms/ezs-landingpageconfigpopupformview.js&/tpl/handlebars/landingpagecreatorview-ez-template.js&/bundles/ezsystemsformbuilder/js/models/fb-formfield-model.js&/bundles/ezsystemsformbuilder/js/lists/fb-formfields-modellist.js&/bundles/ezsystemsformbuilder/js/models/fb-formpage-model.js&/bundles/ezsystemsformbuilder/js/lists/fb-formpages-modellist.js&/bundles/ezsystemsformbuilder/js/models/fb-form-model.js&/tpl/handlebars/fbbasetabview-ez-template.js&/bundles/ezsystemsformbuilder/js/tabs/fb-base-tabview.js&/tpl/handlebars/fbpanelview-ez-template.js&/bundles/ezsystemsformbuilder/js/panels/fb-panelview.js +# will not work when loading http://localhost:8080/ez +# The other directories (except web/var) can be removed as they will be located in the web (nginx) image +# web/var can be removed as will be mounted via vardir volume +RUN rm -rf web/css web/fonts web/js web/var + + +FROM ${PHP_IMAGE} + +# This is prod image (for dev use just mount your application as host volume into php image we extend here) +ENV SYMFONY_ENV=prod + +COPY --from=builder /var/www /var/www + +# Fix permissions for www-data +RUN chown -R www-data:www-data var \ + && find var -type d -print0 | xargs -0 chmod -R 775 \ + && find var -type f -print0 | xargs -0 chmod -R 664 diff --git a/doc/docker/Dockerfile-dbdump b/doc/docker/Dockerfile-dbdump new file mode 100644 index 0000000..8c94902 --- /dev/null +++ b/doc/docker/Dockerfile-dbdump @@ -0,0 +1,9 @@ +FROM busybox + +copy doc/docker/entrypoint/mysql/2_dump.sql /dbdump/ezp.sql + +VOLUME ["/dbdump"] + + +CMD ["/bin/true"] + diff --git a/doc/docker/Dockerfile-distribution b/doc/docker/Dockerfile-distribution new file mode 100644 index 0000000..aae6a9d --- /dev/null +++ b/doc/docker/Dockerfile-distribution @@ -0,0 +1,27 @@ +# Note : if you set the environment variable COMPOSE_PROJECT_NAME to a non-default value, you'll need to set the +# DISTRIBUTION_IMAGE build arg too (for instance docker-compose build --no-cache --build-arg DISTRIBUTION_IMAGE=customprojectname_app distribution) +ARG DISTRIBUTION_IMAGE=docker_app +ARG PHP_IMAGE=ezsystems/php:7.3-v1 +FROM ${DISTRIBUTION_IMAGE} as distrofiles + +FROM ${PHP_IMAGE}-node as builder + +COPY --from=distrofiles /var/www /var/www + +RUN composer config extra.symfony-assets-install hard +RUN composer run-script post-install-cmd --no-interaction + +RUN rm -Rf /var/www/var/cache/*/* + +FROM busybox + +COPY --from=builder /var/www /var/www + +WORKDIR /var/www + +# Fix permissions for www-data +RUN chown -R www-data:www-data var \ + && find var -type d -print0 | xargs -0 chmod -R 775 \ + && find var -type f -print0 | xargs -0 chmod -R 664 + +VOLUME ["/var/www"] diff --git a/doc/docker/Dockerfile-nginx b/doc/docker/Dockerfile-nginx new file mode 100644 index 0000000..b251dc3 --- /dev/null +++ b/doc/docker/Dockerfile-nginx @@ -0,0 +1,44 @@ +ARG PHP_IMAGE=ezsystems/php:7.3-v1 +FROM ${PHP_IMAGE}-node as web-build + +ENV SYMFONY_ENV=prod + +# Copy in project files into work dir +COPY . /var/www + +# Create asset directories that might not exists +RUN if [ ! -d /var/www/web/bundles ]; then mkdir /var/www/web/bundles; fi +RUN if [ ! -d /var/www/web/css ]; then mkdir /var/www/web/css; fi +RUN if [ ! -d /var/www/web/fonts ]; then mkdir /var/www/web/fonts; fi +RUN if [ ! -d /var/www/web/js ]; then mkdir /var/www/web/js; fi +RUN if [ ! -d /var/www/web/assets ]; then mkdir /var/www/web/assets; fi + +# Generate assets using hard copy as we need to copy them over to resulting image +RUN composer config extra.symfony-assets-install hard +RUN composer run-script post-install-cmd --no-interaction + + +# Copy over just the files we want in second stage, so resulting stage only has assets +# and vhost config in as few layers as possible +FROM nginx:stable as web-multilayers + +COPY bin/vhost.sh /var/www/bin/vhost.sh +COPY doc/nginx/vhost.template /var/www/doc/nginx/vhost.template + +# Auto generated assets +COPY --from=web-build /var/www/web/bundles /var/www/web/bundles +COPY --from=web-build /var/www/web/css /var/www/web/css +COPY --from=web-build /var/www/web/fonts /var/www/web/fonts +COPY --from=web-build /var/www/web/js /var/www/web/js + +# User provided assets +COPY --from=web-build /var/www/web/assets /var/www/web/assets + + +# In third stage build the resulting image +FROM nginx:stable + +COPY --from=web-multilayers /var/www /var/www +COPY doc/nginx/ez_params.d /etc/nginx/ez_params.d + +CMD /bin/bash -c "cd /var/www && bin/vhost.sh --template-file=doc/nginx/vhost.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" diff --git a/doc/docker/Dockerfile-solr b/doc/docker/Dockerfile-solr new file mode 100644 index 0000000..e807851 --- /dev/null +++ b/doc/docker/Dockerfile-solr @@ -0,0 +1,22 @@ +FROM solr:6-alpine + +# Copy solr config from the version used by eZ Platform +COPY vendor/ezsystems/ezplatform-solr-search-engine/lib/Resources/config/solr/ /opt/solr/server/tmp + +# Prepare config +RUN mkdir -p /opt/solr/server/ez/template \ + && cp -R /opt/solr/server/tmp/* /opt/solr/server/ez/template \ + && cp /opt/solr/server/solr/configsets/basic_configs/conf/currency.xml /opt/solr/server/ez/template \ + && cp /opt/solr/server/solr/configsets/basic_configs/conf/solrconfig.xml /opt/solr/server/ez/template \ + && cp /opt/solr/server/solr/configsets/basic_configs/conf/stopwords.txt /opt/solr/server/ez/template \ + && cp /opt/solr/server/solr/configsets/basic_configs/conf/synonyms.txt /opt/solr/server/ez/template \ + && cp /opt/solr/server/solr/configsets/basic_configs/conf/elevate.xml /opt/solr/server/ez/template \ + && cp /opt/solr/server/solr/solr.xml /opt/solr/server/ez \ + && sed -i.bak '//,/<\/updateRequestProcessorChain>/d' /opt/solr/server/ez/template/solrconfig.xml \ + && sed -ie 's/${solr.autoSoftCommit.maxTime:-1}/${solr.autoSoftCommit.maxTime:20}/' /opt/solr/server/ez/template/solrconfig.xml + +# Set our core config as home +ENV SOLR_HOME /opt/solr/server/ez + +# Make sure core is created on startup +CMD ["solr-create", "-c", "collection1", "-d", "/opt/solr/server/ez/template"] diff --git a/doc/docker/Dockerfile-vardir b/doc/docker/Dockerfile-vardir new file mode 100644 index 0000000..aff6c4c --- /dev/null +++ b/doc/docker/Dockerfile-vardir @@ -0,0 +1,14 @@ +FROM busybox + +COPY ./web/var /var/www/web/var + +WORKDIR /var/www + +# Fix permissions for www-data +RUN chown -R www-data:www-data web/var \ + && find web/var -type d -print0 | xargs -0 chmod -R 775 \ + && find web/var -type f -print0 | xargs -0 chmod -R 664 + +VOLUME ["/var/www/web/var"] + +CMD ["/bin/true"] diff --git a/doc/docker/Dockerfile-varnish b/doc/docker/Dockerfile-varnish new file mode 100644 index 0000000..14ab852 --- /dev/null +++ b/doc/docker/Dockerfile-varnish @@ -0,0 +1,54 @@ +FROM debian:stretch-slim + +ENV VARNISH_MALLOC_SIZE="256M" \ + DEBIAN_FRONTEND=noninteractive + +ARG PACKAGECLOUD_URL=https://packagecloud.io/install/repositories/varnishcache/varnish60/script.deb.sh +ARG VARNISH_MODULES_VERSION=0.15.0 + +# Use official packages from Varnish and build with varnish-modules mainly for xkey +# see: https://github.com/varnish/varnish-modules/tree/master/docs +RUN set -xe \ + && buildDeps=" \ + make \ + automake \ + autotools-dev \ + libedit-dev \ + libjemalloc-dev \ + libncurses-dev \ + libpcre3-dev \ + libtool \ + pkg-config \ + python-docutils \ + python-sphinx \ + varnish-dev \ + " \ + # Update apt and get dependencies + && apt-get update -q -y \ + && apt-get install -q -y --no-install-recommends ca-certificates curl bc net-tools \ + \ + # Get official Varnish package + && curl -s ${PACKAGECLOUD_URL} | bash \ + && apt-get install -q -y --allow-unauthenticated --no-install-recommends varnish $buildDeps \ + \ + # Install varnish modules + && curl -A "Docker" -o /tmp/varnish-modules.tar.gz -D - -L -s https://download.varnish-software.com/varnish-modules/varnish-modules-${VARNISH_MODULES_VERSION}.tar.gz \ + && tar zxpf /tmp/varnish-modules.tar.gz -C /tmp/ \ + && cd /tmp/varnish-modules-${VARNISH_MODULES_VERSION} \ + && ./configure \ + && make \ + # && make check \ + && make install \ + && rm -f /tmp/varnish-modules.tar.gz && rm -Rf /tmp/varnish-modules \ + \ + # Cleanup apt cache and remove build packages + && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $buildDeps \ + && rm -rf /var/lib/apt/lists/* + +COPY vendor/ezsystems/ezplatform-http-cache/docs/varnish/vcl/varnish5.vcl /etc/varnish/default.vcl +COPY doc/docker/entrypoint/varnish/parameters.vcl /etc/varnish/parameters.vcl +COPY doc/docker/entrypoint/varnish/entrypoint.sh /entrypoint.sh + +EXPOSE 80 6082 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/doc/docker/README.md b/doc/docker/README.md new file mode 100644 index 0000000..cf047d8 --- /dev/null +++ b/doc/docker/README.md @@ -0,0 +1,322 @@ +# Docker blueprints + +Unsupported docker building blocks used for some of our automated functional testing infrastructure at eZ, feel free to +copy it for own use or look to it for some recommended settings. + +**NOTE**: If you are just looking to get easily up and running and developing with eZ Platform, rather look towards +community supported [eZ Launchpad](https://ezsystems.github.io/launchpad/) which is tailored for Project Development use cases. _If not, be +aware of the following limitations:_ + +> **WARNING, made mainly for automation:** The tools within this directory are meant for use for test automation, QA, +Support and demo use cases. And with time as a blueprint for how to best configure your own setup. You are free to use +and adopt this for your needs, and we more than welcome contributions to improve it. + +> **WARNING, low performance on MacOS and Windows:** For reasons mentioned above, these tools are not +optimized for use as development environment with Mac or Windows, and are affected by known I/O performance issues caused +by Docker for Mac/Windows use of shared folders. This is a know issue and nothing we intend to add complexity to workaround here. + +## Overview + +This setup currently requires Docker Compose 1.14 and Docker 17.06 or higher. Defaults are set in `.env`, and +files to ignore are set in `.dockerignore`. By default `.env` specifies that dev setup is used. + +_**NB:** For this and other reasons all docker-compose commands **must** be executed from root of your project directory._ + +#### Before you begin: Install Docker & Docker-Compose + +Before jumping into steps below, make sure you have recent versions of [Docker & Docker-Compose](https://www.docker.com/) +installed on your machine. + +*For Windows you'll also need to [install bash](https://msdn.microsoft.com/en-us/commandline/wsl/about), or adapt instructions below for Windows command line where needed.* + + +#### Concept: Docker Compose "Building blocks" for eZ Platform + +The current Docker Compose files are made to be mixed and matched together for QA/Support use cases. Currently available: +- base-prod.yml _(required, always needs to be first, contains: db, web and app container)_ +- base-dev.yml _(alternative to `base-prod.yml`, same applies here if used)_ +- create-dataset.yml _(optional, to be used together with base-prod.yml in order to set up db and vardir)_ +- demo.yml _(optional, to be used together with base-prod.yml in order to set up db and vardir)_ +- dfs.yml _(optional, adds DFS cluster handler. Note that you need to run the migrate script manually, see below)_ +- blackfire.yml _(optional, adds blackfire service and lets you trigger profiling against the setup)_ +- redis.yml _(optional, adds redis service and appends config to app)_ +- redis-session.yml _(optional, stores sessions in a separate redis instance)_ +- varnish.yml _(optional, adds varnish service and appends config to app)_ +- solr.yml _(optional, add solr service and configure app for it)_ +- selenium.yml _(optional, always needs to be last, adds selenium service and appends config to app)_ +- multihost.yml _(optional, adds multihost config to app container network)_ + + +These can be used with `-f` argument on docker-compose, like: +```bash +docker-compose -f doc/docker/base-prod.yml -f doc/docker/create-dataset.yml -f doc/docker/demo.yml -f doc/docker/redis.yml up -d --force-recreate +``` + +However below environment variable `COMPOSE_FILE` is used instead since this is also what is used to have a default in +`.env` file at root of the project. + + +## Project setup + +### Demo "image" use + +Using this approach, everything will run in containers and volumes. This means that if you for instance upload a image +using the eZ Platform backend, that image will land in a volume, not somewhere below web/var/ in your project directory. + +From root of your projects clone of this distribution, [setup composer auth.json](#composer) and execute the following: +```sh +export COMPOSE_FILE=doc/docker/base-prod.yml:doc/docker/create-dataset.yml:doc/docker/demo.yml + +# Optional step if you'd like to use blackfire with the setup, change and with your own values +#export COMPOSE_FILE=doc/docker/base-prod.yml:doc/docker/create-dataset.yml:doc/docker/demo.yml:doc/docker/blackfire.yml BLACKFIRE_SERVER_ID= BLACKFIRE_SERVER_TOKEN= + +# First time: Install setup, and generate database dump: +docker-compose -f doc/docker/install-dependencies.yml -f doc/docker/install-database.yml up --abort-on-container-exit + +# Optionally, build dbdump and vardir images. +# The dbdump image is created based on doc/docker/entrypoint/mysql/2_dump.sql which is created by above command +# The vardir image is created based on the content of web/var +# If you don't build these image explicitly, they will automaticly be builded later when running `docker-compose up` +docker-compose build dataset-vardir dataset-dbdump + +# Boot up full setup: +docker-compose up -d --force-recreate +``` + +After some 5-10 seconds you should be able to browse the site on `localhost:8080` and the backend on `localhost:8080/admin`. + +### Development "mount" use + +Using this approach, your project directory will be bind mounted into the nginx and php containers. So if you change a +php file in for instance src/, that change will kick in automatically. + +Warning: *Dev setup works a lot faster on Linux then on Windows/Mac where Docker uses virtual machines using shared folders +by default under the hood, which leads to much slower IO performance.* + +From root of your projects clone of this distribution, [setup composer auth.json](#composer) and execute the following: +```sh +# Optional: If you use Docker Machine with NFS, you'll need to specify where project is, & give composer a valid directory. +#export COMPOSE_DIR=/data/SOURCES/MYPROJECTS/ezplatform/doc/docker COMPOSER_HOME=/tmp + +# First time: Install setup, and generate database dump: +docker-compose -f doc/docker/install-dependencies.yml -f doc/docker/install-database.yml up --abort-on-container-exit + +# Boot up full setup: +docker-compose up -d --force-recreate +``` + + +After some 5-10 seconds you should be able to browse the site on `localhost:8080` and the backend on `localhost:8080/admin`. + + +_TIP: If you are seeing 500 errors, or in the case of `SYMFONY_ENV=dev` Database exceptions, then make sure to comment out `database_*` params in `app/config/parameters.yml` to make sure env variables are used correctly._ + +### Behat and Selenium use + +*Docker-Compose setup for Behat use is provided and used internally to test eZ Platform, this can be combined with most +setups, here shown in combination with production setup which is what you'll typically need to test before pushing your +image to Docker Hub/Registry.* + +From root of your projects clone of this distribution, [setup composer auth.json](#composer) and execute the following: +```sh +export COMPOSE_FILE=doc/docker/base-prod.yml:doc/docker/selenium.yml + +# First time: Install setup, and generate database dump: +docker-compose -f doc/docker/install-dependencies.yml -f doc/docker/install-database.yml up --abort-on-container-exit + +# Boot up full setup: +docker-compose up -d --force-recreate +``` + +*Last step is to execute behat scenarios using `app` container which now has access to web and selenium containers, example:* +``` +docker-compose exec --user www-data app sh -c "php /scripts/wait_for_db.php; php bin/behat -vv --profile=rest --suite=fullJson --tags=~@broken" +``` + + +*Tip: You can typically re run the install command to get back to a clean installation in between behat runs using:* +``` +docker-compose exec --user www-data app composer ezplatform-install +``` + +### DFS + +If you want to use the DFS cluster handler, you'll need to run the migration script manually, after starting the +containers ( run `docker-compose up -d --force-create` first). + +The migration script will copy the binary files in web/var to the nfs mount point ( ./dfsdata ) and add the files' +metadata to the database. If your are going to run eZ Platform in a cluster you must then ensure ./dfsdata is a mounted +nfs share on every node/app container. + +``` +# Enter the app container +docker-compose exec --user www-data app /bin/bash + +# Inside app container +php app/console ezplatform:io:migrate-files --from=default,default --to=dfs,nfs --env=prod + +``` + +Once this is done, you may delete web/var/* if you don't intendt to run the migration scripts ever again. + +### Production use + +#### Example: Building app with php image + +In this example we'll build a app image which includes both php (php_fpm) and the eZ Platform application and run them +in a swarm cluster using docker stack. + +Prerequisite: +- A running [swarm cluster](https://docs.docker.com/engine/swarm/swarm-tutorial/) ( a one-node cluster is sufficient for running this example ) +- A running NFS server. How to configure a nfs server is distro dependent, but this [ubuntu guide](https://help.ubuntu.com/community/NFSv4Howto) might be of help +- A running [docker registry](https://docs.docker.com/registry/deploying/#managing-with-compose) (Only required if your swarm cluster has more than one node) + +In this example we assume your swarm manager is named `swarmmanager` and that this hostname resolves on all swarm hosts. We also assume that the nfs server and docker registry are running on `swarmmanager`. + +All the commands below should be executed on your `swarmmanager` + +```sh +# If not already done, install setup, and generate database dump : +docker-compose -f doc/docker/install-dependencies.yml -f doc/docker/install-database.yml up --abort-on-container-exit + +# Build docker_app and docker_web images ( php and nginx ) +docker-compose -f doc/docker/base-prod.yml build --no-cache app web + +# Build varnish image +docker-compose -f doc/docker/base-prod.yml -f doc/docker/varnish.yml build --no-cache varnish + +# Create dataset images ( my-ez-app-dataset-dbdump and my-ez-app-dataset-vardir ) +# The dataset images contains a dump of the database and a dump of the var/ files ( located in web/var ) +docker-compose -f doc/docker/create-dataset.yml build --no-cache + +# Tag the images +docker tag docker_dataset-dbdump swarmmanager:5000/my-ez-app/dataset-dbdump +docker tag docker_dataset-vardir swarmmanager:5000/my-ez-app/dataset-vardir +docker tag docker_web swarmmanager:5000/my-ez-app/web +docker tag docker_app swarmmanager:5000/my-ez-app/app +docker tag docker_varnish swarmmanager:5000/my-ez-app/varnish + +# Upload the images to the registry ( only needed if your swarm cluster has more than one node) +docker push swarmmanager:5000/my-ez-app/dataset-dbdump +docker push swarmmanager:5000/my-ez-app/dataset-vardir +docker push swarmmanager:5000/my-ez-app/web +docker push swarmmanager:5000/my-ez-app/app +docker push swarmmanager:5000/my-ez-app/varnish + +# In this example we run the database in a separate stack so that you may easily have multiple eZ Platform installations using the same database instance +docker stack deploy --compose-file doc/docker/db-stack.yml stack-db + +# Now, wait a half a minute to ensure that the database is ready to accept incomming requests before continuing + +# Now, load the database dump into the db and the var dir to the nfs server +docker-compose -f doc/docker/import-dataset.yml up + +# Finally, create the eZ Platform stack +docker stack deploy --compose-file doc/docker/my-ez-app-stack.yml my-ez-app-stack + +# Cleanup +# If you want to remove the stacks again: +docker stack rm my-ez-app-stack +sleep 15 +docker stack rm stack-db +sleep 15 +docker volume rm my-ez-app-stack_vardir +docker volume rm stack-db_mysql +``` + +#### Example: Separating app and php + +In this alternative way of running eZ Platform, the eZ Platform code and PHP executables are separated in two different +images. The upside of this is that it gets easier to upgrade PHP ( or any other distro applications ) independently +of eZ Platform; simply just replace the PHP container with an updated one without having to rebuild the eZ Platform +image. The downside of this approach is that all eZ Platform code is copied to a volume so that it can be shared with +other containers. This means bigger disk space footprint and longer loading time of the containers. +It is also more complicated to make this approach work with docker stack so only a docker-compose example is provided. + +```sh +export COMPOSE_FILE=doc/docker/base-prod.yml:doc/docker/create-dataset.yml:doc/docker/distribution.yml +# If not already done, install setup, and generate database dump : +docker-compose -f doc/docker/install-dependencies.yml -f doc/docker/install-database.yml up --abort-on-container-exit + +# Build docker_app and docker_web images ( php and nginx ) +# The docker_app image (which contain both php and eZ Platform) will be used as base image when creating the image which +# only contains the eZ Platform files. +docker-compose -f doc/docker/base-prod.yml build --no-cache app + +# Optional, only build the images, do not create containers +docker-compose build --no-cache distribution + +# Note that if you set the environment variable COMPOSE_PROJECT_NAME to a non-default value, you'll need to use set the +# build argument DISTRIBUTION_IMAGE when building the distribution image +docker-compose build --no-cache --build-arg DISTRIBUTION_IMAGE=customprojectname_app distribution + +# Build the "distribution" and dataset images, then start the containers +docker-compose up -d +``` + +## Further info + +### Configuring Composer + +For composer to run correctly as part of the build process, you'll need to create a `auth.json` file in your project root with your github readonly token: + +```sh +echo "{\"github-oauth\":{\"github.com\":\"\"}}" > auth.json +# If you use eZ Enterprise software, also include your updates.ez.no auth token +echo "{\"github-oauth\":{\"github.com\":\"\"},\"http-basic\":{\"updates.ez.no\": {\"username\":\"\",\"password\":\"\",}}}" > auth.json +``` + +For further information on tokens for updates.ez.no, see [doc.ez.no](https://doc.ez.no/display/DEVELOPER/Using+Composer). + + + +### Debugging + +For checking logs from the containers themselves, use `docker-compose logs`. Here on `app` service, but can be omitted to get all: +```sh +docker-compose logs -t app +``` + + +You can login to any of the services using `docker-compose exec`, here shown against `app` image and using `bash`: +```sh +docker-compose exec app /bin/bash +``` + +To display running services: +```sh +docker-compose ps +``` + +### Database dumps + +Database dump is placed in `doc/docker/entrypoint/mysql/`, this folder is used my mysql/mariadb which will execute +everything inside the folder. This means there should only be data represent one install in the folder at any given time. + + +### Updating service images + +To updated the used service images, you can run: +```sh +docker-compose pull --ignore-pull-failures +``` + +This assumed you either use `docker-compose -f` or have `COMPOSE_FILE` defined in cases where you use something else +then defaults in `.env`. + +After this you can re run the production or dev steps to setup containers again with updated images. + +### Cleanup + +Once you are done with your setup, you can stop it, and remove the involved containers. +```sh +docker-compose down -v +``` + +And if you have defined any environment variables you can unset them using: +```sh +unset COMPOSE_FILE COMPOSE_DIR COMPOSER_HOME + +# To unset blackfire variables +unset BLACKFIRE_SERVER_ID BLACKFIRE_SERVER_TOKEN +``` diff --git a/doc/docker/base-dev.yml b/doc/docker/base-dev.yml new file mode 100644 index 0000000..2f817fd --- /dev/null +++ b/doc/docker/base-dev.yml @@ -0,0 +1,64 @@ +version: '3.3' +# Single server setup for dev + +services: + app: + image: ${PHP_IMAGE}-node + volumes: + - ${COMPOSE_DIR}/../../:/var/www:cached + - ${COMPOSER_HOME}:/root/.composer:cached + depends_on: + - db + environment: + - COMPOSER_MEMORY_LIMIT + - EZPLATFORM_SITEACCESS + - PHP_INI_ENV_memory_limit + - SYMFONY_ENV=${SYMFONY_ENV-dev} + - SYMFONY_DEBUG + - SYMFONY_HTTP_CACHE + - SYMFONY_TRUSTED_PROXIES + - DATABASE_USER + - DATABASE_PASSWORD + - DATABASE_NAME + - DATABASE_HOST=db + - RECOMMENDATIONS_CUSTOMER_ID + - RECOMMENDATIONS_LICENSE_KEY + - PUBLIC_SERVER_URI + - HTTPCACHE_VARNISH_INVALIDATE_TOKEN + networks: + - backend + + web: + image: ${NGINX_IMAGE} + volumes: + - ${COMPOSE_DIR}/../../:/var/www:ro,cached + depends_on: + - app + ports: + - "8080:80" + environment: + - SYMFONY_ENV=${SYMFONY_ENV-dev} + - MAX_BODY_SIZE=20 + - FASTCGI_PASS=app:9000 + - TIMEOUT=190 + command: /bin/bash -c "cd /var/www && cp -a doc/nginx/ez_params.d /etc/nginx && bin/vhost.sh --template-file=doc/nginx/vhost.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" + networks: + - frontend + - backend + + db: + image: ${MYSQL_IMAGE} + volumes: + - ${COMPOSE_DIR}/entrypoint/mysql:/docker-entrypoint-initdb.d/:ro,cached + environment: + - MYSQL_RANDOM_ROOT_PASSWORD=1 + - MYSQL_USER=$DATABASE_USER + - MYSQL_PASSWORD=$DATABASE_PASSWORD + - MYSQL_DATABASE=$DATABASE_NAME + - TERM=dumb + networks: + - backend + +networks: + frontend: + backend: diff --git a/doc/docker/base-prod.yml b/doc/docker/base-prod.yml new file mode 100644 index 0000000..cc4faec --- /dev/null +++ b/doc/docker/base-prod.yml @@ -0,0 +1,71 @@ +version: '3.3' +# Simple single server setup for prod + +services: + app: + build: + context: ../../ + dockerfile: ${APP_DOCKER_FILE} + args: + - PHP_IMAGE + depends_on: + - db + environment: + - COMPOSER_MEMORY_LIMIT + - EZPLATFORM_SITEACCESS + - PHP_INI_ENV_memory_limit + - SYMFONY_ENV=${SYMFONY_ENV-prod} + - SYMFONY_DEBUG + - SYMFONY_HTTP_CACHE + - SYMFONY_TRUSTED_PROXIES + - DATABASE_USER + - DATABASE_PASSWORD + - DATABASE_NAME + - DATABASE_HOST=db + - RECOMMENDATIONS_CUSTOMER_ID + - RECOMMENDATIONS_LICENSE_KEY + - PUBLIC_SERVER_URI + - HTTPCACHE_VARNISH_INVALIDATE_TOKEN + networks: + - backend + + web: + build: + context: ../../ + dockerfile: doc/docker/Dockerfile-nginx + args: + - PHP_IMAGE + depends_on: + - app + ports: + - "8080:80" + environment: + - SYMFONY_ENV=${SYMFONY_ENV-prod} + - MAX_BODY_SIZE=20 + - FASTCGI_PASS=app:9000 + - TIMEOUT=190 + networks: + - frontend + - backend + + db: + image: ${MYSQL_IMAGE} + # TODO: Get rid of by having some sort of migration command executed by app container at startup for inserting/updating data (if needed) instead of db dump, as for charset find another way of setting that. + volumes: + - dbdump:/docker-entrypoint-initdb.d/:ro + environment: + - MYSQL_RANDOM_ROOT_PASSWORD=1 + - MYSQL_USER=$DATABASE_USER + - MYSQL_PASSWORD=$DATABASE_PASSWORD + - MYSQL_DATABASE=$DATABASE_NAME + - TERM=dumb + networks: + - backend + +volumes: + vardir: + dbdump: + +networks: + frontend: + backend: diff --git a/doc/docker/blackfire.yml b/doc/docker/blackfire.yml new file mode 100644 index 0000000..03efde1 --- /dev/null +++ b/doc/docker/blackfire.yml @@ -0,0 +1,14 @@ +version: '3.3' +# Blackfire agent config, to be appended after base-prod or base-dev config. +# You'll need to export the two blackfire server variables before you can use this. + +services: + # See: https://blackfire.io/docs/integrations/docker + blackfire: + image: blackfire/blackfire + environment: + # Reads the host BLACKFIRE_SERVER_ID and BLACKFIRE_SERVER_TOKEN environment variables. + - BLACKFIRE_SERVER_ID + - BLACKFIRE_SERVER_TOKEN + networks: + - backend diff --git a/doc/docker/create-dataset.yml b/doc/docker/create-dataset.yml new file mode 100644 index 0000000..3526753 --- /dev/null +++ b/doc/docker/create-dataset.yml @@ -0,0 +1,13 @@ +version: '3.3' +# Config for creating dataset images. To be appended before demo.yml and to be used for generating datasets for prod + +services: + dataset-dbdump: + build: + context: ../../ + dockerfile: doc/docker/Dockerfile-dbdump + + dataset-vardir: + build: + context: ../../ + dockerfile: doc/docker/Dockerfile-vardir diff --git a/doc/docker/db-stack.yml b/doc/docker/db-stack.yml new file mode 100644 index 0000000..2f182dc --- /dev/null +++ b/doc/docker/db-stack.yml @@ -0,0 +1,27 @@ +version: '3.3' +# Config for running mariadb in a docker stack + +services: + db: + image: mariadb:10.1 + volumes: + - ../../doc/docker/entrypoint/mysql/0_database_character_set.sh:/docker-entrypoint-initdb.d/0_database_character_set.sh:ro + - mysql:/var/lib/mysql + environment: + - MYSQL_RANDOM_ROOT_PASSWORD=1 + - MYSQL_USER=ezp + - MYSQL_PASSWORD=SetYourOwnPassword + - MYSQL_DATABASE=ezp + - TERM=dumb + networks: + - db + deploy: + placement: + constraints: [node.role == manager] + +volumes: + mysql: + +networks: + db: + attachable: true diff --git a/doc/docker/demo.yml b/doc/docker/demo.yml new file mode 100644 index 0000000..1df8fbe --- /dev/null +++ b/doc/docker/demo.yml @@ -0,0 +1,28 @@ +version: '3.3' +# Demo config, to be appended after base-prod.yml and create-dataset.yml + +services: + app: + volumes: + - vardir:/var/www/web/var + depends_on: + - dataset-vardir + + web: + volumes: + - vardir:/var/www/web/var:ro + + dataset-vardir: + volumes: + - vardir:/var/www/web/var:ro + networks: + - backend + + dataset-dbdump: + volumes: + - dbdump:/dbdump:ro + networks: + - backend + +volumes: + vardir: diff --git a/doc/docker/dfs.yml b/doc/docker/dfs.yml new file mode 100644 index 0000000..7a123b5 --- /dev/null +++ b/doc/docker/dfs.yml @@ -0,0 +1,20 @@ +version: '3.3' + +services: + app: + environment: + - DFS_NFS_PATH=/dfsdata + depends_on: + - dfsperm + volumes: + - ../../dfsdata:/dfsdata + + web: + environment: + - BINARY_DATA_HANDLER=dfs + + dfsperm: + image: ${PHP_IMAGE} + volumes: + - ../../dfsdata:/dfsdata + command: /bin/bash -c "mkdir -p /dfsdata/var; chown 1000:33 /dfsdata/var" diff --git a/doc/docker/distribution.yml b/doc/docker/distribution.yml new file mode 100644 index 0000000..5841b8a --- /dev/null +++ b/doc/docker/distribution.yml @@ -0,0 +1,96 @@ +version: '3.3' +# Single server setup for prod where we have php executables in one image and a distribution image which contains +# the php code. +# To be appended after base-prod.yml and create-dataset.yml + +services: + distribution: + build: + context: . + dockerfile: Dockerfile-distribution + volumes: + - distribution:/var/www + networks: + - backend + + app: + image: ${PHP_IMAGE} + depends_on: + - db + - distribution + - dataset-vardir + environment: + - SYMFONY_ENV=${SYMFONY_ENV-prod} + - SYMFONY_DEBUG + - SYMFONY_HTTP_CACHE + - SYMFONY_TRUSTED_PROXIES + - DATABASE_USER + - DATABASE_PASSWORD + - DATABASE_NAME + - DATABASE_HOST=db + - RECOMMENDATIONS_CUSTOMER_ID + - RECOMMENDATIONS_LICENSE_KEY + - PUBLIC_SERVER_URI + networks: + - backend + volumes: + - distribution:/var/www + - vardir:/var/www/web/var + + web: + image: ${NGINX_IMAGE} + depends_on: + - distribution + - app + ports: + - "8080:80" + environment: + - SYMFONY_ENV=${SYMFONY_ENV-prod} + - MAX_BODY_SIZE=20 + - FASTCGI_PASS=app:9000 + - TIMEOUT=190 + volumes: + - distribution:/var/www:ro + - vardir:/var/www/web/var:ro + networks: + - frontend + - backend + command: > + /bin/sh -c " + if [ -e /etc/nginx/ez_params.d ]; then rm /etc/nginx/ez_params.d; fi; + cp -a /var/www/doc/nginx/ez_params.d /etc/nginx/ez_params.d; + cd /var/www && bin/vhost.sh --template-file=doc/nginx/vhost.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" + + dataset-vardir: + volumes: + - vardir:/var/www/web/var:ro + networks: + - backend + + dataset-dbdump: + volumes: + - dbdump:/dbdump:ro + networks: + - backend + + db: + image: ${MYSQL_IMAGE} + volumes: + - dbdump:/docker-entrypoint-initdb.d/:ro + environment: + - MYSQL_RANDOM_ROOT_PASSWORD=1 + - MYSQL_USER=$DATABASE_USER + - MYSQL_PASSWORD=$DATABASE_PASSWORD + - MYSQL_DATABASE=$DATABASE_NAME + - TERM=dumb + networks: + - backend + +networks: + frontend: + backend: + +volumes: + vardir: + dbdump: + distribution: diff --git a/doc/docker/entrypoint/mysql/0_database_character_set.sh b/doc/docker/entrypoint/mysql/0_database_character_set.sh new file mode 100755 index 0000000..8450068 --- /dev/null +++ b/doc/docker/entrypoint/mysql/0_database_character_set.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +echo "Altering database, setting character set to utf8mb4" +echo "ALTER DATABASE ${MYSQL_DATABASE} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" | "${mysql[@]}" diff --git a/doc/docker/entrypoint/varnish/entrypoint.sh b/doc/docker/entrypoint/varnish/entrypoint.sh new file mode 100755 index 0000000..8b53cd2 --- /dev/null +++ b/doc/docker/entrypoint/varnish/entrypoint.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +# Script takes the following parameters: +# [--acl-all-networks] - Add all container's network in the PURGE ACL. +# [--acl-add ...] - Add a host or network segment to the PURGE ACL + +function create_template_file +{ + if [ -f /etc/varnish/parameters.vcl.template ]; then + cp /etc/varnish/parameters.vcl.template /etc/varnish/parameters.vcl + else + cp /etc/varnish/parameters.vcl /etc/varnish/parameters.vcl.template + fi +} + +function get_net_segments +{ + for IP_ADDR in `hostname -I`; do + IFS=. read -r io1 io2 io3 io4 <<< "$IP_ADDR" + IFS=. read -r mo1 mo2 mo3 mo4 mo5 < <(ifconfig -a | sed -n "/inet $IP_ADDR /{ s/.*netmask \(.*\) broadcast.*/\1/;p; }") + if [ "$mo1" == "" ]; then + continue; + fi + mb1=$(echo "obase=2;$mo1"|bc) + mb2=$(echo "obase=2;$mo2"|bc) + mb3=$(echo "obase=2;$mo3"|bc) + mb4=$(echo "obase=2;$mo4"|bc) + + NETMASK=`echo $mb1 $mb2 $mb3 $mb4|tr -cd '1' | wc -c` + NET_ADDR="$((io1 & mo1)).$(($io2 & mo2)).$((io3 & mo3)).$((io4 & mo4))" + + echo $NET_ADDR/$NETMASK + done +} + +# $1 is segment, format 1.2.3.4/24 or myhostname +function add_segment +{ + # convert format 1.2.3.4/24 --> "1.2.3.4"/24; + segment=`echo $1 | sed "s|\(.*\)/\(.*\)|\"\1\"/\2;|"` + + # convert format myhost --> "myhost"; ( any string not containing slash ) + segment=`echo $segment | sed -E "s|^([^/]+)\$|\"\1\";|"` + + echo "Adding network segment to varnish ACL : $segment" + sed -i -s "s|\(.*ACL_INVALIDATOR.*\)| $segment\n\1|" /etc/varnish/parameters.vcl +} + +create_template_file + +while (( "$#" )); do + if [ "$1" = "--acl-all-networks" ]; then + segments=`get_net_segments` + + for segment in `echo $segments`; do + add_segment $segment + done + elif [ "$1" = "--acl-add" ]; then + shift + new_network="$1" + + if [ "$new_network" = "" ]; then + echo "Warning : --acl-add parameter needs to be followed by a network segment, for instance \"--acl-add 10.0.1.0/24\"" + else + add_segment $new_network + fi + else + echo "Warning : Unrecognized parameter $1" + fi + + shift +done + +varnishd -F -a :80 -T :6082 -f /etc/varnish/default.vcl -s malloc,${VARNISH_MALLOC_SIZE} diff --git a/doc/docker/entrypoint/varnish/parameters.vcl b/doc/docker/entrypoint/varnish/parameters.vcl new file mode 100644 index 0000000..c3f40c9 --- /dev/null +++ b/doc/docker/entrypoint/varnish/parameters.vcl @@ -0,0 +1,18 @@ +// Custom parameters.vcl for docker use + +backend ezplatform { + .host = "web"; + .port = "80"; +} + +// ACL for invalidators IP +acl invalidators { + "127.0.0.1"; +// ACL_INVALIDATOR +} + +// ACL for debuggers IP +acl debuggers { + "127.0.0.1"; + "172.16.0.0"/20; +} diff --git a/doc/docker/import-dataset.yml b/doc/docker/import-dataset.yml new file mode 100644 index 0000000..f3df06a --- /dev/null +++ b/doc/docker/import-dataset.yml @@ -0,0 +1,65 @@ +version: '3.3' +# Config for importing dataset images into db and nfs server +# Depends on separate stack for db; db-stack.yml + +services: + databasedump: + image: swarmmanager:5000/my-ez-app/dataset-dbdump + volumes: + - type: volume + source: dbdump + target: /dbdump + volume: + nocopy: false + + import-db: + # Using dev for now, because we need mysql client + image: ${PHP_IMAGE_DEV} + environment: + - DATABASE_USER + - DATABASE_PASSWORD + - DATABASE_NAME + - TERM=dumb + networks: + - stack-db_db + volumes: + - type: volume + source: dbdump + target: /dbdump + volume: + nocopy: true + depends_on: + - databasedump + command: > + /bin/bash -c " + time mysql -u $${DATABASE_USER} -p$${DATABASE_PASSWORD} $${DATABASE_NAME} -h db< /dbdump/ezp.sql" + + import-vardir: + image: swarmmanager:5000/my-ez-app/dataset-vardir + volumes: + - vardir:/nfs/vardirs + environment: + - DATASET_VARDIR + command: > + /bin/sh -c " + if [ ! -e /nfs/vardirs/$${DATASET_VARDIR} ]; then + echo Copying files from /var/www/web/var to /nfs/vardirs/$${DATASET_VARDIR}; + mkdir /nfs/vardirs/$${DATASET_VARDIR} && \ + time cp -a /var/www/web/var/ /nfs/vardirs/$${DATASET_VARDIR}; + else + echo Aborted, /nfs/vardirs/$${DATASET_VARDIR} already exists; + exit 2; + fi" + +networks: + stack-db_db: + external: true + +volumes: + dbdump: + vardir: + driver: local + driver_opts: + type: nfs + o: addr=swarmmanager,rw,vers=4.0 + device: ":/vardirs" \ No newline at end of file diff --git a/doc/docker/install-database.yml b/doc/docker/install-database.yml new file mode 100644 index 0000000..d0f49cd --- /dev/null +++ b/doc/docker/install-database.yml @@ -0,0 +1,20 @@ +version: '3.3' +# compose file perform install and dump database. Append after install-dependencies.yml + +services: + install_db: + image: ${MYSQL_IMAGE} + volumes: + - ${COMPOSE_DIR}/entrypoint/mysql:/docker-entrypoint-initdb.d/:ro,cached + environment: + - MYSQL_RANDOM_ROOT_PASSWORD=1 + - MYSQL_USER=$DATABASE_USER + - MYSQL_PASSWORD=$DATABASE_PASSWORD + - MYSQL_DATABASE=$DATABASE_NAME + + install_dependencies: + environment: + - INSTALL_DATABASE=1 + - DATABASE_HOST=install_db + depends_on: + - install_db diff --git a/doc/docker/install-dependencies.yml b/doc/docker/install-dependencies.yml new file mode 100644 index 0000000..0a6bccb --- /dev/null +++ b/doc/docker/install-dependencies.yml @@ -0,0 +1,19 @@ +version: '3.3' +# compose file for installing composer packages + +services: + install_dependencies: + image: ${PHP_IMAGE}-dev + volumes: + - ${COMPOSE_DIR}/../..:/var/www:cached + - ${COMPOSER_HOME}:/root/.composer:cached + environment: + - COMPOSER_MEMORY_LIMIT + - SYMFONY_ENV=${SYMFONY_ENV-prod} + - SYMFONY_DEBUG + - SYMFONY_CMD + - DATABASE_USER + - DATABASE_PASSWORD + - DATABASE_NAME + - COMPOSER_AUTH + command: ./doc/docker/install_script.sh diff --git a/doc/docker/install_script.sh b/doc/docker/install_script.sh new file mode 100755 index 0000000..9702469 --- /dev/null +++ b/doc/docker/install_script.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Dumping autoload using --optimize-autoloader to keep performenace on a usable level, not needed on linux host. +# Second chown line: For dev and behat tests we give a bit extra rights, never do this for prod. + +for i in $(seq 1 3); do + composer install --no-progress --no-interaction --prefer-dist --no-suggest --optimize-autoloader && s=0 && break || s=$? && sleep 1 +done +if [ "$s" != "0" ]; then + echo "ERROR : composer install failed, exit code : $s" + exit $s +fi +mkdir -p web/var + +if [ "${INSTALL_DATABASE}" == "1" ]; then + php /scripts/wait_for_db.php + composer ezplatform-install + if [ "$SYMFONY_CMD" != '' ]; then + echo '> Executing' "$SYMFONY_CMD"; php bin/console $SYMFONY_CMD + fi + echo 'Dumping database into doc/docker/entrypoint/mysql/2_dump.sql for use by mysql on startup.' + mysqldump -u $DATABASE_USER --password=$DATABASE_PASSWORD -h $DATABASE_HOST --add-drop-table --extended-insert --protocol=tcp $DATABASE_NAME > doc/docker/entrypoint/mysql/2_dump.sql +fi; + +rm -Rf var/logs/* var/cache/*/* +chown -R www-data:www-data var/cache var/logs web/var +find var/cache var/logs web/var -type d -print0 | xargs -0 chmod -R 775 +find var/cache var/logs web/var -type f -print0 | xargs -0 chmod -R 664 +chown -R www-data:www-data app/config src diff --git a/doc/docker/multihost.yml b/doc/docker/multihost.yml new file mode 100644 index 0000000..77b5614 --- /dev/null +++ b/doc/docker/multihost.yml @@ -0,0 +1,17 @@ +version: '3.3' +# Multi-host setup for behat tests + +services: + web: + command: /bin/bash -c "cd /var/www && cp -a doc/nginx/ez_params.d /etc/nginx && bin/vhost.sh --host-name=site.example.com --host-alias='admin.example.com test.example.com' --template-file=doc/nginx/vhost.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'" + networks: + frontend: + aliases: + - site.example.com + - admin.example.com + - test.example.com + backend: + aliases: + - site.example.com + - admin.example.com + - test.example.com diff --git a/doc/docker/my-ez-app-stack.yml b/doc/docker/my-ez-app-stack.yml new file mode 100644 index 0000000..bbd3650 --- /dev/null +++ b/doc/docker/my-ez-app-stack.yml @@ -0,0 +1,80 @@ +version: '3.3' +# Config for running eZ Platform using docker stack +# Depends on separate stack for db; db-stack.yml + +services: + web: + image: swarmmanager:5000/my-ez-app/web + ports: + - "8081:80" + environment: + - SYMFONY_ENV + - MAX_BODY_SIZE=20 + - FASTCGI_PASS=app:9000 + - TIMEOUT=190 + volumes: + - vardir:/var/www/web/var + networks: + - my-ez-app + deploy: + replicas: 2 + + app: + image: swarmmanager:5000/my-ez-app/app + environment: + - SYMFONY_ENV=prod + - SYMFONY_DEBUG + - SYMFONY_HTTP_CACHE + - SYMFONY_TRUSTED_PROXIES + - DATABASE_USER=ezp + - DATABASE_PASSWORD=SetYourOwnPassword + - DATABASE_NAME=ezp + - DATABASE_HOST=db + - CUSTOM_CACHE_POOL=singleredis + - CACHE_HOST=redis + - SYMFONY_HTTP_CACHE=0 + - SYMFONY_TRUSTED_PROXIES=varnish + - HTTPCACHE_PURGE_SERVER=http://varnish + - HTTPCACHE_PURGE_TYPE=http + - PHP_INI_ENV_session.save_handler=redis + - PHP_INI_ENV_session.save_path="tcp://redis:6379?weight=1" + - RECOMMENDATIONS_CUSTOMER_ID + - RECOMMENDATIONS_LICENSE_KEY + - PUBLIC_SERVER_URI + volumes: + - vardir:/var/www/web/var + networks: + - stack-db_db + - my-ez-app + deploy: + replicas: 5 + + redis: + image: healthcheck/redis + networks: + - my-ez-app + + varnish: + image: swarmmanager:5000/my-ez-app/varnish + ports: + - "8080:80" + depends_on: + - web + networks: + - my-ez-app + volumes: + - /var/www/vidarl-ezplatform-ee-demo/vscripts:/vscripts + command: --acl-all-networks + +networks: + stack-db_db: + external: true + my-ez-app: + +volumes: + vardir: + driver: local + driver_opts: + type: nfs + o: addr=swarmmanager,rw,vers=4.0 + device: ":/vardirs/my-ez-app/var" diff --git a/doc/docker/redis-session.yml b/doc/docker/redis-session.yml new file mode 100644 index 0000000..b65b992 --- /dev/null +++ b/doc/docker/redis-session.yml @@ -0,0 +1,19 @@ +version: '3.3' +# Config for having sessions in separate redis instance, to be appended after base-prod or base-dev, ..., but before selenium.yml + +## WARNING: +# This service is currently work in progress, is not tested by CI, and thus not guaranteed to work. +# You are however more then welcome to try it out and help make it stable. + +services: + app: + depends_on: + - redis-session + environment: + - SESSION_HANDLER_ID=ezplatform.core.session.handler.native_redis + - SESSION_SAVE_PATH=tcp://redis-session:6379?weight=1 + + redis-session: + image: ${REDIS_IMAGE} + networks: + - backend diff --git a/doc/docker/redis.yml b/doc/docker/redis.yml new file mode 100644 index 0000000..1a0c59c --- /dev/null +++ b/doc/docker/redis.yml @@ -0,0 +1,19 @@ +version: '3.3' +# Redis config, to be appended after base-prod or base-dev, ..., but before selenium.yml + +## WARNING: +# This service is currently work in progress, is not tested by CI, and thus not guaranteed to work. +# You are however more then welcome to try it out and help make it stable. + +services: + app: + depends_on: + - redis + environment: + - CACHE_POOL=cache.redis + - CACHE_DSN=redis:6379 + + redis: + image: ${REDIS_IMAGE} + networks: + - backend diff --git a/doc/docker/selenium.yml b/doc/docker/selenium.yml new file mode 100644 index 0000000..14a345b --- /dev/null +++ b/doc/docker/selenium.yml @@ -0,0 +1,27 @@ +version: '3.3' +# Appends services to prod.yml, prod+dev, prod+redis, ..., always latest + +services: + selenium: + image: ${SELENIUM_IMAGE} + ports: + - "9999:9999" + - "4444:4444" + - "5900:5900" + environment: + - SCREEN_WIDTH=1920 + - SCREEN_HEIGHT=1080 + - SCREEN_DEPTH=24 + - VNC_NO_PASSWORD=1 + networks: + - backend + # Because of: https://github.com/elgalu/docker-selenium/issues/20 + shm_size: '1gb' + + app: + depends_on: + - selenium + environment: + - EZP_TEST_REST_HOST=$WEB_HOST + - BEHAT_SELENIUM_HOST=$SELENIUM_HOST + - BEHAT_WEB_HOST=$WEB_HOST diff --git a/doc/docker/solr.yml b/doc/docker/solr.yml new file mode 100644 index 0000000..55b49f7 --- /dev/null +++ b/doc/docker/solr.yml @@ -0,0 +1,27 @@ +version: '3.3' +# Solr config, to be appended after base-prod or base-dev, ..., but before selenium.yml +# +# NOTE: You'll need to manually reindex the solr index when booting this as we don't have entrypoint for solr yet. +# (Unless you use ezplatform:install command which indexes for you) + +## WARNING! +# This service is currently work in progress, is not tested by CI, and thus not guaranteed to work. +# You are however more then welcome to try it out and help make it stable. + +services: + app: + depends_on: + - solr + environment: + - SEARCH_ENGINE=solr + - SOLR_DSN=http://solr:8983/solr + + solr: + build: + context: ../../ + dockerfile: doc/docker/Dockerfile-solr + ports: + - "8983:8983" + networks: + - frontend + - backend diff --git a/doc/docker/varnish.yml b/doc/docker/varnish.yml new file mode 100644 index 0000000..1c66ae3 --- /dev/null +++ b/doc/docker/varnish.yml @@ -0,0 +1,41 @@ +version: '3.3' +# Simple single server setup for prod + +## WARNING! +# This service is currently work in progress, is not tested by CI, and thus not guaranteed to work. +# You are however more then welcome to try it out and help make it stable. + +services: + app: + environment: + - SYMFONY_HTTP_CACHE=0 + - SYMFONY_TRUSTED_PROXIES=varnish + - HTTPCACHE_PURGE_SERVER=http://varnish + - HTTPCACHE_PURGE_TYPE=http + + varnish: + build: + context: ../../ + dockerfile: doc/docker/Dockerfile-varnish + ports: + - "8081:80" + environment: + - VARNISH_MALLOC_SIZE=256m + depends_on: + - web + - app + networks: + - frontend + - backend + command: ["--acl-add", "app"] + +## DEBUG?? +# In need of debugging all request going to Varnish, use varnishlog, example: +# docker-compose exec varnish varnishlog -c -i ReqURL,ReqMethod -I ReqHeader:xkey +# Or more relevant only PURGE's with all info: +# docker-compose exec varnish varnishlog -g request -q "ReqMethod eq 'PURGE'" +# +# But before doing that check that http and not local purge client is set: +# docker-compose exec app bin/console --env=dev debug:container ezplatform.http_cache.purge_client_internal +# +# And if in prod make sure you have rebuilt app container on code changes ;) diff --git a/doc/i18n/distribute_translations.md b/doc/i18n/distribute_translations.md new file mode 100644 index 0000000..776c83e --- /dev/null +++ b/doc/i18n/distribute_translations.md @@ -0,0 +1,36 @@ +# Distribute translations + +## Introduction + +This documentation is for the eZ Systems team and presents the process of integrating new translations and distributing +them as a package. + +## Merge Crowdin contributions + +When translators contribute to translate the strings you added, [Crowdin][crowdin-ezplatform] will make a huge PR on the +l10n_master branch (or l10n_xx where xx is the target branch). + +You can squash and merge this PR directly on GitHub with the following rules: + +- **Squash commits**: Crowdin does a lot of commits so this is mandatory. +- **Update commit message**: Add an understandable message with the locales translated... +- **DO NOT remove the branch**: Crowdin synchronization is based on it, so if you remove it you break the Crowdin workflow. + +Then when contributions are merged on the target branch, you just need to synchronize the translation packages. + +## Translation packages per language + +To allow users to install only what they need, we have split every language into a dedicated package. + +All translation packages are published on [ezplatform-i18n organisation on github][ezplatform-i18n-org] + +**Important**: these packages are read only, they must be updated with the [eZ Platform i18n git split command][ezplatform-i18n]. + +## Next + +The last step to validate that the translation has been correctly added is to [install the corresponding translation package][install-translation]. + +[crowdin-ezplatform]: https://crowdin.com/project/ezplatform +[ezplatform-i18n-org]: https://github.com/ezplatform-i18n +[ezplatform-i18n]: https://github.com/ezsystems/ezplatform-i18n +[install-translation]: /doc/i18n/install_translation_package.md diff --git a/doc/i18n/handle_translation_in_contribution.md b/doc/i18n/handle_translation_in_contribution.md new file mode 100644 index 0000000..7d7d8a8 --- /dev/null +++ b/doc/i18n/handle_translation_in_contribution.md @@ -0,0 +1,43 @@ +# Translation: How to integrate new strings in your contributions + +## Introduction + +This documentation is for contributors to eZ Platform. It will explain how to format your contribution +to fit in the translation workflow. + +## How to add new strings to be translated + +To ease translators' work we use JMSTranslation which allows us to add a `desc` parameter to translated strings. +This `desc` should contain the default English string and will be displayed to the translator as a help message on Crowdin. + +For example in a twig template it will look like this: + + {{ 'field_definition.description'|trans|desc("Description") }} + +you can even use this feature with `transchoice`: + + {{ 'yes_no'|transchoice(field_definition.isRequired)|desc("{0} No|{1} Yes") }} + +## How to extract new strings from template + +All translations are handled by the repository. So if you add new strings in ezpublish-kernel, you will extract them into +ezpublish-kernel translation files. + +To help you in this task and maintain consistency, we implement a dedicated script. + + bin/extract-translations.sh + +**Important:** you'll notice that all files will be updated at least to change the date attribute. If this is the +only change to a file, please don't commit it. + +**Note:** this script is present in all eZ Systems repositories which handle translations, so you can use the same command +on platform-ui-bundle or repository-forms. + +## What happens next + +At this point, your contributor job is done. When your PR is merged, the eZ Systems team will add your new strings in the +[ezplatform-i18n][ezplatform-i18n] repository so they can be translated. + +[crowdin-ezplatform]: https://crowdin.com/project/ezplatform +[ezplatform-i18n-org]: https://github.com/ezplatform-i18n +[ezplatform-i18n]: https://github.com/ezsystems/ezplatform-i18n diff --git a/doc/i18n/in_context_translation.md b/doc/i18n/in_context_translation.md new file mode 100644 index 0000000..bde203f --- /dev/null +++ b/doc/i18n/in_context_translation.md @@ -0,0 +1,44 @@ +### In-context UI translation + +Since eZ Platform 1.7.0, the interface has been fully translatable. Version 1.8.0 introduces +official support for [crowdin.com](crowdin.com) as a translation management system. In +addition, it integrates support for [in-context translation](in-context), a feature that +allows you to translate strings from the interface, _in context_. + +![In-context translation of Platform UI](https://cloud.githubusercontent.com/assets/235928/21649816/44fc2ea0-d2a3-11e6-8c0e-1b5493ea47e9.png) + +## Toggling in-context translation +To start translating, you need to set a browser cookie. There are several ways to do this, +but we will highlight a couple here. + +### Using the debugging console +One way is to open the development console and run these lines: +- enable: `document.cookie='ez_in_context_translation=1;path=/;'; location.reload();` +- disable: `document.cookie='ez_in_context_translation=;expires=Mon, 05 Jul 2000 00:00:00 GMT;path=/;'; location.reload();` + +### Using bookmarks +You can easily create two bookmarks to toggle in-context on/off. + +Right-click your browser's bookmark bar and create a new one, with the following label and link: +- Enable in-context: `javascript:(function() {document.cookie='ez_in_context_translation=1;path=/;'; location.reload();})()` +- Disable in-context: `javascript:(function() {document.cookie='ez_in_context_translation=;expires=Mon, 05 Jul 2000 00:00:00 GMT;path=/;'; location.reload();})()` + +Then click on the bookmarks from Platform UI to enable/disable in-context. + +## Using in-context translation +The first time you enable in-context, if you're not logged in to Crowdin, it will ask you +to log in or register an account. Once done, it will ask you which language you want to +translate to, from the list of languages configured in Crowdin. + +Choose your language and you can start translating right away. Translatable strings in the +interface will be outlined in red (untranslated), blue (translated) or green (approved). +When moving over them, an edit button will show up in the top left corner of the outline. +Click on it, and edit the string in the window that shows up. + +## Troubleshooting + +Make sure you clear your browser's cache in addition to eZ Platform's. Some of the translation resources +use aggressive HTTP cache. + +[crowdin.com]: https://crowdin.com +[in-context]: https://support.crowdin.com/in-context-localization/ diff --git a/doc/i18n/install_translation_package.md b/doc/i18n/install_translation_package.md new file mode 100644 index 0000000..7f205a2 --- /dev/null +++ b/doc/i18n/install_translation_package.md @@ -0,0 +1,32 @@ +# Install new translation package + +## Introduction + +This documentation is for eZ Platform integrators who realize projects based on eZ Platform. It will present +how to install a new package of translations in your project. + +## Translation packages per language + +To allow users to install only what they need, we have split every language into a dedicated package. + +All translation packages are published on [ezplatform-i18n organisation on github][ezplatform-i18n-org] + +**Important**: these packages are read only, they must be updated with the [eZ Platform i18n git split command][ezplatform-i18n]. + +## Install a new language in your project + +If you want to install a new language in your project, you just have to install the corresponding package. + +For example, if you want to translate your application into Portuguese (pt_PT: the only package supported by our QA team ;)), +you just have to run: + + composer require ezplatform-i18n/ezplatform-i18n-pt_pt + +and then clear the cache. + +Now you can reload your eZ Platform administration page which will be translated in Portuguese (if your browser is +configured to pt_PT.) + +[crowdin-ezplatform]: https://crowdin.com/project/ezplatform +[ezplatform-i18n-org]: https://github.com/ezplatform-i18n +[ezplatform-i18n]: https://github.com/ezsystems/ezplatform-i18n diff --git a/doc/i18n/integrate_new_string_to_translate.md b/doc/i18n/integrate_new_string_to_translate.md new file mode 100644 index 0000000..567c1b7 --- /dev/null +++ b/doc/i18n/integrate_new_string_to_translate.md @@ -0,0 +1,43 @@ +# Integrate new strings to translate + +## Introduction + +This documentation is for the eZ Systems team and presents the process of sending the new strings for translation. + +To be able to provide a single translation project on our translator platform, we gathered all translation +files in a single repository [ezplatform-i18n][ezplatform-i18n] which is synchronized with [Crowdin][crowdin-ezplatform]. + +## Add new strings in ezplatform-i18n + +Before extracting new strings you have to make sure that your eZ Systems bundles are up to date on your eZ Platorm installation. + +Then your project should be in dev mode with development dependencies installed and ezsystems/ezplatform-i18n up to date. + +To synchronize [ezplatform-i18n][ezplatform-i18n] with new translations, we implemented a script which extracts translation files from +ezsystems bundles and formats them to the Crowdin source file format. + +You just have to run this command from the eZ Platform project: + + sh bin/synchronize-translations.sh + +Then make a PR on the [ezplatform-i18n][ezplatform-i18n] repository. + +**Important:** you'll notice that all files will be updated at least to change the date attribute. If this is the +only change to a file, please don't commit it. + +## Add new strings for translation + +At this point, the only thing you have to do to add the new strings in Crowdin is to merge the PR and make sure that +the destination branch is configured as a 'branch for translation' on [Crowdin][crowdin-github-integration]. + +**Note:** you'll notice Crowdin will make a PR to update ach_UG file corresponding to your modification. + +## Next + +You should wait for the translators' work and read the [Distribute translations documentation][distribute-translations] + +[crowdin-ezplatform]: https://crowdin.com/project/ezplatform +[crowdin-github-integration]: https://crowdin.com/project/ezplatform/settings#integration +[ezplatform-i18n-org]: https://github.com/ezplatform-i18n +[ezplatform-i18n]: https://github.com/ezsystems/ezplatform-i18n +[distribute-translations]: /doc/i18n/distribute_translations.md diff --git a/doc/i18n/translation_workflow.md b/doc/i18n/translation_workflow.md new file mode 100644 index 0000000..a7e515d --- /dev/null +++ b/doc/i18n/translation_workflow.md @@ -0,0 +1,35 @@ +# Translation workflow + +## Introduction + +eZ Platform is translated into several languages with the help of [Crowdin](http://crowdin.com). + +This documentation presents the overall concept from contribution to distribution for every participant. + +## Handle translation in your contribution + +This part is for contributors to eZ Platform. It will explain how to format your contribution +to fit in the translation workflow. + +[Handle translation in your contribution](/doc/i18n/handle_translation_in_contribution.md) + +## Integrate new string to translate + +Then these new strings need to be added to the translation process so they can be translated. +This part is for the eZ Systems team and presents the process of sending the new strings for translation. + +[Integrate new string to translate](/doc/i18n/integrate_new_string_to_translate.md) + +## Distribute translations + +When translators are done, it's time to integrate their translations and distribute them. +This part is for the eZ Systems team. + +[Distribute translations](/doc/i18n/distribute_translations.md) + +## Install a translation package + +This documentation is for eZ Platform integrators who realize projects based on eZ Platform. It will present +how to install a new package of translations in your project. + +[Install a translation package](/doc/i18n/install_translation_package.md) diff --git a/doc/logrotate/ezplatform b/doc/logrotate/ezplatform new file mode 100644 index 0000000..3700b51 --- /dev/null +++ b/doc/logrotate/ezplatform @@ -0,0 +1,8 @@ +/var/www/html/*/var/logs/dev.log { + daily + missingok + rotate 5 + size 10M + compress + create 664 www-data www-data +} diff --git a/doc/netgen/FRONTEND.md b/doc/netgen/FRONTEND.md new file mode 100644 index 0000000..413592a --- /dev/null +++ b/doc/netgen/FRONTEND.md @@ -0,0 +1,93 @@ +Netgen Site frontend setup +========================== + +Authors +------- + +* Goran Martinjak +* Marko Žabčić + +Prerequisites +------------- + +* Node JS +* Yarn + +Usage +----- + +In root directory: + +1. `yarn install` to install Node JS packages used by Webpack and the project defined in `package.json` +2. `yarn build:dev` to generate frontend assets used in dev environment (CSS, JavaScript, images...) + + +Using Yarn +---------- + +For packages used on frontend: + +```shell +$ yarn add jquery --save +``` + +For packages used by Webpack: + +```shell +$ yarn add autoprefixer --save-dev +``` + +After adding files, use them as Node JS modules by requiring them in your +`.js` file in `es6` folder, e.g.: + +```javascript +require('swiper'); +``` + +or: + +```javascript +import $ from 'jquery'; +``` + +Read more about [Yarn](https://yarnpkg.com) + +Using Webpack Encore +-------------------- + +Start Webpack Encore with `yarn run encore`. + +To build dev assets use `yarn build:dev` or `yarn encore dev`. +To build minified production assets use `yarn build:prod` or `yarn encore production`. +To build and watch `.sass` and `.js` files for changes use `yarn watch` or `yarn encore dev --watch`. +To start webpack dev server use `yarn server` or `yarn encore dev-server`. + +What Webpack Encore does +------------------------ + +1. Watches `public/sass` and `public/es6` directories if started with `--watch` +2. Compiles Sass and ES6 files +3. Copies all assets (images, fonts...) referenced in CSS to `web/assets/app/build` folder (or `web/assets/app/build_dev` in development environment) +4. Adds vendor prefixes to css (`-moz`, `-webkit` ...) +5. Compiles es6 `.js` files to supported syntax and transpiles required node modules to `app.js` +6. Adds hashes to `manifest.json` for cache busting if building production assets + +eZ Platform +----------- + +Clear cache after adding/removing files. From project root directory execute: + +``` +php bin/console cache:clear +``` + +Conventions +----------- + +Main scss file is `sass/style.scss` + +Resources +--------- + +* [Yarn](https://yarnpkg.com) +* [Webpack Encore](http://symfony.com/doc/current/frontend.html) diff --git a/doc/netgen/INSTALL.md b/doc/netgen/INSTALL.md new file mode 100644 index 0000000..b47d09b --- /dev/null +++ b/doc/netgen/INSTALL.md @@ -0,0 +1,144 @@ +Netgen Site install instructions +================================ + +Software requirements +--------------------- + +* PHP built in server / Apache 2.4+ / Nginx 1.12+ +* MySQL 5.7+ +* PHP 7.1+ (with `gd`, `imagick`, `curl`, `json`, `mysql`, `xsl`, `xml`, `intl` and `mbstring` extensions) +* ImageMagick + +Optional dependencies +--------------------- + +* Varnish 5+ +* Solr 6.5+ + +Installation instructions +------------------------- + +### MySQL database + +Use the following MySQL DDL to create a database which will be used for your project: + +```mysql +CREATE DATABASE CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci; +``` + +### Create the new project based on this repo + +``` +composer create-project netgen/media-site +``` + +Near the end of vendor installation procedure, when asked, be sure to specify +the correct database connection for the site. + +### Generate frontend assets + +Run the following to generate development versions of the assets: + +``` +yarn install +yarn build:dev +``` + +or to build production versions of the assets: + +``` +yarn install +yarn build:prod +``` + +### Note for eZ Platform official WebPack support + +This repo completely replaces the default `webpack.config.js` file coming from eZ Platform with +Netgen Site specific version which is used **only** for frontend of the project. The eZ Systems provided +file is renamed to `webpack.config.ezplatform.js` without changes. + +Also, automatic building of eZ Platform Admin UI assets on every `composer install` or `composer update` +has been disabled so there's no need to install `nodejs` or `yarn` on your production servers to build +those assets. Either deploy them via your deployment procedures, or commit the entire `web/assets` folder +to the git repository. You can build the eZ Platform Admin UI assets on demand simply by executing +`composer ezplatform-assets`. + +If, however, you wish to bring back building eZ Platform Admin UI assets when running Composer, add the +`web/assets/` folder to `.gitignore` and add the following to `symfony-scripts` in your `composer.json`: + +```json +"@php bin/console bazinga:js-translation:dump web/assets --merge-domains", +"yarn install", +"yarn ezplatform" +``` + +Note that you do NOT need to rename `webpack.config.ezplatform.js` back to its old name since +`yarn ezplatform` takes the new name into account. + +More info: https://github.com/ezsystems/ezplatform/pull/392 + +### Import database schema and demo data + +Run the following command to import database schema and demo data (add `--env=prod` +after `bin/console` if running in prod mode): + +``` +php bin/console ezplatform:install +``` + +where `` is the name of wanted site, e.g. `netgen-media`, +or `netgen-media-clean` for the clean version, without demo data. + +### Generate image variations + +If using demo content, it can be quite resource intensive to generate all needed image variations +at request time, especially when demo content uses high quality and high resolution images. + +To overcome this, you can use the following command to generate all image variations for all images: + +``` +php bin/console ngsite:content:generate-image-variations +``` + +This command will take a couple of minutes to complete, so grab a cup of coffee while it's running. + +You can also limit the command only to a subset of image variations, subtrees, content types and +content fields. Use the following command to list all available options: + +``` +php bin/console ngsite:content:generate-image-variations --help +``` + +### Run PHP built in server / Setup Apache virtual host + +For development purposes, you can use PHP built in server to run the site. + +Just start with: + +``` +php bin/console server:run -d web +``` + +Alternatively, you can create a new Apache virtual host and set it up to point +to `web/` directory inside the repo root. + +An example virtual host is available at `doc/apache2/netgen-site-vhost.conf` + +If you wish to use rewrite rules located `.htaccess` file instead of putting +them in virtual host configuration, you can use a virtual host variant located +at `doc/apache2/netgen-site.conf` + +### Setup folder permissions + +You need to setup file and directory permissions so eZ Platform can write to cache, +log and var folders: + +```bash +$ setfacl -R -m u::rwX -m g::rwX var web/var +$ setfacl -dR -m u::rwX -m g::rwX var web/var +``` + +In case `setfacl` is not available on your system, refer to [Symfony installation instructions] +to set up the permissions correctly. + +[Symfony installation instructions]: https://symfony.com/doc/3.4/setup/file_permissions.html diff --git a/doc/netgen/LAUNCHPAD.md b/doc/netgen/LAUNCHPAD.md new file mode 100644 index 0000000..39fb440 --- /dev/null +++ b/doc/netgen/LAUNCHPAD.md @@ -0,0 +1,74 @@ +Netgen Site development with eZ Launchpad and Docker +==================================================== + +Software requirements +--------------------- + +* [Docker](https://docs.docker.com) +* [eZ Launchpad](https://ezsystems.github.io/launchpad/) +* [Yarn](https://yarnpkg.com/en/) + +Installation instructions +------------------------- + +### Docker containers + +First create the directory where you want your Media Site project to live and enter it: + +```bash +mkdir my-project-with-media-site +cd my-project-with-media-site +``` + +Instantiate the Media Site with eZ Launchpad: + +```bash +ez init netgen/media-site CURRENT_VERSION INSTALL_TYPE +``` + +where `netgen/media-site` is the name of Media Site package in Composer, `CURRENT_VERSION` is a version string, e.g. `1.1.3` and `INSTALL_TYPE` +is the type of site to install. Currently there are two options: `netgen-media` that contains demo data and `netgen-media-clean` which has no +demo data at all. Now just select `0` for standard installation and wait for Docker to finish creating containers. + +When the whole process of creating containers is done, eZ Launchpad will print out a very nice report page with all currently running containers. + +### Generate frontend assets + +First enter the project directory: + +```bash +cd ezplatform +``` + +Then run the following to generate development versions of the assets: + +``` +yarn install +yarn build:dev +``` + +or to build production versions of the assets: + +``` +yarn install +yarn build:prod +``` + +Go back to parent directory: + +```bash +cd .. +``` + +### Generate image variations + +If using demo content, it can be quite resource intensive to generate all needed image variations +at request time, especially when demo content uses high quality and high resolution images. + +To overcome this, you can use the following command to generate all image variations for all images: + +``` +ez sfrun ngsite:content:generate-image-variations +``` + +This command will take a couple of minutes to complete, so grab a cup of coffee while it's running. diff --git a/doc/nginx/Readme.md b/doc/nginx/Readme.md new file mode 100644 index 0000000..54f3202 --- /dev/null +++ b/doc/nginx/Readme.md @@ -0,0 +1,90 @@ +NGINX configuration +=================== + +For recommended versions of [NGINX](http://nginx.org/), see [online eZ requirements](https://doc.ez.no/display/TECHDOC/Requirements). + + +Prerequisites +------------- +- Some general knowledge of how to install and configure NGINX. +- A working [PHP FPM](http://php.net/manual/en/install.fpm.php) setup. +- NGINX must be installed, and configured\* to use PHP FPM as fastcgi server. + +\* *Covered by config provided below, but for general info [see online NGINX wiki](https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/)*. + +Configure +--------- +This example is simplified to get you up and running, see [Virtual host template](#virtual-host-template) for more options and details on best practice. + +#### Virtual Host + +1. Place virtualhost config *(example below)* in suitable nginx config folder, typically: + - Debian/Ubuntu: `/etc/nginx/sites-enabled/.conf` + - RHEL/CentOS/Amazon-Linux: `/etc/nginx/conf.d/.conf` +2. Adjust the basics to your setup: + - [listen](http://nginx.org/en/docs/http/ngx_http_core_module.html#listen): IP and port number to listen to. + - [server_name](http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name): Host list, example `ez.no *.ez.no` + - Or for local dev for instance `ezinstall.localhost`, with corresponding entry in your [hosts file](https://en.wikipedia.org/wiki/Hosts_file). + - [root](http://nginx.org/en/docs/http/ngx_http_core_module.html#root): Point this to `web` directory of your eZ installation. + - [fastcgi_pass](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_pass): Socket or TCP address of `php-fpm`. +2. Copy `ez_params.d` directory to folder to you nginx config folder, for examples: + - Debian/Ubuntu: `sudo cp -R doc/nginx/ez_params.d /etc/nginx/` + - RHEL/CentOS/Amazon-Linux: `sudo cp -R doc/nginx/ez_params.d /etc/nginx/` +3. Restart Nginx, normally: `sudo service nginx restart` + +Example config: + + server { + listen 80; + # Further documentation: http://nginx.org/en/docs/http/server_names.html + server_name localhost; + + root /var/www/ezinstall/web; + + # Additional Assetic rules for environments different from dev, + # remember to run php bin/console assetic:dump --env=prod + # and make sure to comment these out in "dev" environment. + include ez_params.d/ez_prod_rewrite_params; + + # Access to repository images in single server setup + include ez_params.d/ez_rewrite_params; + + # upload max size + client_max_body_size 48m; + + location / { + location ~ ^/app\.php(/|$) { + include ez_params.d/ez_fastcgi_params; + + # FPM socket + # Possible values : unix:/var/run/php5-fpm.sock or 127.0.0.1:9000 + fastcgi_pass 127.0.0.1:9000; + + # FPM fastcgi_read_timeout + fastcgi_read_timeout 90s; + + # Environment. + # Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration + # Make sure to comment the "ez_params.d/ez_prod_rewrite_params" include above in dev. + # Defaults to "prod" if omitted + fastcgi_param SYMFONY_ENV prod; + } + + # Disable .php(3) and other executable extensions in the var directory + location ~ ^/var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ { + return 403; + } + } + + include ez_params.d/ez_server_params; + } + + +Virtual host template +--------------------- +This folder contains `vhost.template` file which provides more features you can enable in your virtual host configuration. + +Bash script *(Unix/Linux/OS X)* exists to generate the configuration. To display the help text, execute the following command from your eZ installation root: +```bash +./bin/vhost.sh -h +``` diff --git a/doc/nginx/ez_params.d/ez_fastcgi_params b/doc/nginx/ez_params.d/ez_fastcgi_params new file mode 100644 index 0000000..d30e929 --- /dev/null +++ b/doc/nginx/ez_params.d/ez_fastcgi_params @@ -0,0 +1,23 @@ + +# Including the distribution's default fastcgi parameters +include fastcgi_params; + +fastcgi_buffer_size 128k; +fastcgi_buffers 4 256k; +fastcgi_busy_buffers_size 256k; + +set $fc_script_name "app.php"; + +if ( $uri ~ "^/(.*\.php)" ) { + set $fc_script_name $1; +} + +fastcgi_split_path_info ^(.+\.php)(/.+)$; + +fastcgi_param PATH_INFO $fastcgi_path_info; +fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; +fastcgi_param SCRIPT_NAME $fc_script_name; +fastcgi_param SCRIPT_FILENAME $document_root/$fc_script_name; + +fastcgi_index app.php; + diff --git a/doc/nginx/ez_params.d/ez_legacy_rewrite_params b/doc/nginx/ez_params.d/ez_legacy_rewrite_params new file mode 100644 index 0000000..b832a81 --- /dev/null +++ b/doc/nginx/ez_params.d/ez_legacy_rewrite_params @@ -0,0 +1,5 @@ +rewrite "^/var/([^/]+/)?storage/images(-versioned)?/(.*)" "/var/$1storage/images$2/$3" break; +rewrite "^/var/([^/]+/)?cache/(texttoimage|public)/(.*)" "/var/$1cache/$2/$3" break; +rewrite "^/design/([^/]+)/(stylesheets|images|fonts|javascript)/(.*)" "/design/$1/$2/$3" break; +rewrite "^/share/icons/(.*)" "/share/icons/$1" break; +rewrite "^/extension/([^/]+)/design/([^/]+)/(stylesheets|flash|images||fonts|lib|javascripts?)/(.*)" "/extension/$1/design/$2/$3/$4" break; diff --git a/doc/nginx/ez_params.d/ez_prod_rewrite_params b/doc/nginx/ez_params.d/ez_prod_rewrite_params new file mode 100644 index 0000000..1609cc8 --- /dev/null +++ b/doc/nginx/ez_params.d/ez_prod_rewrite_params @@ -0,0 +1,11 @@ + +# Additional Assetic rules +## Don't forget to run php bin/console assetic:dump --env=prod +## and make sure to comment these out in DEV environment. +rewrite "^/css/(.*)\.css" "/css/$1.css" break; +rewrite "^/js/(.*)\.js" "/js/$1.js" break; +rewrite "^/font(s?)/(.*)\.ttf" "/font$1/$2.ttf" break; +rewrite "^/font(s?)/(.*)\.woff" "/font$1/$2.woff" break; +rewrite "^/font(s?)/(.*)\.otf" "/font$1/$2.otf" break; +rewrite "^/font(s?)/(.*)\.eot" "/font$1/$2.eot" break; +rewrite "^/font(s?)/(.*)\.svg" "/font$1/$2.svg" break; diff --git a/doc/nginx/ez_params.d/ez_rewrite_dfsimage_params b/doc/nginx/ez_params.d/ez_rewrite_dfsimage_params new file mode 100644 index 0000000..eba062a --- /dev/null +++ b/doc/nginx/ez_params.d/ez_rewrite_dfsimage_params @@ -0,0 +1,2 @@ +rewrite "^/var/([^/]+/)?storage/images(-versioned)?/(.*)" "/app.php" break; +rewrite "^/var/([^/]+/)?cache/(texttoimage|public)/(.*)" "/index_cluster.php" break; diff --git a/doc/nginx/ez_params.d/ez_rewrite_image_params b/doc/nginx/ez_params.d/ez_rewrite_image_params new file mode 100644 index 0000000..784ed18 --- /dev/null +++ b/doc/nginx/ez_params.d/ez_rewrite_image_params @@ -0,0 +1,2 @@ +rewrite "^/var/([^/]+/)?storage/images(-versioned)?/(.*)" "/var/$1storage/images$2/$3" break; +rewrite "^/var/([^/]+/)?storage/original/image/(.*)\.svg" "/var/$1storage/original/image/$2.svg" break; diff --git a/doc/nginx/ez_params.d/ez_rewrite_params b/doc/nginx/ez_params.d/ez_rewrite_params new file mode 100644 index 0000000..d12a67c --- /dev/null +++ b/doc/nginx/ez_params.d/ez_rewrite_params @@ -0,0 +1,27 @@ +rewrite "^/var/([^/]+/)?storage/images(-versioned)?/(.*)" "/var/$1storage/images$2/$3" break; +rewrite "^/var/([^/]+/)?storage/original/image/(.*)\.svg" "/var/$1storage/original/image/$2.svg" break; + +# Makes it possible to place your favicon at the root of your +# eZ Platform instance. It will then be served directly. +rewrite "^/favicon\.ico" "/favicon.ico" break; + +# Give direct access to robots.txt for use by crawlers (Google, +# Bing, Spammers..) +rewrite "^/robots\.txt" "/robots.txt" break; + +# Platform for Privacy Preferences Project ( P3P ) related files +# for Internet Explorer +# More info here : http://en.wikipedia.org/wiki/P3p +rewrite "^/w3c/p3p\.xml" "/w3c/p3p.xml" break; + +# Following rule is needed to correctly display bundle and project assets +rewrite "^/bundles/(.*)" "/bundles/$1" break; +rewrite "^/assets/(.*)" "/assets/$1" break; + +# Prevent access to website with direct usage of app.php in URL +if ($request_uri ~ "^/([^/]+/)?app\.php([/?#]|$)") { + return 404; +} + +rewrite "^(.*)$" "/app.php$1" last; + diff --git a/doc/nginx/ez_params.d/ez_server_params b/doc/nginx/ez_params.d/ez_server_params new file mode 100644 index 0000000..c67a00f --- /dev/null +++ b/doc/nginx/ez_params.d/ez_server_params @@ -0,0 +1,7 @@ + +disable_symlinks off; + +location = /favicon.ico { + log_not_found off; + access_log off; +} diff --git a/doc/nginx/netgen-site.conf b/doc/nginx/netgen-site.conf new file mode 100644 index 0000000..cd4cce7 --- /dev/null +++ b/doc/nginx/netgen-site.conf @@ -0,0 +1,83 @@ +server { + listen 80; + listen [::]:80; + # Further documentation: http://nginx.org/en/docs/http/server_names.html + server_name localhost; + + root /var/www/netgensite/web; + + # Cluster/streamed files rewrite rules. Enable on cluster with DFS as a binary data handler + #rewrite "^/var/([^/]+/)?storage/images(-versioned)?/(.*)" "/app.php" break; + #rewrite "^/var/([^/]+/)?cache/(texttoimage|public)/(.*)" "/index_cluster.php" break; + + # Include image rule for DFS or binary handler + # include ez_params.d/ez_rewrite_dfsimage_params; + include ez_params.d/ez_rewrite_image_params; + + # Include remaining ez rewrite rules + include ez_params.d/ez_legacy_rewrite_params; + include ez_params.d/ez_rewrite_params; + + # Let's Encrypt support + rewrite "^/.well-known/acme-challenge/(.*)" "/.well-known/acme-challenge/$1" break; + + # upload max size + client_max_body_size 48m; + + # FPM fastcgi_read_timeout + fastcgi_read_timeout 90s; + + # Gzip is enabled by default on most platforms, so here we just specify mime types to compress. + # NOTE: Using gzip on text/html can be a security issue, unless you somehow pad. See http://breachattack.com + gzip_types text/plain text/css application/json text/javascript application/javascript text/xml application/xml application/xml+rss; + + location / { + location ~ ^/app\.php(/|$) { + include ez_params.d/ez_fastcgi_params; + + # FPM socket + # Possible values : unix:/var/run/php/php7.3-fpm.sock or 127.0.0.1:9000 + fastcgi_pass unix:/var/run/php/php7.3-fpm.sock; + + ## eZ Platform ENVIRONMENT variables, used for customizing app.php execution (not used by console commands) + + # Environment. + # Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration + # Make sure to comment the "ez_params.d/ez_prod_rewrite_params" include above in dev. + # Defaults to "prod" if omitted + fastcgi_param SYMFONY_ENV dev; + + # Whether to use debugging. + # Possible values: 0 or 1 + # Defaults to 0 if omitted, unless SYMFONY_ENV is set to: "dev" + #fastcgi_param SYMFONY_DEBUG "0"; + + # Optional: Whether to use Symfony's builtin HTTP Caching Proxy. + # Disable it if you are using an external reverse proxy (e.g. Varnish) + # Possible values: 0 or 1 + # Defaults to 1 if omitted, unless SYMFONY_ENV is set to: "dev" + #fastcgi_param SYMFONY_HTTP_CACHE "1"; + + # Optional: Defines the proxies to trust + # Needed when using Varnish as proxy, if so disable SYMFONY_HTTP_CACHE. + # Separate entries by a comma, example: "ip1,ip2" + # Defaults to not be set if env value is omitted or empty + #fastcgi_param SYMFONY_TRUSTED_PROXIES "127.0.0.1"; + + # TIP: There are many more environment variables supported by eZ Platform. However unlike those listed above + # they should in most cases rather be set in the environment then in vhost config to make sure cronjobs + # and cli command usage takes them into account as well. + } + + # Disable .php(3) and other executable extensions in the var directory + location ~ ^/var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ { + return 403; + } + } + + # Custom logs + access_log /var/log/nginx/netgensite-access.log; + error_log /var/log/nginx/netgensite-error.log notice; + + include ez_params.d/ez_server_params; +} diff --git a/doc/nginx/vhost.template b/doc/nginx/vhost.template new file mode 100644 index 0000000..a1d4766 --- /dev/null +++ b/doc/nginx/vhost.template @@ -0,0 +1,79 @@ + +server { + listen %PORT%; + # Further documentation: http://nginx.org/en/docs/http/server_names.html + server_name %HOST_LIST%; + + root %BASEDIR%/web; + + # Additional Assetic rules + ## Don't forget to run php bin/console assetic:dump --env=prod + ## and make sure to comment these out in DEV environment. + #if[SYMFONY_ENV!=dev] include ez_params.d/ez_prod_rewrite_params; + + # Include image rule for DFS or binary handler + include ez_params.d/ez_rewrite_%BINARY_DATA_HANDLER%image_params; + + # Include remaining ez rewrite rules + include ez_params.d/ez_rewrite_params; + + # upload max size + client_max_body_size %BODY_SIZE_LIMIT_M%; + + # FPM fastcgi_read_timeout + fastcgi_read_timeout %TIMEOUT_S%; + + # Gzip is enabled by default on most platforms, so here we just specify mime types to compress. + # NOTE: Using gzip on text/html can be a security issue, unless you somehow pad. See http://breachattack.com + gzip_types text/plain text/css application/json text/javascript application/javascript text/xml application/xml application/xml+rss; + + location / { + location ~ ^/app\.php(/|$) { + include ez_params.d/ez_fastcgi_params; + + # FPM socket + # Possible values : unix:/var/run/php5-fpm.sock or 127.0.0.1:9000 + fastcgi_pass %FASTCGI_PASS%; + + ## eZ Platform ENVIRONMENT variables, used for customizing app.php execution (not used by console commands) + + # Environment. + # Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration + # Make sure to comment the "ez_params.d/ez_prod_rewrite_params" include above in dev. + # Defaults to "prod" if omitted + #if[SYMFONY_ENV] fastcgi_param SYMFONY_ENV %SYMFONY_ENV%; + + # Whether to use debugging. + # Possible values: 0 or 1 + # Defaults to 0 if omitted, unless SYMFONY_ENV is set to: "dev" + #if[SYMFONY_DEBUG] fastcgi_param SYMFONY_DEBUG "%SYMFONY_DEBUG%"; + + # Optional: Whether to use Symfony's builtin HTTP Caching Proxy. + # Disable it if you are using an external reverse proxy (e.g. Varnish) + # Possible values: 0 or 1 + # Defaults to 1 if omitted, unless SYMFONY_ENV is set to: "dev" + #if[SYMFONY_HTTP_CACHE] fastcgi_param SYMFONY_HTTP_CACHE "%SYMFONY_HTTP_CACHE%"; + + # Optional: Defines the proxies to trust + # Needed when using Varnish as proxy, if so disable SYMFONY_HTTP_CACHE. + # Separate entries by a comma, example: "ip1,ip2" + # Defaults to not be set if env value is omitted or empty + #if[SYMFONY_TRUSTED_PROXIES] fastcgi_param SYMFONY_TRUSTED_PROXIES "%SYMFONY_TRUSTED_PROXIES%"; + + # TIP: There are many more environment variables supported by eZ Platform. However unlike those listed above + # they should in most cases rather be set in the environment then in vhost config to make sure cronjobs + # and cli command usage takes them into account as well. + } + + # Disable .php(3) and other executable extensions in the var directory + location ~ ^/var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ { + return 403; + } + } + + # Custom logs + # access_log %BASEDIR%/app/logs/httpd-access.log; + # error_log %BASEDIR%/app/logs/httpd-error.log notice; + + include ez_params.d/ez_server_params; +} diff --git a/doc/platformsh/INSTALL.md b/doc/platformsh/INSTALL.md new file mode 100644 index 0000000..6493ddf --- /dev/null +++ b/doc/platformsh/INSTALL.md @@ -0,0 +1,92 @@ +# Install eZ Platform on Platform.sh + +## Installation using eZ Platform template +This is the simplest approach, but may be less up to date with current development than the other, more manual approach. + +### Using eZ Platform Cloud +With eZ Platform Cloud subscription, you are able to create an instance of both open source and Enterprise using templates. In the future it will also enable you to create an instance of eZ Commerce. + +To use eZ Platform Cloud: +1. Log in to [cloud.ezplatform.com](https://cloud.ezplatform.com/) +2. Click Add a project, during setup wizard you'll get the choice to pick a flavor of eZ Platform. +3. Complete the setup wizard, and your eZ Platform site will be created. + +### Using vanilla platform.sh +Using a platform.sh account, you can create an instance of open source version of eZ Platform from template: +1. Login or create an account at [Platform.sh](https://platform.sh) +2. Create a Platform.sh project, using the "Create a blank site from a template" option. Select one of the "eZ Platform" stack templates. +3. Complete the setup wizard, and your eZ Platform site will be created. + +## Manual installation using an eZ Platform Git clone +This requires more manual steps, but may be more up to date with current development than the template-based approach. + +**NB:** Some optional aspects of the installation require you to be project owner on a Platform.sh project. If you create a new project now, you will be. + +1. Log in or create an account at [Platform.sh](https://platform.sh) _(or login to [cloud.ezplatform.com](https://cloud.ezplatform.com/) if you have an subscription)_ +2. Unless this has already been done for you, create a new project by using the **Import your existing code** option. Follow the setup wizard, but halt at the end, before clicking **Finish**. +3. Fork [eZ Platform](https://github.com/ezsystems/ezplatform/) _(or [eZ Platform Enterprise](https://github.com/ezsystems/ezplatform-ee/)/[eZ Commerce](https://github.com/ezsystems/ezcommerce/) if you have a subscription)_ and clone your fork locally. +4. Add the platform remote of your project, and push your branch. The Platform.sh setup wizard provides the command to use. Example: + `git remote add platform my_project@git.eu.platform.sh:my_project.git` +5. [Optional] Authentication against Github/Bitbucket/Gitlab/updates.ez.no for locale development: + If you have private packages from your own git repositories or use eZ Platform Enterprise, you can use Composer's + [auth.json](https://getcomposer.org/doc/articles/http-basic-authentication.md) file or [COMPOSER_AUTH](https://getcomposer.org/doc/03-cli.md#composer-auth) environment variable for this. + Here's an example of `COMPOSER_AUTH` usage to authenticate for eZ Enterprise packages: + `export COMPOSER_AUTH='{"http-basic":{"updates.ez.no":{"username":"network-id","password":"token-key"}}}'` + + Further reading also on [docs.platform.sh](https://docs.platform.sh/tutorials/composer-auth.html#set-the-envcomposerauth-project-variable) +6. [Optional] Set the `env:symfony_env` or `env:COMPOSER_AUTH` project variables by performing the following steps: + 1. Install the Platform.sh CLI according to https://docs.platform.sh/gettingstarted/own-code/cli-install.html + 2. Run `platform` + Run `platform get ` + 3. Authentication against Github/Bitbucket/Gitlab/updates.ez.no + For example set the project variables for your eZ Network installation ID and token: + `platform project:variable:create env:COMPOSER_AUTH '{"http-basic":{"updates.ez.no":{"username":"network-id","password":"token-key"}}}' --no-visible-runtime --sensitive true` + 4. If you have the need to debug things remotely, set the `SYMFONY_ENV` environment variable to 'dev': + `platform project:variable:set env:SYMONY_ENV dev`. +7. Push your branch. The Platform.sh setup wizard provides the command to use. Example: + `git push -u platform master` + This starts the build process. Now, finish the Platform.sh setup wizard. + 1. The build may fail due to mismatching SSH keys. If you are project administrator, verify that your Platform.sh project "Deploy key" (under "Configure project") is included among your GitHub SSH keys: https://github.com/settings/keys If not, copy the deploy key and add it on GitHub using the "New SSH key" button. Then push an empty commit to trigger a Platform.sh rebuild: + `git commit --allow-empty -m'rebuild' && git push` + +# FAQ + +## Can I adjust the platform.sh config? + +Yes, like all configuration (YML/VCL/..) bundled with the eZ Platform installation, all config in the "root project" is yours, and for you to customize for your needs. +The bundled config is a recommended safe default that you can start from, just make sure to make it possible to merge in future config changes when you later need to upgrade. + +## Using Enterprise Dedicated Cluster + +If you are on a Platform.sh Enterprise Dedicated Cluster setup, typically named PE-6 / PE-12 / (...), you'll need to do some adjustment on the platform.sh config and you'll +have dedicated on-boarding where topics around using eZ Platform on this cluster will be gone true before you can deploy to it. + +If you want to read up a bit, look in the bundled platform.sh config. There is a lot of config commented out by default, some of these are explicitly for Dedicated Cluster setup. + +It's recommended to: +- Get platform.sh Support to setup `var/cache` and `var/log` as locale mounts to avoid performance issues _(default on PE Cluster is shared)_ +- Either: + A. Enable eZ Clustered DFS setup _(A **requirement** if you use eZ Publish legacy and legacy bridge, due to shared cache files)_. + B. Stay with a shared mount on `web/var` for storage files _(images, videos, files)_. +- Setup own persisted redis service for sessions, to avoid sessions risking being evicted with cache. + +Tips: +- _As always, with help from Platform.sh Support tune memory/disk size for services (Redis, Solr, ..) to make sure it can handle your traffic and data needs._ +- _For use with Redis and Solr we recommend at a minimum a PE-6+ ("ME-6") instance with additional memory available._ + +## Downgrading services + +Note that if you downgrade certain services like mysql, this can cause your deploy to hang. Contact platform.sh support if this happens and they will downgrade it for you. + +## Re-install Demo + +If you use default config, where database is installed on first deploy and thus have installed eZ Platform or the Enterprise Edition on this Platform.sh instance before, you may need to remove the `web/var/.platform.installed` file to ensure the installation is performed in the deploy stage. + +The symptom for this is when, in the Back Office, you go to **Content** -> **Form** Manager and get an error message or when the "My Drafts Scheduled for Future Publication" and "All Drafts Scheduled for Future Publication" sections on "My Dashboard" do not load. + +To do this, you'll need to remove `web/var/.platform.installed`, either using SSH or using `platform` command: +``` +platform ssh -e [env] 'rm web/var/.platform.installed' +``` + +The next time you trigger a rebuild _(can be done in UI)_, the full install will run. diff --git a/doc/platformsh/README.md b/doc/platformsh/README.md new file mode 100644 index 0000000..0c08dae --- /dev/null +++ b/doc/platformsh/README.md @@ -0,0 +1,16 @@ +# Use eZ Platform on Platform.sh + +## What is Platform.sh? +*Platform.sh* is a continuous deployment cloud hosting solution which can replicate a live production setup in seconds and create byte-level clones of throwaway dev and staging environments, which makes human testing and validation easy. + +## Install +For installation instructions, see [INSTALL.md](https://github.com/ezsystems/ezplatform/blob/master/doc/platformsh/INSTALL.md). + +## Platform.sh configuration files +You need to tweak these files before pushing to platform.sh setup: +- [.platform.app.yaml](https://docs.platform.sh/configuration/app-containers.html) controls your application, including dependencies, build and deployment. +- The `.platform` directory contains Platform.sh service and route settings. +- `app/config/env/platformsh.php` ensures that database, cache, and sessions provided by or configured for Platform.sh is applied in eZ Platform. You should normally not need to change this, but there may be special cases where it is required. + +There are inline comments in these files for choices you should consider, and as stated in [INSTALL.md](https://github.com/ezsystems/ezplatform/blob/master/doc/platformsh/INSTALL.md) +FAQ there are also specific hints if you plan to use Platform.sh Enterprise Dedicated Cluster setup. diff --git a/doc/varnish/varnish.md b/doc/varnish/varnish.md new file mode 100644 index 0000000..2f7df42 --- /dev/null +++ b/doc/varnish/varnish.md @@ -0,0 +1,16 @@ +eZ Platform Varnish configuration +================================= + +Prerequisites +------------- +* A working Varnish 5.1 or higher _(6.0 is a LTS, so the recommended version we test against)_. +* [Varnish xkey module](https://github.com/varnish/varnish-modules/) + +Recommended VCL base files +-------------------------- +Provided VCL for eZ can be found in [vendor/ezsystems/ezplatform-http-cache/docs/varnish](https://github.com/ezsystems/ezplatform-http-cache/tree/0.8/docs/varnish). Specifically `/vcl/varnish5.vcl`. + + +> **Note:** Http cache management is done with the help of [FOSHttpCacheBundle](http://foshttpcachebundle.readthedocs.org/). + One may need to tweak their VCL further on according to [FOSHttpCache documentation](http://foshttpcache.readthedocs.org/en/latest/varnish-configuration.html) + in order to use features supported by it. diff --git a/doc/varnish/vcl/parameters.vcl b/doc/varnish/vcl/parameters.vcl new file mode 100644 index 0000000..00820f6 --- /dev/null +++ b/doc/varnish/vcl/parameters.vcl @@ -0,0 +1,21 @@ +// Our Backend - Assuming that web server is listening on port 80 +// Replace the host to fit your setup +// +// For additional example see: doc/docker/entrypoint/varnish/parameters.vcl + +backend ezplatform { + .host = "127.0.0.1"; + .port = "80"; +} + +// ACL for invalidators IP +acl invalidators { + "127.0.0.1"; + "192.168.0.0"/16; +} + +// ACL for debuggers IP +acl debuggers { + "127.0.0.1"; + "192.168.0.0"/16; +} diff --git a/doc/varnish/vcl/varnish4_xkey.vcl b/doc/varnish/vcl/varnish4_xkey.vcl new file mode 100644 index 0000000..d3e418d --- /dev/null +++ b/doc/varnish/vcl/varnish4_xkey.vcl @@ -0,0 +1,321 @@ +// Varnish VCL for: +// - Varnish 5.1 or higher with xkey vmod (via varnish-modules package, or via Varnish Plus) +// - eZ Platform 2.x or higher (with bundled ezplatform-http-cache package) +// DEPRECATED; please use VCL from https://github.com/ezsystems/ezplatform-http-cache/blob/1.0/docs/varnish/vcl/varnish5.vcl + +vcl 4.0; +import std; +import xkey; + +// For customizing your backend and acl rules see parameters.vcl +include "parameters.vcl"; + +// Called at the beginning of a request, after the complete request has been received +sub vcl_recv { + + // Set the backend + set req.backend_hint = ezplatform; + + // Add a Surrogate-Capability header to announce ESI support. + set req.http.Surrogate-Capability = "abc=ESI/1.0"; + + // Ensure that the Symfony Router generates URLs correctly with Varnish + if (req.http.X-Forwarded-Proto == "https" ) { + set req.http.X-Forwarded-Port = "443"; + } else { + set req.http.X-Forwarded-Port = "80"; + } + + // Trigger cache purge if needed + call ez_purge; + + // Don't cache requests other than GET and HEAD. + if (req.method != "GET" && req.method != "HEAD") { + return (pass); + } + + // Don't cache Authenticate & Authorization + // You may remove this when using REST API with basic auth. + if (req.http.Authenticate || req.http.Authorization) { + if (client.ip ~ debuggers) { + set req.http.X-Debug = "Not Cached according to configuration (Authorization)"; + } + return (hash); + } + + // Remove all cookies besides Session ID, as JS tracker cookies and so will make the responses effectively un-cached + if (req.http.cookie) { + set req.http.cookie = ";" + req.http.cookie; + set req.http.cookie = regsuball(req.http.cookie, "; +", ";"); + set req.http.cookie = regsuball(req.http.cookie, ";(eZSESSID[^=]*)=", "; \1="); + set req.http.cookie = regsuball(req.http.cookie, ";[^ ][^;]*", ""); + set req.http.cookie = regsuball(req.http.cookie, "^[; ]+|[; ]+$", ""); + + if (req.http.cookie == "") { + // If there are no more cookies, remove the header to get page cached. + unset req.http.cookie; + } + } + + // Do a standard lookup on assets (these don't vary by user context hash) + // Note that file extension list below is not extensive, so consider completing it to fit your needs. + if (req.url ~ "\.(css|js|gif|jpe?g|bmp|png|tiff?|ico|img|tga|wmf|svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|zip|gz|pdf|ttf|eot|wof)$") { + return (hash); + } + + // Sort the query string for cache normalization. + set req.url = std.querysort(req.url); + + // Retrieve client user context hash and add it to the forwarded request. + call ez_user_context_hash; + + // If it passes all these tests, do a lookup anyway. + return (hash); +} + +// Called when a cache lookup is successful. The object being hit may be stale: It can have a zero or negative ttl with only grace or keep time left. +sub vcl_hit { + if (obj.ttl >= 0s) { + // A pure unadulterated hit, deliver it + return (deliver); + } + + if (obj.ttl + obj.grace > 0s) { + // Object is in grace, logic below in this block is what differs from default: + // https://varnish-cache.org/docs/5.2/users-guide/vcl-grace.html#grace-mode + if (!std.healthy(req.backend_hint)) { + // Service is unhealthy, deliver from cache + return (deliver); + } else if (req.http.cookie) { + // Request it by a user with session, refresh the cache to avoid issues for editors and forum users + return (miss); + } + + // By default deliver cache, automatically triggers a background fetch + return (deliver); + } + + // fetch & deliver once we get the result + return (miss); +} + +// Called when the requested object has been retrieved from the backend +sub vcl_backend_response { + + if (bereq.http.accept ~ "application/vnd.fos.user-context-hash" + && beresp.status >= 500 + ) { + return (abandon); + } + + // Check for ESI acknowledgement and remove Surrogate-Control header + if (beresp.http.Surrogate-Control ~ "ESI/1.0") { + unset beresp.http.Surrogate-Control; + set beresp.do_esi = true; + } + + // Make Varnish keep all objects for up to 1 hour beyond their TTL, see vcl_hit for Request logic on this + set beresp.grace = 1h; + + // Compressing the content + if (beresp.http.Content-Type ~ "application/javascript" + || beresp.http.Content-Type ~ "application/json" + || beresp.http.Content-Type ~ "application/vnd.ms-fontobject" + || beresp.http.Content-Type ~ "application/vnd.ez.api" + || beresp.http.Content-Type ~ "application/x-font-ttf" + || beresp.http.Content-Type ~ "image/svg+xml" + || beresp.http.Content-Type ~ "text/css" + || beresp.http.Content-Type ~ "text/plain" + ) { + set beresp.do_gzip = true; + } +} + +// Handle purge +// You may add FOSHttpCacheBundle tagging rules +// See http://foshttpcache.readthedocs.org/en/latest/varnish-configuration.html#id4 +sub ez_purge { + // Retrieve purge token, needs to be here due to restart, match for PURGE method done within + call ez_invalidate_token; + + # Support how purging was done in earlier versions, this is deprecated and here just for BC for code still using it + if (req.method == "BAN") { + call ez_purge_acl; + + if (req.http.X-Location-Id) { + ban("obj.http.X-Location-Id ~ " + req.http.X-Location-Id); + if (client.ip ~ debuggers) { + set req.http.X-Debug = "Ban done for content connected to LocationId " + req.http.X-Location-Id; + } + return (synth(200, "Banned")); + } + } + + if (req.method == "PURGE") { + call ez_purge_acl; + + # If http header "key" is set, we assume purge is on key and you have Varnish xkey installed + if (req.http.key) { + # By default we recommend using soft purge to respect grace time, if you need to hard purge use: + # set req.http.n-gone = xkey.purge(req.http.key); + set req.http.n-gone = xkey.softpurge(req.http.key); + + return (synth(200, "Invalidated "+req.http.n-gone+" objects")); + } + + # if not, then this is a normal purge by url + return (purge); + } +} + +sub ez_purge_acl { + if (req.http.x-invalidate-token) { + if (req.http.x-invalidate-token != req.http.x-backend-invalidate-token) { + return (synth(405, "Method not allowed")); + } + } else if (!client.ip ~ invalidators) { + return (synth(405, "Method not allowed")); + } +} + +// Sub-routine to get client user context hash, used to for being able to vary page cache on user rights. +sub ez_user_context_hash { + + // Prevent tampering attacks on the hash mechanism + if (req.restarts == 0 + && (req.http.accept ~ "application/vnd.fos.user-context-hash" + || req.http.x-user-hash + ) + ) { + return (synth(400, "Bad Request")); + } + + if (req.restarts == 0 && (req.method == "GET" || req.method == "HEAD")) { + // Backup accept header, if set + if (req.http.accept) { + set req.http.x-fos-original-accept = req.http.accept; + } + set req.http.accept = "application/vnd.fos.user-context-hash"; + + // Backup original URL + set req.http.x-fos-original-url = req.url; + set req.url = "/_fos_user_context_hash"; + + // Force the lookup, the backend must tell not to cache or vary on all + // headers that are used to build the hash. + return (hash); + } + + // Rebuild the original request which now has the hash. + if (req.restarts > 0 + && req.http.accept == "application/vnd.fos.user-context-hash" + ) { + set req.url = req.http.x-fos-original-url; + unset req.http.x-fos-original-url; + if (req.http.x-fos-original-accept) { + set req.http.accept = req.http.x-fos-original-accept; + unset req.http.x-fos-original-accept; + } else { + // If accept header was not set in original request, remove the header here. + unset req.http.accept; + } + + // Force the lookup, the backend must tell not to cache or vary on the + // user context hash to properly separate cached data. + + return (hash); + } +} + +// Sub-routine to get invalidate token. +sub ez_invalidate_token { + // Prevent tampering attacks on the token mechanisms + if (req.restarts == 0 + && (req.http.accept ~ "application/vnd.ezplatform.invalidate-token" + || req.http.x-backend-invalidate-token + ) + ) { + return (synth(400, "Bad Request")); + } + + if (req.restarts == 0 && req.method == "PURGE" && req.http.x-invalidate-token) { + set req.http.accept = "application/vnd.ezplatform.invalidate-token"; + + set req.url = "/_ez_http_invalidatetoken"; + + // Force the lookup + return (hash); + } + + // Rebuild the original request which now has the invalidate token. + if (req.restarts > 0 + && req.http.accept == "application/vnd.ezplatform.invalidate-token" + ) { + set req.url = "/"; + set req.method = "PURGE"; + unset req.http.accept; + } +} + +sub vcl_deliver { + // On receiving the invalidate token response, copy the invalidate token to the original + // request and restart. + if (req.restarts == 0 + && resp.http.content-type ~ "application/vnd.ezplatform.invalidate-token" + ) { + set req.http.x-backend-invalidate-token = resp.http.x-invalidate-token; + + return (restart); + } + + // On receiving the hash response, copy the hash header to the original + // request and restart. + if (req.restarts == 0 + && resp.http.content-type ~ "application/vnd.fos.user-context-hash" + ) { + set req.http.x-user-hash = resp.http.x-user-hash; + + return (restart); + } + + // If we get here, this is a real response that gets sent to the client. + + // Remove the vary on user context hash, this is nothing public. Keep all + // other vary headers. + if (resp.http.Vary ~ "X-User-Hash") { + set resp.http.Vary = regsub(resp.http.Vary, "(?i),? *X-User-Hash *", ""); + set resp.http.Vary = regsub(resp.http.Vary, "^, *", ""); + if (resp.http.Vary == "") { + unset resp.http.Vary; + } + + // If we vary by user hash, we'll also adjust the cache control headers going out by default to avoid sending + // large ttl meant for Varnish to shared proxies and such. We assume only session cookie is left after vcl_recv. + if (req.http.cookie) { + // When in session where we vary by user hash we by default avoid caching this in shared proxies & browsers + // For browser cache with it revalidating against varnish, use for instance "private, no-cache" instead + set resp.http.cache-control = "private, no-cache, no-store, must-revalidate"; + } else if (resp.http.cache-control ~ "public") { + // For non logged in users we allow caching on shared proxies (mobile network accelerators, planes, ...) + // But only for a short while, as there is no way to purge them + set resp.http.cache-control = "public, s-maxage=600, stale-while-revalidate=300, stale-if-error=300"; + } + } + + if (client.ip ~ debuggers) { + // Add X-Cache header if debugging is enabled + if (obj.hits > 0) { + set resp.http.X-Cache = "HIT"; + set resp.http.X-Cache-Hits = obj.hits; + // For Varnihs 5.1+ you can uncomment this to get debug of remaining TTL + //set resp.http.X-Cache-TTL = obj.ttl; + } else { + set resp.http.X-Cache = "MISS"; + } + } else { + // Remove tag headers when delivering to non debug client + unset resp.http.xkey; + // Sanity check to prevent ever exposing the hash to a non debug client. + unset resp.http.x-user-hash; + } +} diff --git a/ez.webpack.config.js b/ez.webpack.config.js new file mode 100644 index 0000000..633977c --- /dev/null +++ b/ez.webpack.config.js @@ -0,0 +1,39 @@ +const path = require('path'); +const bundles = require('./var/encore/ez.config.js'); +const eZConfigManager = require('./ez.webpack.config.manager.js'); +const configManagers = require('./var/encore/ez.config.manager.js'); + +module.exports = (Encore) => { + Encore.setOutputPath('web/assets/ezplatform/build') + .setPublicPath('/assets/ezplatform/build') + .addExternals({ + react: 'React', + 'react-dom': 'ReactDOM', + jquery: 'jQuery', + moment: 'moment', + 'popper.js': 'Popper', + alloyeditor: 'AlloyEditor', + 'prop-types': 'PropTypes', + }) + .enableSassLoader() + .enableReactPreset() + .enableSingleRuntimeChunk(); + + bundles.forEach((configPath) => { + const addEntries = require(configPath); + + addEntries(Encore); + }); + + const eZConfig = Encore.getWebpackConfig(); + + eZConfig.name = 'ezplatform'; + + configManagers.forEach((configManagerPath) => { + const configManager = require(configManagerPath); + + configManager(eZConfig, eZConfigManager); + }); + + return eZConfig; +}; diff --git a/ez.webpack.config.manager.js b/ez.webpack.config.manager.js new file mode 100644 index 0000000..91ab60f --- /dev/null +++ b/ez.webpack.config.manager.js @@ -0,0 +1,37 @@ +const fs = require('fs'); +const findItems = (eZConfig, entryName) => { + const items = eZConfig.entry[entryName]; + + if (!items) { + throw new Error(`Couldn't find entry with name: "${entryName}". Please check if there is a typo in the name.`); + } + + return items; +}; +const replace = ({ eZConfig, entryName, itemToReplace, newItem }) => { + const items = findItems(eZConfig, entryName); + const indexToReplace = items.indexOf(fs.realpathSync(itemToReplace)); + + if (indexToReplace < 0) { + throw new Error(`Couldn't find item "${itemToReplace}" in entry "${entryName}". Please check if there is a typo in the name.`); + } + + items[indexToReplace] = newItem; +}; +const remove = ({ eZConfig, entryName, itemsToRemove }) => { + const items = findItems(eZConfig, entryName); + const realPathItemsToRemove = itemsToRemove.map((item) => fs.realpathSync(item)); + + eZConfig.entry[entryName] = items.filter((item) => !realPathItemsToRemove.includes(item)); +}; +const add = ({ eZConfig, entryName, newItems }) => { + const items = findItems(eZConfig, entryName); + + eZConfig.entry[entryName] = [...items, ...newItems]; +}; + +module.exports = { + replace, + remove, + add +}; diff --git a/ez.webpack.custom.configs.js b/ez.webpack.custom.configs.js new file mode 100644 index 0000000..2245b86 --- /dev/null +++ b/ez.webpack.custom.configs.js @@ -0,0 +1,12 @@ +const path = require('path'); +const customConfigs = require('./var/encore/ez.webpack.custom.config.js'); + +module.exports = customConfigs.reduce((configs, customConfigPath) => { + let customConfig = require(customConfigPath); + + if (!Array.isArray(customConfig)) { + customConfig = [customConfig]; + } + + return [ ...configs, ...customConfig ]; +}, []); diff --git a/ngsite.cron b/ngsite.cron new file mode 100644 index 0000000..a05b2e5 --- /dev/null +++ b/ngsite.cron @@ -0,0 +1,35 @@ +# This must be set to the directory where eZ Publish is installed. +EZPUBLISHROOT=/path/to/the/ez/publish/directory + +# The command used to call the cronjobs +# In production, add --env=prod after "bin/console" to speed up things a bit +EZPUBLISHSCRIPT=bin/console ezpublish:legacy:script runcronjobs.php + +# Siteaccess used for operations +SITEACCESS=ngadminui + +# Location of the PHP Command Line Interface binary. +PHP=/usr/bin/php + +# Disable sending e-mails +MAILTO="" + +# Instruct cron to run the main set of cronjobs +# at 6:35am every day +35 6 * * * cd $EZPUBLISHROOT && $PHP $EZPUBLISHSCRIPT -q --siteaccess $SITEACCESS 2>&1 + +# Instruct cron to run the "infrequent" set of cronjobs +# at 5:20am every Monday +20 5 * * 1 cd $EZPUBLISHROOT && $PHP $EZPUBLISHSCRIPT -q --siteaccess $SITEACCESS infrequent 2>&1 + +# Instruct cron to run the "frequent" set of cronjobs +# every 15 minutes +*/15 * * * * cd $EZPUBLISHROOT && $PHP $EZPUBLISHSCRIPT -q --siteaccess $SITEACCESS frequent 2>&1 + +# Instruct cron to run the "ezplatformindexsubtree" set of cronjobs +# every 15 minutes +*/15 * * * * cd $EZPUBLISHROOT && $PHP $EZPUBLISHSCRIPT -q --siteaccess $SITEACCESS ezplatformindexsubtree 2>&1 + +# Instruct cron to run the "ezflow" set of cronjobs +# every 5 minutes +*/5 * * * * cd $EZPUBLISHROOT && $PHP $EZPUBLISHSCRIPT -q --siteaccess $SITEACCESS ezflow 2>&1 diff --git a/package.json b/package.json new file mode 100644 index 0000000..ffd8c0e --- /dev/null +++ b/package.json @@ -0,0 +1,63 @@ +{ + "browserslist": { + "defaults": [ + "last 2 versions", + "Safari >= 10", + "iOS >= 10", + "not ie <= 10", + "> 1%" + ], + "evergreen": [ + "last 2 Chrome versions", + "last 2 ChromeAndroid versions", + "last 2 Firefox versions", + "last 2 FirefoxAndroid versions", + "last 2 Safari versions", + "last 2 iOS versions", + "last 2 Edge versions", + "last 2 Opera versions" + ] + }, + "scripts": { + "dev": "encore dev", + "build:dev": "encore dev", + "prod": "encore production", + "build:prod": "encore production", + "watch": "encore dev --watch", + "start": "encore dev-server", + "server": "encore dev-server", + "site:dev": "encore dev --config-name", + "site:prod": "encore production --config-name", + "site:watch": "encore dev --watch --config-name", + "site:server": "encore dev-server --config-name", + "ezplatform": "encore production --config=webpack.config.ezplatform.js" + }, + "private": true, + "devDependencies": { + "@babel/core": "^7.4.3", + "@babel/preset-env": "^7.4.3", + "@babel/preset-react": "^7.0.0", + "@symfony/webpack-encore": "^0.28.0", + "autoprefixer": "^9.5.1", + "eslint": "^5.16.0", + "eslint-config-airbnb": "^17.1.0", + "eslint-plugin-import": "^2.17.2", + "eslint-plugin-jsx-a11y": "^6.2.1", + "eslint-plugin-react": "^7.12.4", + "node-sass": "^4.11.0", + "path": "^0.12.7", + "postcss-loader": "^3.0.0", + "sass-lint": "^1.12.1", + "sass-loader": "^7.1.0" + }, + "dependencies": { + "@babel/polyfill": "^7.4.3", + "@fortawesome/fontawesome-free": "^5.8.1", + "@netgen/javascript-cookie-control": "^0.0.6", + "bootstrap": "^4.3.1", + "jquery": "^3.4.0", + "magnific-popup": "^1.1.0", + "popper.js": "^1.15.0", + "swiper": "^4.5.0" + } +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..5a12e67 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + + + tests + + + + + + src + + src/*Bundle/Resources + src/*/*Bundle/Resources + src/*/Bundle/*Bundle/Resources + + + + diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..a47ef4f --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + autoprefixer: {}, + }, +}; diff --git a/src/.htaccess b/src/.htaccess new file mode 100644 index 0000000..fb1de45 --- /dev/null +++ b/src/.htaccess @@ -0,0 +1,7 @@ + + Require all denied + + + Order deny,allow + Deny from all + diff --git a/src/AppBundle/AppBundle.php b/src/AppBundle/AppBundle.php new file mode 100644 index 0000000..b5bf6bc --- /dev/null +++ b/src/AppBundle/AppBundle.php @@ -0,0 +1,21 @@ +addCompilerPass(new CompilerPass\DisableLegacyContentViewFallbackPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 20); + $container->addCompilerPass(new CompilerPass\XslRegisterPass()); + $container->addCompilerPass(new CompilerPass\DisableVerticalWhitespacePass()); + } +} diff --git a/src/AppBundle/DependencyInjection/AppExtension.php b/src/AppBundle/DependencyInjection/AppExtension.php new file mode 100644 index 0000000..33771a7 --- /dev/null +++ b/src/AppBundle/DependencyInjection/AppExtension.php @@ -0,0 +1,47 @@ +processConfiguration($configuration, $configs); + + $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('services.yml'); + $loader->load('layouts/services.yml'); + } + + public function prepend(ContainerBuilder $container): void + { + $prependConfigs = [ + 'layouts/blocks.yml' => 'netgen_layouts', + 'layouts/block_view.yml' => 'netgen_layouts', + 'layouts/item_view.yml' => 'netgen_layouts', + ]; + + foreach ($prependConfigs as $configFile => $prependConfig) { + $configFile = __DIR__ . '/../Resources/config/' . $configFile; + $config = Yaml::parse(file_get_contents($configFile)); + $container->prependExtensionConfig($prependConfig, $config); + $container->addResource(new FileResource($configFile)); + } + + $configFile = __DIR__ . '/../Resources/config/content_view.yml'; + $config = Yaml::parse(file_get_contents($configFile)); + $container->prependExtensionConfig('ezpublish', ['system' => $config]); + $container->addResource(new FileResource($configFile)); + } +} diff --git a/src/AppBundle/DependencyInjection/CompilerPass/DisableLegacyContentViewFallbackPass.php b/src/AppBundle/DependencyInjection/CompilerPass/DisableLegacyContentViewFallbackPass.php new file mode 100644 index 0000000..a6aa51a --- /dev/null +++ b/src/AppBundle/DependencyInjection/CompilerPass/DisableLegacyContentViewFallbackPass.php @@ -0,0 +1,40 @@ +hasDefinition(self::SiteApiLegacyFallbackContentViewProvider)) { + $container->removeDefinition(self::SiteApiLegacyFallbackContentViewProvider); + } + + if ($container->hasDefinition(self::SiteApiLegacyFallbackLocationViewProvider)) { + $container->removeDefinition(self::SiteApiLegacyFallbackLocationViewProvider); + } + + if ($container->hasDefinition(self::EzPlatformLegacyFallbackContentViewProvider)) { + $container->removeDefinition(self::EzPlatformLegacyFallbackContentViewProvider); + } + + if ($container->hasDefinition(self::EzPlatformLegacyFallbackLocationViewProvider)) { + $container->removeDefinition(self::EzPlatformLegacyFallbackLocationViewProvider); + } + + if ($container->hasDefinition(self::LegacyFallbackApiContentExceptionListener)) { + $container->removeDefinition(self::LegacyFallbackApiContentExceptionListener); + } + } +} diff --git a/src/AppBundle/DependencyInjection/CompilerPass/DisableVerticalWhitespacePass.php b/src/AppBundle/DependencyInjection/CompilerPass/DisableVerticalWhitespacePass.php new file mode 100644 index 0000000..a427e28 --- /dev/null +++ b/src/AppBundle/DependencyInjection/CompilerPass/DisableVerticalWhitespacePass.php @@ -0,0 +1,19 @@ +removeDefinition('ngsite.layouts.block.plugin.vertical_whitespace'); + } +} diff --git a/src/AppBundle/DependencyInjection/CompilerPass/XslRegisterPass.php b/src/AppBundle/DependencyInjection/CompilerPass/XslRegisterPass.php new file mode 100644 index 0000000..1492323 --- /dev/null +++ b/src/AppBundle/DependencyInjection/CompilerPass/XslRegisterPass.php @@ -0,0 +1,34 @@ +getParameter('ezpublish.siteaccess.list') + ); + + // Adding ezxml_tags.xsl to all scopes + foreach ($scopes as $scope) { + if (!$container->hasParameter("ezsettings.{$scope}.fieldtypes.ezxml.custom_xsl")) { + continue; + } + + $xslConfig = $container->getParameter("ezsettings.{$scope}.fieldtypes.ezxml.custom_xsl"); + $xslConfig[] = ['path' => __DIR__ . '/../../Resources/xsl/ezxml_tags.xsl', 'priority' => 10000]; + $container->setParameter("ezsettings.{$scope}.fieldtypes.ezxml.custom_xsl", $xslConfig); + } + } +} diff --git a/src/AppBundle/DependencyInjection/Configuration.php b/src/AppBundle/DependencyInjection/Configuration.php new file mode 100644 index 0000000..ba252b4 --- /dev/null +++ b/src/AppBundle/DependencyInjection/Configuration.php @@ -0,0 +1,23 @@ +root('app'); + + // Here you should define the parameters that are allowed to + // configure your bundle. See the documentation linked above for + // more information on that topic. + + return $treeBuilder; + } +} diff --git a/src/AppBundle/Resources/config/browser.yml b/src/AppBundle/Resources/config/browser.yml new file mode 100644 index 0000000..56fb346 --- /dev/null +++ b/src/AppBundle/Resources/config/browser.yml @@ -0,0 +1,3 @@ +parameters: + netgen_content_browser.ezplatform.item_template: '@@ezdesign/browser/item.html.twig' + netgen_content_browser.ezplatform.preview_template: '@@ezdesign/browser/ngcb_preview.html.twig' diff --git a/src/AppBundle/Resources/config/content_view.yml b/src/AppBundle/Resources/config/content_view.yml new file mode 100644 index 0000000..0013c59 --- /dev/null +++ b/src/AppBundle/Resources/config/content_view.yml @@ -0,0 +1,240 @@ +frontend_group: + ngcontent_view: + full: + ng_category: + template: "@ezdesign/content/full/ng_category.html.twig" + controller: "ngsite.controller.full_view:viewNgCategory" + match: + Identifier\ContentType: ng_category + ng_feedback_form: + template: "@ezdesign/content/full/ng_feedback_form.html.twig" + controller: "netgen_information_collection.controller:displayAndHandle" + match: + Identifier\ContentType: ng_feedback_form + ng_landing_page: + template: "@ezdesign/content/full/ng_landing_page.html.twig" + controller: "ngsite.controller.full_view:viewNgLandingPage" + match: + Identifier\ContentType: ng_landing_page + common: + template: "@ezdesign/content/full/{content_type}.html.twig" + match: + Identifier\ContentType: + - ng_article + - ng_audio + - ng_blog_post + - ng_frontpage + - ng_gallery + - ng_htmlbox + - ng_news + - ng_recipe + - ng_topic + - ng_video + line: + common: + template: "@ezdesign/content/line/{content_type}.html.twig" + match: + Identifier\ContentType: + - file + - ng_article + - ng_audio + - ng_blog_post + - ng_category + - ng_feedback_form + - ng_gallery + - ng_landing_page + - ng_news + - ng_recipe + - ng_video + match_all: + template: "@ezdesign/content/line.html.twig" + match: ~ + listitem: + common: + template: "@ezdesign/content/listitem/{content_type}.html.twig" + params: + with_intro: false + match: + Identifier\ContentType: + - file + - ng_article + - ng_audio + - ng_blog_post + - ng_gallery + - ng_news + - ng_recipe + - ng_video + match_all: + template: "@ezdesign/content/listitem.html.twig" + params: + with_intro: false + match: ~ + listitem_with_intro: + common: + extends: listitem/common + params: + with_intro: true + match_all: + template: "@ezdesign/content/listitem.html.twig" + params: + with_intro: true + match: ~ + standard: + common: + template: "@ezdesign/content/standard/{content_type}.html.twig" + params: + with_intro: false + match: + Identifier\ContentType: + - file + - image + - ng_article + - ng_audio + - ng_banner + - ng_blog_post + - ng_category + - ng_feedback_form + - ng_frontpage + - ng_gallery + - ng_htmlbox + - ng_landing_page + - ng_news + - ng_recipe + - ng_video + match_all: + template: "@ezdesign/content/standard.html.twig" + params: + with_intro: false + match: ~ + standard_with_intro: + common: + extends: standard/common + params: + with_intro: true + match_all: + template: "@ezdesign/content/standard.html.twig" + params: + with_intro: true + match: ~ + mini: + common: + template: "@ezdesign/content/mini/{content_type}.html.twig" + match: + Identifier\ContentType: + - file + - ng_article + - ng_audio + - ng_blog_post + - ng_gallery + - ng_news + - ng_recipe + - ng_video + match_all: + template: "@ezdesign/content/mini.html.twig" + match: ~ + overlay: + common: + template: "@ezdesign/content/overlay/{content_type}.html.twig" + match: + Identifier\ContentType: + - ng_article + - ng_banner + - ng_blog_post + - ng_gallery + - ng_news + - ng_recipe + - ng_video + match_all: + template: "@ezdesign/content/overlay.html.twig" + match: ~ + slide: + common: + template: "@ezdesign/content/slide/{content_type}.html.twig" + match: + Identifier\ContentType: + - image + - ng_article + - ng_banner + - ng_blog_post + - ng_news + - ng_video + match_all: + template: "@ezdesign/content/slide.html.twig" + match: ~ + gallery_thumb: + common: + template: "@ezdesign/content/gallery_thumb/{content_type}.html.twig" + match: + Identifier\ContentType: + - image + - ng_article + - ng_banner + - ng_blog_post + - ng_news + - ng_video + match_all: + template: "@ezdesign/content/gallery_thumb.html.twig" + match: ~ + gallery_grid: + common: + template: "@ezdesign/content/gallery_grid/{content_type}.html.twig" + match: + Identifier\ContentType: + - image + - ng_article + - ng_banner + - ng_blog_post + - ng_news + - ng_video + match_all: + template: "@ezdesign/content/gallery_grid.html.twig" + match: ~ + embed: + image: + template: "@ezdesign/content/embed/image.html.twig" + controller: "ngsite.controller.embed_view:embedImage" + match: + Identifier\ContentType: image + common: + template: "@ezdesign/content/embed/{content_type}.html.twig" + match: + Identifier\ContentType: + - file + - image + - ng_article + - ng_audio + - ng_banner + - ng_blog_post + - ng_category + - ng_feedback_form + - ng_frontpage + - ng_gallery + - ng_htmlbox + - ng_landing_page + - ng_news + - ng_shortcut + - ng_video + match_all: + template: "@ezdesign/content/embed.html.twig" + match: ~ + search: + match_all: + template: "@ezdesign/content/search.html.twig" + match: ~ + +default: + ngcontent_view: + ngcb_preview: + common: + template: "@ezdesign/content/ngcb_preview/{content_type}.html.twig" + match: + Identifier\ContentType: + - image + - ng_article + - ng_audio + - ng_banner + - ng_blog_post + - ng_gallery + - ng_news + - ng_video + - ng_recipe diff --git a/src/AppBundle/Resources/config/ezplatform.yml b/src/AppBundle/Resources/config/ezplatform.yml new file mode 100644 index 0000000..c18f86e --- /dev/null +++ b/src/AppBundle/Resources/config/ezplatform.yml @@ -0,0 +1,37 @@ +imports: + - { resource: parameters.yml } + - { resource: templates.yml } + - { resource: image.yml } + - { resource: opengraph.yml } + - { resource: legacy.yml } + - { resource: info_collection.yml } + - { resource: browser.yml } + +ezpublish: + system: + frontend_group: + pagelayout: "@ezdesign/pagelayout.html.twig" + user: + login_template: "@ezdesign/user/login.html.twig" + +ez_publish_legacy: + system: + frontend_group: + templating: + view_layout: "@ezdesign/pagelayout_legacy.html.twig" + module_layout: "@ezdesign/pagelayout_module.html.twig" + +netgen_tags: + system: + frontend_group: + tag_view: + template: "@ezdesign/tag/view.html.twig" + related_content_list: + limit: 6 + return_content_info: false + +netgen_ez_platform_site_api: + system: + frontend_group: + override_url_alias_view_action: true + diff --git a/src/AppBundle/Resources/config/image.yml b/src/AppBundle/Resources/config/image.yml new file mode 100644 index 0000000..60c9942 --- /dev/null +++ b/src/AppBundle/Resources/config/image.yml @@ -0,0 +1,87 @@ +ezpublish: + system: + default: + image_host: / + image_variations: + i30: + reference: original + filters: + - { name: geometry/scalewidthdownonly, params: [30] } + - { name: strip } + i160: + reference: original + filters: + - { name: geometry/scalewidthdownonly, params: [160] } + - { name: strip } + i320: + reference: original + filters: + - { name: geometry/scalewidthdownonly, params: [320] } + - { name: strip } + i480: + reference: original + filters: + - { name: geometry/scalewidthdownonly, params: [480] } + - { name: strip } + i770: + reference: original + filters: + - { name: geometry/scalewidthdownonly, params: [770] } + - { name: strip } + i1200: + reference: original + filters: + - { name: geometry/scalewidthdownonly, params: [1200] } + - { name: strip } + i1920: + reference: original + filters: + - { name: geometry/scalewidthdownonly, params: [1920] } + - { name: strip } + ngadmin_group: + image_variations: + small: + reference: original + filters: + - { name: geometry/scaledownonly, params: [100, 100] } + - { name: strip } + medium: + reference: original + filters: + - { name: geometry/scaledownonly, params: [200, 200] } + - { name: strip } + large: + reference: original + filters: + - { name: geometry/scaledownonly, params: [300, 300] } + - { name: strip } + +liip_imagine: + filter_sets: + small: + quality: 85 + jpeg_quality: 85 + medium: + quality: 85 + jpeg_quality: 85 + large: + quality: 85 + jpeg_quality: 85 + i30: + quality: 20 + jpeg_quality: 20 + i320: + quality: 85 + jpeg_quality: 85 + i480: + quality: 85 + jpeg_quality: 85 + i770: + quality: 85 + jpeg_quality: 85 + i1200: + quality: 75 + jpeg_quality: 75 + i1920: + quality: 75 + jpeg_quality: 75 diff --git a/src/AppBundle/Resources/config/info_collection.yml b/src/AppBundle/Resources/config/info_collection.yml new file mode 100644 index 0000000..fc5d575 --- /dev/null +++ b/src/AppBundle/Resources/config/info_collection.yml @@ -0,0 +1,14 @@ +netgen_information_collection: + system: + default: + action_config: + email: + templates: + default: "@ezdesign/info_collection/email.html.twig" + default_variables: + sender: "%collected_info_sender%" + recipient: "%collected_info_recipient%" + actions: + default: + - database + - email diff --git a/src/AppBundle/Resources/config/layouts/block_view.yml b/src/AppBundle/Resources/config/layouts/block_view.yml new file mode 100644 index 0000000..a6d9a18 --- /dev/null +++ b/src/AppBundle/Resources/config/layouts/block_view.yml @@ -0,0 +1,55 @@ +system: + frontend_group: + view: + block_view: + default: + title\centered: + template: "@nglayouts/block/title/centered.html.twig" + match: + block\definition: title + block\view_type: title_centered + + title\section: + template: "@nglayouts/block/title/section.html.twig" + match: + block\definition: title + block\view_type: section + + title\section_centered: + template: "@nglayouts/block/title/section_centered.html.twig" + match: + block\definition: title + block\view_type: section_centered + + list\numbered: + template: "@nglayouts/block/list/numbered.html.twig" + match: + block\definition: list + block\view_type: list_numbered + + list\grid_featured: + template: "@nglayouts/block/list/grid_featured.html.twig" + match: + block\definition: list + block\view_type: grid_featured + ajax: + list\numbered: + template: "@nglayouts/block/list/list_ajax.html.twig" + match: + block\definition: list + block\view_type: list_numbered + +view: + block_view: + app: + list\numbered: + template: "@NetgenLayoutsStandard/app/block/list/list.html.twig" + match: + block\definition: list + block\view_type: list_numbered + + list\grid_featured: + template: "@NetgenLayoutsStandard/app/block/list/grid.html.twig" + match: + block\definition: list + block\view_type: grid_featured diff --git a/src/AppBundle/Resources/config/layouts/blocks.yml b/src/AppBundle/Resources/config/layouts/blocks.yml new file mode 100644 index 0000000..a7c658e --- /dev/null +++ b/src/AppBundle/Resources/config/layouts/blocks.yml @@ -0,0 +1,72 @@ +block_definitions: + title: + view_types: + title_centered: + name: 'Title centered' + section: + name: 'Title (section)' + section_centered: + name: 'Title (section centered)' + + list: + view_types: + list: + item_view_types: &list_item_view_types + standard_with_intro: + name: 'Standard (with intro)' + overlay: + name: 'Overlay' + line: + name: 'Line' + mini: + name: 'Mini' + listitem: + name: 'List item' + listitem_with_intro: + name: 'List item (with intro)' + list_numbered: + name: 'List (numbered)' + item_view_types: *list_item_view_types + valid_parameters: ['!number_of_columns'] + grid: + item_view_types: + standard_with_intro: + name: 'Standard (with intro)' + overlay: + name: 'Overlay' + grid_featured: + name: 'Grid (featured)' + item_view_types: + standard: + enabled: false + overlay: + name: 'Overlay' + + gallery: + view_types: + slider: + item_view_types: + standard: + enabled: false + slide: + name: 'Slide' + thumb_gallery: + item_view_types: + standard: + enabled: false + gallery_thumb: + name: 'Gallery thumb' + grid_gallery: + item_view_types: + standard: + enabled: false + gallery_grid: + name: 'Gallery grid' + sushi_bar: + item_view_types: + standard_with_intro: + name: 'Standard (with intro)' + overlay: + name: 'Overlay' + line: + name: 'Line' diff --git a/src/AppBundle/Resources/config/layouts/item_view.yml b/src/AppBundle/Resources/config/layouts/item_view.yml new file mode 100644 index 0000000..f143f0c --- /dev/null +++ b/src/AppBundle/Resources/config/layouts/item_view.yml @@ -0,0 +1,38 @@ +system: + frontend_group: + view: + item_view: + default: + ezcontent\gallery_thumb: + template: "@nglayouts/item/gallery_thumb/ezcontent.html.twig" + match: + item\value_type: ezcontent + item\view_type: gallery_thumb + ezlocation\gallery_thumb: + template: "@nglayouts/item/gallery_thumb/ezlocation.html.twig" + match: + item\value_type: ezlocation + item\view_type: gallery_thumb + ajax: + ezcontent\gallery_thumb: + template: "@nglayouts/item/gallery_thumb/ezcontent.html.twig" + match: + item\value_type: ezcontent + item\view_type: gallery_thumb + ezlocation\gallery_thumb: + template: "@nglayouts/item/gallery_thumb/ezlocation.html.twig" + match: + item\value_type: ezlocation + item\view_type: gallery_thumb + +view: + item_view: + app: + ezcontent\siteapi\override: + template: "@App/nglayouts/app/item/ezcontent.html.twig" + match: + item\value_type: ezcontent + ezlocation\siteapi\override: + template: "@App/nglayouts/app/item/ezlocation.html.twig" + match: + item\value_type: ezlocation diff --git a/src/AppBundle/Resources/config/layouts/services.yml b/src/AppBundle/Resources/config/layouts/services.yml new file mode 100644 index 0000000..fce631c --- /dev/null +++ b/src/AppBundle/Resources/config/layouts/services.yml @@ -0,0 +1,8 @@ +parameters: + ngsite.layouts.block.plugin.background_color.colors: + primary: 'block.plugin.background_color.primary' + secondary: 'block.plugin.background_color.secondary' + white: 'block.plugin.background_color.white' + black: 'block.plugin.background_color.black' + +services: diff --git a/src/AppBundle/Resources/config/legacy.yml b/src/AppBundle/Resources/config/legacy.yml new file mode 100644 index 0000000..e2a1f41 --- /dev/null +++ b/src/AppBundle/Resources/config/legacy.yml @@ -0,0 +1,101 @@ +netgen_site_legacy: + system: + frontend_group: + injected_settings: + site.ini: + # The following parameter need to be "false" string + # since eZ legacy config uses string as config, as opposed to booleans + SiteAccessSettings/RequireUserLogin: "false" + injected_merge_settings: + site.ini: + SiteAccessRules/Rules: + - access;disable + - module;content/advancedsearch + + ngadminui: + injected_settings: + site.ini: + DesignSettings/SiteDesign: ngadminui + + legacy_admin: + injected_settings: + site.ini: + DesignSettings/SiteDesign: admin + + default: + injected_merge_settings: + site.ini: + ExtensionSettings/ActiveExtensions: + - app + - nglayouts + - ezplatformsearch + - ezrichtext + - ngadminui + - ngsymfonytools + - ngsite + - ngclasslist + - xrowmetadata + - birthday + - hideuntildate + - ezclasslists + - ezchangeclass + - enhancedselection2 + - ezmultiupload + - eztags + - ezjscore + - ezstarrating + - ezgmaplocation + - ezdemo + - ezoe + + injected_settings: + content.ini: + ClassGroupIDs/Media: 2 + ClassGroupIDs/Users: 3 + # Setup class group was deleted long ago, this makes sure + # it doesn't mess up custom groups that have its' old ID + ClassGroupIDs/Setup: -1 + + site.ini: + DatabaseSettings/Charset: "utf8mb4" + SiteSettings/DefaultAccess: "%ezpublish.siteaccess.default%" + SiteSettings/SiteList: "%ezpublish.siteaccess.list%" + SiteSettings/RootNodeDepth: 1 + SiteSettings/SiteURL: "%ngsite.default.site_domain%" + SiteSettings/MetaDataArray: "%ngsite.default.site_settings.meta_data%" + + SiteAccessSettings/AvailableSiteAccessList: "%ezpublish.siteaccess.list%" + SiteAccessSettings/RemoveSiteAccessIfDefaultAccess: enabled + # The following two parameters need to be "true" and "false" strings + # since eZ legacy config uses those, as opposed to booleans + SiteAccessSettings/ForceVirtualHost: "true" + SiteAccessSettings/CheckValidity: "false" + + Session/SessionNameHandler: custom + UserSettings/LogoutRedirect: / + + SiteAccessRules/Rules: + - access;disable + - module;user/register + - module;user/activate + - module;user/unactivated + - module;user/success + - module;user/forgotpassword + - module;ezinfo/about + - module;ezinfo/copyright + - module;content/tipafriend + - module;settings/edit + - module;layout + - module;visual + - module;shop + + DesignSettings/SiteDesign: standard + DesignSettings/DesignLocationCache: enabled + + MailSettings/Transport: "%mailer_transport%" + MailSettings/TransportServer: "%mailer_host%" + MailSettings/TransportPort: "%mailer_port%" + MailSettings/TransportUser: "%mailer_user%" + MailSettings/TransportPassword: "%mailer_password%" + MailSettings/AdminEmail: "%ngsite.default.mail.sender_email%" + MailSettings/EmailSender: "%ngsite.default.mail.sender_email%" diff --git a/src/AppBundle/Resources/config/opengraph.yml b/src/AppBundle/Resources/config/opengraph.yml new file mode 100644 index 0000000..9dd0347 --- /dev/null +++ b/src/AppBundle/Resources/config/opengraph.yml @@ -0,0 +1,39 @@ +netgen_open_graph: + system: + frontend_group: + global_handlers: + - { handler: ngsite/site_name, tag: "og:site_name" } + content_type_handlers: + ng_frontpage: + - { handler: literal/text, tag: "og:type", params: [website] } + - { handler: ngsite/site_name, tag: "og:title" } + - { handler: ngsite/site_name, tag: "og:description" } + - { handler: ngsite/site_image, tag: "og:image" } + ng_landing_page: + - { handler: literal/text, tag: "og:type", params: [website] } + - { handler: field_type/ezstring, tag: "og:title", params: [title] } + - { handler: ngsite/site_image, tag: "og:image" } + ng_category: + - { handler: literal/text, tag: "og:type", params: [website] } + - { handler: field_type/ezstring, tag: "og:title", params: [title] } + - { handler: field_type/ezxmltext, tag: "og:description", params: [full_intro] } + ng_article: + - { handler: literal/text, tag: "og:type", params: [article] } + - { handler: field_type/ezstring, tag: "og:title", params: [title] } + - { handler: field_type/ezxmltext, tag: "og:description", params: [full_intro] } + - { handler: field_type/ezimage, tag: "og:image", params: [image, i1200] } + ng_news: + - { handler: literal/text, tag: "og:type", params: [article] } + - { handler: field_type/ezstring, tag: "og:title", params: [title] } + - { handler: field_type/ezxmltext, tag: "og:description", params: [full_intro] } + - { handler: field_type/ezimage, tag: "og:image", params: [image, i1200] } + ng_blog_post: + - { handler: literal/text, tag: "og:type", params: [article] } + - { handler: field_type/ezstring, tag: "og:title", params: [title] } + - { handler: field_type/ezxmltext, tag: "og:description", params: [full_intro] } + - { handler: field_type/ezimage, tag: "og:image", params: [image, i1200] } + ng_feedback_form: + - { handler: literal/text, tag: "og:type", params: [article] } + - { handler: field_type/ezstring, tag: "og:title", params: [title] } + - { handler: field_type/ezxmltext, tag: "og:description", params: [full_intro] } + - { handler: ngsite/site_image, tag: "og:image" } diff --git a/src/AppBundle/Resources/config/parameters.yml b/src/AppBundle/Resources/config/parameters.yml new file mode 100644 index 0000000..8c8f7e4 --- /dev/null +++ b/src/AppBundle/Resources/config/parameters.yml @@ -0,0 +1,17 @@ +parameters: + ngsite.default.search.content_types: + - ng_blog_post + - ng_article + - ng_news + - ng_category + - ng_feedback_form + - ng_landing_page + - ng_video + - ng_audio + - file + + netgen_admin_ui.default.legacy_routes: [ez_urlalias, ngsite_content_search] + + ngsite.default.lazy_loading.enabled: true + ngsite.default.lazy_loading.initial_image_alias: 'i30' + ngsite.default.render_content_directly: true diff --git a/src/AppBundle/Resources/config/routing.yml b/src/AppBundle/Resources/config/routing.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/AppBundle/Resources/config/services.yml b/src/AppBundle/Resources/config/services.yml new file mode 100644 index 0000000..33d1cf6 --- /dev/null +++ b/src/AppBundle/Resources/config/services.yml @@ -0,0 +1,10 @@ +parameters: + +services: + ngsite.layouts.block.plugin.vertical_whitespace_v2: + class: Netgen\Bundle\SiteBundle\Layouts\Block\Plugin\VerticalWhitespaceV2Plugin + arguments: + - "%ngsite.layouts.block.plugin.vertical_whitespace.top%" + - "%ngsite.layouts.block.plugin.vertical_whitespace.bottom%" + tags: + - { name: netgen_layouts.block_definition_handler.plugin, priority: 200 } diff --git a/src/AppBundle/Resources/config/templates.yml b/src/AppBundle/Resources/config/templates.yml new file mode 100644 index 0000000..de2e403 --- /dev/null +++ b/src/AppBundle/Resources/config/templates.yml @@ -0,0 +1,38 @@ +parameters: + ngsite.default.template.user.activate: "@@ezdesign/user/activate.html.twig" + ngsite.default.template.user.activate_done: "@@ezdesign/user/activate_done.html.twig" + ngsite.default.template.user.activate_sent: "@@ezdesign/user/activate_sent.html.twig" + ngsite.default.template.user.activate_admin_activation_pending: "@@ezdesign/user/activate_admin_activation_pending.html.twig" + + ngsite.default.template.user.forgot_password: "@@ezdesign/user/forgot_password.html.twig" + ngsite.default.template.user.forgot_password_sent: "@@ezdesign/user/forgot_password_sent.html.twig" + + ngsite.default.template.user.register: "@@ezdesign/user/register.html.twig" + ngsite.default.template.user.register_success: "@@ezdesign/user/register_success.html.twig" + + ngsite.default.template.user.reset_password: "@@ezdesign/user/reset_password.html.twig" + ngsite.default.template.user.reset_password_done: "@@ezdesign/user/reset_password_done.html.twig" + + ngsite.default.template.user.mail.activate: "@@ezdesign/user/mail/activate.html.twig" + ngsite.default.template.user.mail.activate_already_active: "@@ezdesign/user/mail/activate_already_active.html.twig" + ngsite.default.template.user.mail.activate_disabled: "@@ezdesign/user/mail/activate_disabled.html.twig" + ngsite.default.template.user.mail.activate_not_registered: "@@ezdesign/user/mail/activate_not_registered.html.twig" + ngsite.default.template.user.mail.activate_admin_activation_pending: "@@ezdesign/user/mail/activate_admin_activation_pending.html.twig" + ngsite.default.template.user.mail.activate_admin_activation_required: "@@ezdesign/user/mail/activate_admin_activation_required.html.twig" + + ngsite.default.template.user.mail.forgot_password: "@@ezdesign/user/mail/forgot_password.html.twig" + ngsite.default.template.user.mail.forgot_password_disabled: "@@ezdesign/user/mail/forgot_password_disabled.html.twig" + ngsite.default.template.user.mail.forgot_password_not_active: "@@ezdesign/user/mail/forgot_password_not_active.html.twig" + ngsite.default.template.user.mail.forgot_password_not_registered: "@@ezdesign/user/mail/forgot_password_not_registered.html.twig" + ngsite.default.template.user.mail.forgot_password_password_changed: "@@ezdesign/user/mail/forgot_password_password_changed.html.twig" + + ngsite.default.template.user.mail.welcome: "@@ezdesign/user/mail/welcome.html.twig" + + ngsite.default.template.errors.403: "@@ezdesign/errors/403.html.twig" + ngsite.default.template.errors.404: "@@ezdesign/errors/404.html.twig" + ngsite.default.template.errors.500: "@@ezdesign/errors/500.html.twig" + ngsite.default.template.errors.default: "@@ezdesign/errors/default.html.twig" + + ngsite.default.template.search: "@@ezdesign/search/search.html.twig" + + ngsite.default.template.menu: '@@ezdesign/menu.html.twig' diff --git a/src/AppBundle/Resources/es6/app.js b/src/AppBundle/Resources/es6/app.js new file mode 100644 index 0000000..96c9fef --- /dev/null +++ b/src/AppBundle/Resources/es6/app.js @@ -0,0 +1,8 @@ +import '@babel/polyfill'; +import $ from 'jquery'; +import './ngsite'; +import '../sass/style.scss'; + +$(() => { + // Put your code here +}); diff --git a/src/AppBundle/Resources/es6/ngsite.js b/src/AppBundle/Resources/es6/ngsite.js new file mode 100644 index 0000000..1d230fd --- /dev/null +++ b/src/AppBundle/Resources/es6/ngsite.js @@ -0,0 +1,276 @@ +/* globals jwplayer */ +import $ from 'jquery'; +import 'magnific-popup'; +import Swiper from 'swiper/dist/js/swiper'; +import 'bootstrap'; +import CookieControl from '@netgen/javascript-cookie-control'; + +global.$ = global.jQuery = $; // eslint-disable-line no-multi-assign +global.Swiper = Swiper; + +/* CHECK WHEN ELEMENT IS IN VIEWPORT -----------------------------------------------*/ +(() => { + function isElementInViewport(element) { + // special bonus for those using jQuery + const el = typeof $ === 'function' && element instanceof $ ? element[0] : element; + + const rect = el.getBoundingClientRect(); + return ( + rect.top >= 0 + && rect.left >= 0 + && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + && rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); + } + + window.isElementInViewport = isElementInViewport; + + let to; + $(window).on('scroll', () => { + if (to) clearTimeout(to); + to = setTimeout(() => { + $(window).trigger('scroll:end'); + }, 200); + }); + + $.fn.in_viewport = function (cb) { + return $(this).each(function () { + const $this = $(this); + + if ($this.hasClass('in_viewport')) return; + $(window).on('scroll:end', () => { + if (isElementInViewport($this)) { + $this.trigger('in_viewport'); + if (cb) cb.call($this); + } + }).addClass('in_viewport'); + }); + }; +})(); +/* /CHECK WHEN ELEMENT IS IN VIEWPORT -----------------------------------------------*/ + +/* JWPLAYER INIT -----------------------------------------------*/ + +function jwplayerInit(videoObjectClass, videoObj) { + const videoObject = videoObj === false ? $(videoObjectClass) : videoObj; + if (!videoObject.length) return; + + let sources = false; + const videoId = videoObject.data('video_player_id'); + const aspectRatio = '16:9'; + const width = '100%'; + + if (videoObject.data('videotype') === 'local') { + sources = [{ + file: videoObject.data('file'), + type: videoObject.data('mimetype'), + }]; + } else { + sources = [{ + file: videoObject.data('file'), + }]; + } + + jwplayer(videoId).setup({ + primary: 'flash', + width, + aspectratio: aspectRatio, + autostart: videoObject.data('autostart'), + controlbar: [{ idlehide: 'true' }], + playlist: [{ + sources, + image: videoObject.data('image'), + }], + }); +} +/* /JWPLAYER INIT -----------------------------------------------*/ + +$(document).ready(() => { + const $loginform = $('form[name="loginform"]'); + $loginform.attr('action', $loginform.attr('action') + window.location.hash); + + /* JWPLAYER GLOBAL INITIALIZATION -----------------------------------------------*/ + $('div.video-container').each(function () { + const videoObjectClass = $(this).attr('id'); + if ($(this).prev().hasClass('video-config') && $(this).prev().hasClass(videoObjectClass)) { + jwplayerInit(`.${videoObjectClass}`, false); + } else { + $(this).remove(); + } + }); + /* /JWPLAYER GLOBAL INITIALIZATION -----------------------------------------------*/ + + /* idangero.us swiper */ + const relatedSwiper = []; + $('.related-multimedia.swiper-container').each(function (index) { + const swiperId = `relatedMultimediaSwiper-${index + 1}`; + const data = $(this).data(); + $(this).attr('id', swiperId); + relatedSwiper.push( + new Swiper($(this), { + navigation: { + nextEl: `#${swiperId} .swiper-button-next`, + prevEl: `#${swiperId} .swiper-button-prev`, + }, + pagination: { + el: `#${swiperId} .swiper-pagination`, + type: 'fraction', + }, + preloadImages: false, + loop: data.loop, + effect: data.effect, + autoplay: data.autoplay ? { delay: data.autoplay * 1000 } : false, + lazy: { + loadPrevNext: true, + loadPrevNextAmount: 1, + loadOnTransitionStart: true, + }, + autoHeight: true, + on: { + lazyImageReady() { + this.updateAutoHeight(); + }, + }, + }) + ); + }); + /* /idangero.us swiper */ + + /* header actions */ + /* plugin for click outside */ + (function($,c,b){$.map('click dblclick mousemove mousedown mouseup mouseover mouseout change select submit keydown keypress keyup'.split(' '),function(d){a(d)});a('focusin','focus'+b);a('focusout','blur'+b);$.addOutsideEvent=a;function a(g,e){e=e||g+b;var d=$(),h=g+'.'+e+'-special-event';$.event.special[e]={setup:function(){d=d.add(this);if(d.length===1){$(c).bind(h,f)}},teardown:function(){d=d.not(this);if(d.length===0){$(c).unbind(h)}},add:function(i){var j=i.handler;i.handler=function(l,k){l.target=k;j.apply(this,arguments)}}};function f(i){$(d).each(function(){var j=$(this);if(this!==i.target&&!j.has(i.target).length){j.triggerHandler(e,[i.target])}})}}})($,document,'outside'); // eslint-disable-line + /* /plugin for click outside */ + + (() => { + const page = $('#page'); + const navToggle = $('.mainnav-toggle'); + const searchToggle = $('.searchbox-toggle'); + const searchForm = $('.header-search'); + const searchInput = searchForm.find('input.search-query'); + const pageToggleClass = (e, classToToggle, classToRemove) => { + e.preventDefault(); + page.toggleClass(classToToggle); + if (classToRemove) { + page.removeClass(classToRemove); + } + }; + /* toggle mobile menu */ + navToggle.on('click', (e) => { + pageToggleClass(e, 'mainnav-active'); + }); + /* toggle searchbox */ + searchToggle.on('click', (e) => { + pageToggleClass(e, 'searchbox-active', 'mainnav-active'); + searchInput.focus(); + }); + searchForm.on('clickoutside', () => { + page.removeClass('searchbox-active'); + }); + searchInput.on('input', function () { + if ($(this).val() !== '') { + searchForm.addClass('filled'); + } else { + searchForm.removeClass('filled'); + } + }); + + /* toggle mobile sumbmenu */ + const mainNav = $('.main-navigation').find('ul.navbar-nav'); + const submenuTrigContent = $(''); + mainNav.find('.menu_level_1').before(submenuTrigContent).parent('li').attr('data-submenu', 'true'); + mainNav.on('click', 'i.submenu-trigger', function () { + $(this).parent('li').toggleClass('submenu-active'); + }); + })(); + + /* /header actions */ + + /* lazy image loading */ + const lazyImageLoad = (image) => { + if (image.hasAttribute('data-src')) image.setAttribute('src', image.getAttribute('data-src')); + if (image.hasAttribute('data-srcset')) image.setAttribute('srcset', image.getAttribute('data-srcset')); + image.onload = () => { + image.removeAttribute('data-src'); + image.removeAttribute('data-srcset'); + }; + }; + const loadAllLazy = () => { + [].forEach.call(document.querySelectorAll('img[data-src]'), img => lazyImageLoad(img)); + }; + if ('IntersectionObserver' in window) { + const lazyImageObserver = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const lazyImage = entry.target; + lazyImageLoad(lazyImage); + lazyImageObserver.unobserve(lazyImage); + } + }); + }); + + [].forEach.call(document.querySelectorAll('img[data-src]'), (lazyImage) => { + lazyImageObserver.observe(lazyImage); + }); + } else { + loadAllLazy(); + } + /* /lazy image loading */ + + /* get video poster */ + const getVideoPoster = (el, service) => { + if (el.attr('src')) return; + const videoID = el.attr('data-id'); + const thumbname = el.attr('data-thumbname'); + let url; + let getUrl; + if (service === 'dailymotion') { + url = `https://api.dailymotion.com/video/${videoID}?fields=${thumbname}`; + getUrl = obj => obj[thumbname]; + } else if (service === 'vimeo') { + url = `https://vimeo.com/api/v2/video/${videoID}.json`; + getUrl = obj => obj[0][thumbname]; + } + $.ajax({ + type: 'GET', + url, + jsonp: 'callback', + dataType: 'jsonp', + success: (data) => { + el.attr('src', getUrl(data)); + el.trigger('poster:loaded'); + }, + }); + }; + $('img.vimeo-poster').each(function () { + getVideoPoster($(this), 'vimeo'); + }); + $('img.dailymotion-poster').each(function () { + getVideoPoster($(this), 'dailymotion'); + }); + /* /get video poster */ + + Array.prototype.filter.call(document.getElementsByClassName('ajax-collection'), (el) => { + el.addEventListener('ajax-paging-added', () => { + $(el).find('img.vimeo-poster').each(function () { + getVideoPoster($(this), 'vimeo'); + }); + $(el).find('img.dailymotion-poster').each(function () { + getVideoPoster($(this), 'dailymotion'); + }); + /* load lazy images for results */ + [].forEach.call(el.querySelectorAll('img[data-src]'), img => lazyImageLoad(img)); + }, false); + }); + + $(document).on('poster:loaded', function () { + const $link = $(this).closest('.js-video-poster'); + $link.attr('href', this.src); + }); + + $('.js-video-poster').each(function () { + this.href = $('img', this).attr('src'); + }); + + const cookieControl = new CookieControl(window.__ngCcConfig); // eslint-disable-line no-underscore-dangle + cookieControl.init(); +}); diff --git a/src/AppBundle/Resources/public/images/favicon/favicon-114.png b/src/AppBundle/Resources/public/images/favicon/favicon-114.png new file mode 100644 index 0000000..9060577 Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon-114.png differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon-120.png b/src/AppBundle/Resources/public/images/favicon/favicon-120.png new file mode 100644 index 0000000..8bf4599 Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon-120.png differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon-144.png b/src/AppBundle/Resources/public/images/favicon/favicon-144.png new file mode 100644 index 0000000..09a4526 Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon-144.png differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon-152.png b/src/AppBundle/Resources/public/images/favicon/favicon-152.png new file mode 100644 index 0000000..2dffb53 Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon-152.png differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon-57.png b/src/AppBundle/Resources/public/images/favicon/favicon-57.png new file mode 100644 index 0000000..fcc6e7b Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon-57.png differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon-72.png b/src/AppBundle/Resources/public/images/favicon/favicon-72.png new file mode 100644 index 0000000..fcc6e7b Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon-72.png differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon-76.png b/src/AppBundle/Resources/public/images/favicon/favicon-76.png new file mode 100644 index 0000000..191ad29 Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon-76.png differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon.ico b/src/AppBundle/Resources/public/images/favicon/favicon.ico new file mode 100644 index 0000000..c758547 Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon.ico differ diff --git a/src/AppBundle/Resources/public/images/favicon/favicon.png b/src/AppBundle/Resources/public/images/favicon/favicon.png new file mode 100644 index 0000000..66ff72d Binary files /dev/null and b/src/AppBundle/Resources/public/images/favicon/favicon.png differ diff --git a/src/AppBundle/Resources/public/images/video_poster.png b/src/AppBundle/Resources/public/images/video_poster.png new file mode 100644 index 0000000..3c196e3 Binary files /dev/null and b/src/AppBundle/Resources/public/images/video_poster.png differ diff --git a/src/AppBundle/Resources/sass/_cookie_control.scss b/src/AppBundle/Resources/sass/_cookie_control.scss new file mode 100644 index 0000000..105fc5d --- /dev/null +++ b/src/AppBundle/Resources/sass/_cookie_control.scss @@ -0,0 +1,79 @@ +@import '@netgen/javascript-cookie-control/scss/style'; + +##{$ngCcId} { + .ng-cc-optional-list { + .ng-cc-optional-checkbox { + opacity: 0; + left: -9999em; + + label { + padding: 0 0 0 3.25em; + .ng-cc-checkbox-icon { + position: absolute; + left: 0; + top: .25em; + border-radius: 500em; + width: 2.6em; + height: 1em; + background: #fff; + border: 2px solid #fff; + &::before { + content: ''; + position: absolute; + height: 100%; + width: 50%; + left: 0; + top: 0; + border-radius: 500em; + background: hsl(200, 0, 50); + transition: all .3s; + z-index: 2; + } + span { + font-size: .5em; + font-weight: 700; + font-style: normal; + text-transform: uppercase; + color: #333; + display: flex; + align-items: center; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + &::before, + &::after { + flex: 1; + text-align: center; + } + &::before { + content: 'On'; + } + &::after { + content: 'Off'; + opacity: .6; + } + } + } + } + &:checked { + + label { + .ng-cc-checkbox-icon { + &::before { + left: 50%; + background: hsl(200, 95, 30); + } + } + } + } + &:disabled { + + label { + cursor: default; + .ng-cc-checkbox-icon { + opacity: .2; + } + } + } + } + } +} diff --git a/src/AppBundle/Resources/sass/_typography.scss b/src/AppBundle/Resources/sass/_typography.scss new file mode 100644 index 0000000..eed0883 --- /dev/null +++ b/src/AppBundle/Resources/sass/_typography.scss @@ -0,0 +1,63 @@ +// Typography style file +html { + font-size: 100%; +} +body { + -webkit-font-smoothing: antialiased; // sass-lint:disable-line no-vendor-prefixes + -moz-osx-font-smoothing: grayscale; // sass-lint:disable-line no-vendor-prefixes + background: $footer-bg; + overflow-wrap: break-word; + hyphens: auto; + @include media-breakpoint-down(sm) { + font-size: 1rem; + } +} + +#page { + background: $body-bg; +} + +a { + color: inherit; + transition: background 150ms, color 150ms; + &, + &:hover, + &:focus { + color: inherit; + outline: none; + text-decoration: none; + } +} + +p { + text-rendering: optimizeLegibility; + font-feature-settings: 'kern' 1; + font-kerning: normal; + margin: 0 0 1em; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + text-rendering: optimizeLegibility; + font-feature-settings: 'kern' 1; + font-kerning: normal; +} + +img { + max-width: 100%; + opacity: 1; + transition: opacity .3s; +} + +img[data-src] { + opacity: 0; + width: 100%; +} + +figure { + margin: 0; +} diff --git a/src/AppBundle/Resources/sass/_variables.scss b/src/AppBundle/Resources/sass/_variables.scss new file mode 100644 index 0000000..dbbb5fa --- /dev/null +++ b/src/AppBundle/Resources/sass/_variables.scss @@ -0,0 +1,62 @@ +// dimensions +$header-height: 5.9375rem; +$header-height-sm: 4rem; +$gutter: .9375rem; +$gap: 2 * $gutter; + +// colours +$primary: hsl(49, 99, 59); +$secondary: hsl(220, 33, 98); +$tertiary: #2AA9C0; +$white: hsl(0, 0, 100); +$black: hsl(0, 0, 0); +$gray-87: hsl(0, 0, 13); +$gray-54: hsl(0, 0, 46); +$gray-38: hsl(0, 0, 62); +$gray-12: hsl(0, 0, 88); +$gray-7: hsl(0, 0, 93); + +$body-bg: $white; +$footer-bg: $black; + +%clearfix { + &::after { + clear: both; + display: table; + content: ''; + } +} + +%fontawesome { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: inline-block; + font-style: normal; + font-variant: normal; + text-rendering: auto; + line-height: 1; + font-family: 'Font Awesome 5 Free'; + font-weight: 900; +} + +%hover-underline { + position: relative; + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: .5rem; + transform: scaleY(0); + transform-origin: bottom; + background: $primary; + transition: transform .2s; + } + &:hover, + &:focus { + &::after { + transform: scaleY(1); + } + } +} diff --git a/src/AppBundle/Resources/sass/assets/.gitkeep b/src/AppBundle/Resources/sass/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/AppBundle/Resources/sass/blocks/_block.scss b/src/AppBundle/Resources/sass/blocks/_block.scss new file mode 100644 index 0000000..9b59fd8 --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/_block.scss @@ -0,0 +1,52 @@ +.ngl-block { + // whitespace sizes + $sizes: ( + small: 2rem, + medium: 4rem, + large: 8rem, + ); + $sm-sizes: ( + small: 1rem, + medium: 2rem, + large: 4rem, + ); + @each $keyMap, $valueMap in $sizes { + &.whitespace-top-#{$keyMap} { + padding-top: $valueMap; + } + &.whitespace-bottom-#{$keyMap} { + padding-bottom: $valueMap; + } + } + &.with-bg-image { + background-repeat: no-repeat; + background-size: cover; + background-position: center; + } + + /* background colors */ + &.bg-color-primary { + background-color: $primary; + } + &.bg-color-secondary { + background-color: $secondary; + } + &.bg-color-white { + background-color: $white; + } + &.bg-color-black { + background-color: $black; + color: $white; + } + + @include media-breakpoint-down(sm) { + @each $keyMap, $valueMap in $sm-sizes { + &.whitespace-top-#{$keyMap} { + padding-top: $valueMap; + } + &.whitespace-bottom-#{$keyMap} { + padding-bottom: $valueMap; + } + } + } +} diff --git a/src/AppBundle/Resources/sass/blocks/_blocks.scss b/src/AppBundle/Resources/sass/blocks/_blocks.scss new file mode 100644 index 0000000..04a828a --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/_blocks.scss @@ -0,0 +1,8 @@ +@import 'block'; +@import 'list/grid_featured'; +@import 'list/list_numbered'; +@import 'title/title'; +@import 'gallery/gallery'; +@import 'gallery/sushi'; +@import 'button/button'; +@import 'specific/specific'; diff --git a/src/AppBundle/Resources/sass/blocks/button/_button.scss b/src/AppBundle/Resources/sass/blocks/button/_button.scss new file mode 100644 index 0000000..1953d5c --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/button/_button.scss @@ -0,0 +1,20 @@ +/* default button */ +.btn.btn-default { + display: block; + text-transform: uppercase; + font-size: .75rem; + letter-spacing: 1px; + text-align: left; + border-top: 1px solid hsla(0, 0, 0, .12); + padding: .75em 0 0; + line-height: 1.85; + &::after { + @extend %fontawesome; + content: '\f054'; + margin-left: .5em; + color: $gray-87; + } + &:hover { + color: $gray-54; + } +} diff --git a/src/AppBundle/Resources/sass/blocks/gallery/_gallery.scss b/src/AppBundle/Resources/sass/blocks/gallery/_gallery.scss new file mode 100644 index 0000000..cf6e05f --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/gallery/_gallery.scss @@ -0,0 +1,71 @@ +.related-multimedia.swiper-container { + .swiper-navigation { + position: absolute; + right: 0; + bottom: 0; + background: $black; + color: $white; + font-size: 1rem; + font-weight: 900; + display: flex; + z-index: 10; + align-items: center; + } + .swiper-button-prev, + .swiper-button-next { + position: relative; + left: auto; + right: auto; + top: auto; + bottom: auto; + width: 3.5em; + height: 3.5em; + display: inline-block; + background: transparent; + margin: 0; + &::before { + content: ''; + display: block; + position: absolute; + left: 50%; + top: 50%; + width: 1.125em; + height: 1.125em; + border-left: .2222222222em solid currentColor; + border-bottom: .2222222222em solid currentColor; + transform: rotate(45deg) translate3d(-50%, -20%, 0); + margin-left: -.1666666667em; + } + } + .swiper-button-next { + transform: rotate(180deg); + } + .swiper-pagination { + position: static; + width: auto; + font-size: 1.125em; + padding: 0 2.4em; + } + .image-wrapper { + figcaption { + max-width: calc(100% - 16rem); + } + } +} + +.image-wrapper { + position: relative; + figcaption { + position: absolute; + color: $white; + left: 0; + bottom: 0; + z-index: 2; + font-size: .75rem; + padding: .6666666667em 2em; + background: hsla(0, 0, 0, .6); + p { + margin: 0; + } + } +} diff --git a/src/AppBundle/Resources/sass/blocks/gallery/_sushi.scss b/src/AppBundle/Resources/sass/blocks/gallery/_sushi.scss new file mode 100644 index 0000000..cb0d359 --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/gallery/_sushi.scss @@ -0,0 +1,51 @@ +/* sushi bar */ +.ngl-vt-sushi_bar { + position: relative; + overflow: hidden; + .swiper-container { + overflow: visible; + position: static; + } + .swiper-slide { + pointer-events: none; + opacity: .2; + &.swiper-slide-visible { + opacity: 1; + pointer-events: initial; + } + } + .swiper-button-next, + .swiper-button-prev { + position: absolute; + width: 3.5rem; + height: 3.5rem; + background: $black; + color: $white; + transition: background .25s; + margin: 0; + top: 4.375rem; + &::before { + content: ''; + display: block; + position: absolute; + left: 50%; + top: 50%; + width: 1.125em; + height: 1.125em; + border-left: .2222222222em solid currentColor; + border-bottom: .2222222222em solid currentColor; + transform: rotate(45deg) translate3d(-50%, -20%, 0); + margin-left: -.1666666667em; + } + &:hover { + background: $gray-87; + } + } + .swiper-button-prev { + left: 0; + } + .swiper-button-next { + transform: rotate(180deg); + right: 0; + } +} diff --git a/src/AppBundle/Resources/sass/blocks/list/_grid_featured.scss b/src/AppBundle/Resources/sass/blocks/list/_grid_featured.scss new file mode 100644 index 0000000..dc1fa9a --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/list/_grid_featured.scss @@ -0,0 +1,89 @@ +.grid-featured { + display: flex; + flex-wrap: wrap; + margin-left: -.25rem; + margin-right: -.25rem; + .item { + padding: .25rem; + flex: 0 0 33.333333333%; + max-width: 33.333333333%; + } + .vl2 { + margin: 0; + .image-16by9 { + padding-bottom: 100%; + } + .title { + font-size: 2.0625rem; + -webkit-line-clamp: 5; + max-height: 6.25em; + } + } + @include media-breakpoint-down(lg) { + .vl2 { + .title { + font-size: 1.75rem; + } + } + } + @include media-breakpoint-down(md) { + .primary-item { + flex: 0 0 100%; + max-width: 100%; + .vl2 { + .image-16by9 { + padding-bottom: 56.25%; + } + } + } + .secondary-item { + flex: 0 0 50%; + max-width: 50%; + } + .vl2 { + .title { + font-size: 1.75rem; + } + } + } + @include media-breakpoint-down(sm) { + .vl2 { + .title { + font-size: 1.375rem; + } + } + } + @include media-breakpoint-down(xs) { + .vl2 { + .title { + font-size: 1.5rem; + } + } + .secondary-item { + .vl2 { + .title { + font-size: 1.25rem; + } + } + } + } + @include media-breakpoint-down(xxs) { + .secondary-item { + flex: 0 0 100%; + max-width: 100%; + } + .primary-item, + .secondary-item { + .vl2 { + .title { + font-size: 1.5rem; + -webkit-line-clamp: 4; + max-height: 5em; + } + .image-16by9 { + padding-bottom: 75%; + } + } + } + } +} diff --git a/src/AppBundle/Resources/sass/blocks/list/_list_numbered.scss b/src/AppBundle/Resources/sass/blocks/list/_list_numbered.scss new file mode 100644 index 0000000..afcd4c1 --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/list/_list_numbered.scss @@ -0,0 +1,30 @@ +.list-numbered { + counter-reset: my-counter; + .list-item { + display: flex; + align-items: flex-start; + + .list-item { + padding-top: 1rem; + margin-top: 1rem; + border-top: 2px dashed hsla(0, 0, 0, .12); + } + &::before { + counter-increment: my-counter; + content: counter(my-counter); + display: block; + font-size: 2.0625rem; + line-height: .8484848485; + font-weight: 900; + color: $primary; + width: 2.25rem; + } + } + + /* listitem inside numbered list */ + .vl6 { + padding: 0; + margin: 0; + border: 0; + flex: 1; + } +} diff --git a/src/AppBundle/Resources/sass/blocks/specific/_ajax_loading.scss b/src/AppBundle/Resources/sass/blocks/specific/_ajax_loading.scss new file mode 100644 index 0000000..de65a87 --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/specific/_ajax_loading.scss @@ -0,0 +1,54 @@ +.ajax-loading { + > * { + pointer-events: none; + } + .ajax-navigation { + position: relative; + > ul { + opacity: .5; + } + .ajax-load-more { + opacity: 0; + } + &::before { + @extend %fontawesome; + content: '\f1ce'; + position: absolute; + z-index: 100; + left: 50%; + top: 50%; + width: 40px; + height: 40px; + line-height: 40px; + text-align: center; + margin: -20px 0 0 -20px; + color: #333; + font-size: 32px; + animation: ajaxLoader 1s infinite linear; + } + } +} +@keyframes ajaxLoader { + 100% { + transform: rotate(360deg); + } +} +div[class^='ajax-status-reports-'] { + &.ajax-loading { + min-height: 40px; + margin: 0 0 2em; + } +} + +.ajax-navigation { + .ajax-load-more { + font-size: 1rem; + font-weight: 900; + display: inline-block; + background: $primary; + color: $gray-87; + line-height: 1.5; + padding: .3125em 1em; + border: 0; + } +} diff --git a/src/AppBundle/Resources/sass/blocks/specific/_pagination.scss b/src/AppBundle/Resources/sass/blocks/specific/_pagination.scss new file mode 100644 index 0000000..d1d1575 --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/specific/_pagination.scss @@ -0,0 +1,28 @@ +.pagination { + .page-item { + margin: 0 1px 0 0; + } + .page-link { + background: $black; + color: $white; + border: 0; + margin: 0; + font-size: 1.125rem; + font-weight: 900; + padding: .9em 1.2em; + } + a.page-link { + &:hover { + background: $gray-87; + } + } + span.page-link { + cursor: default !important; + } + .active { + .page-link { + background: $white; + color: $black; + } + } +} diff --git a/src/AppBundle/Resources/sass/blocks/specific/_right_box.scss b/src/AppBundle/Resources/sass/blocks/specific/_right_box.scss new file mode 100644 index 0000000..cd475bb --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/specific/_right_box.scss @@ -0,0 +1,6 @@ +.right-column-box { + background: $body-bg; + padding: 2rem; + border-top: .375rem solid $black; + border-bottom: .375rem solid $black; +} diff --git a/src/AppBundle/Resources/sass/blocks/specific/_specific.scss b/src/AppBundle/Resources/sass/blocks/specific/_specific.scss new file mode 100644 index 0000000..4d9cd3b --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/specific/_specific.scss @@ -0,0 +1,3 @@ +@import 'right_box'; +@import 'ajax_loading'; +@import 'pagination'; diff --git a/src/AppBundle/Resources/sass/blocks/title/_section_title.scss b/src/AppBundle/Resources/sass/blocks/title/_section_title.scss new file mode 100644 index 0000000..6b4f6c6 --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/title/_section_title.scss @@ -0,0 +1,23 @@ +.section-title { + .title { + font-size: 1.125rem; + text-transform: uppercase; + letter-spacing: 2px; + font-weight: 900; + margin: 0 0 1.7777777778em; + position: relative; + padding: 0 .75em; + &::before { + content: ''; + position: absolute; + left: 0; + right: 0; + bottom: .2222222222em; + height: .625rem; + background: hsla(0, 0, 0, .04); + } + } + &.section-title-centered { + text-align: center; + } +} diff --git a/src/AppBundle/Resources/sass/blocks/title/_title.scss b/src/AppBundle/Resources/sass/blocks/title/_title.scss new file mode 100644 index 0000000..cd57682 --- /dev/null +++ b/src/AppBundle/Resources/sass/blocks/title/_title.scss @@ -0,0 +1,8 @@ +.ngl-title { + .title-icon { + font-size: .64em; + margin: 0 0 .2em; + } +} + +@import 'section_title'; diff --git a/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap.scss b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap.scss new file mode 100644 index 0000000..801f3b6 --- /dev/null +++ b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap.scss @@ -0,0 +1,42 @@ +/*! + * Bootstrap v4.1.2 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +// @import 'bootstrap/scss/functions'; +@import 'bootstrap/scss/variables'; +@import 'bootstrap/scss/mixins'; +@import 'bootstrap/scss/root'; +@import 'bootstrap/scss/reboot'; +@import 'bootstrap/scss/type'; +// @import 'bootstrap/scss/images'; +// @import 'bootstrap/scss/code'; +@import 'bootstrap/scss/grid'; +@import 'bootstrap/scss/tables'; +@import 'bootstrap/scss/forms'; +@import 'bootstrap/scss/buttons'; +@import 'bootstrap/scss/transitions'; +@import 'bootstrap/scss/dropdown'; +@import 'bootstrap/scss/button-group'; +@import 'bootstrap/scss/input-group'; +// @import 'bootstrap/scss/custom-forms'; +// @import 'bootstrap/scss/nav'; +// @import 'bootstrap/scss/navbar'; +// @import 'bootstrap/scss/card'; +@import 'bootstrap/scss/breadcrumb'; +@import 'bootstrap/scss/pagination'; +// @import 'bootstrap/scss/badge'; +// @import 'bootstrap/scss/jumbotron'; +// @import 'bootstrap/scss/alert'; +@import 'bootstrap/scss/progress'; +// @import 'bootstrap/scss/media'; +// @import 'bootstrap/scss/list-group'; +// @import 'bootstrap/scss/close'; +// @import 'bootstrap/scss/modal'; +// @import 'bootstrap/scss/tooltip'; +// @import 'bootstrap/scss/popover'; +// @import 'bootstrap/scss/carousel'; +@import 'bootstrap/scss/utilities'; +@import 'bootstrap/scss/print'; diff --git a/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_import.scss b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_import.scss new file mode 100644 index 0000000..94bde57 --- /dev/null +++ b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_import.scss @@ -0,0 +1,4 @@ +@import 'bootstrap/scss/functions'; +@import 'bootstrap_variables'; +@import 'bootstrap'; +@import 'bootstrap_override'; diff --git a/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_override.scss b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_override.scss new file mode 100644 index 0000000..d8b6d84 --- /dev/null +++ b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_override.scss @@ -0,0 +1,63 @@ +/* btn overrides */ +.btn { + font-weight: 900; + font-size: 1.125rem; + border-width: 2px; + line-height: 1; +} + +.btn-primary { + background: $black; + color: $white; + border-color: $black; + &:active, + &.active, + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active, + &:hover { + background-color: $gray-87; + border-color: $gray-87; + } +} + +.btn-secondary { + background: transparent; + border-color: $black; + color: $gray-87; + &:active, + &.active, + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active, + &:hover { + background-color: $gray-54; + border-color: $gray-54; + color: $white; + } +} + +.container { + &-wide { + max-width: 1500px; + padding-left: 2 * $gutter; + padding-right: 2 * $gutter; + } + &-narrow { + max-width: 768px; + } + @include media-breakpoint-down(md) { + &-narrow { + max-width: 600px; + } + } + @include media-breakpoint-down(sm) { + &-narrow { + max-width: 460px; + } + } + @include media-breakpoint-down(xs) { + &-wide { + padding-left: $gutter; + padding-right: $gutter; + } + } +} diff --git a/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_variables.scss b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_variables.scss new file mode 100644 index 0000000..8fe5209 --- /dev/null +++ b/src/AppBundle/Resources/sass/bootstrap_import/_bootstrap_variables.scss @@ -0,0 +1,895 @@ +// Variables +// +// Variables should follow the `$component-state-property-size` formula for +// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. + + +// +// Color system +// + +// stylelint-disable +// $white: #fff; +// $gray-100: #f8f9fa; +// $gray-200: #e9ecef; +// $gray-300: #dee2e6; +// $gray-400: #ced4da; +// $gray-500: #adb5bd; +// $gray-600: #6c757d; +// $gray-700: #495057; +// $gray-800: #343a40; +// $gray-900: #212529; +// $black: #000; + +// $grays: (); +// $grays: map-merge(( +// "100": $gray-100, +// "200": $gray-200, +// "300": $gray-300, +// "400": $gray-400, +// "500": $gray-500, +// "600": $gray-600, +// "700": $gray-700, +// "800": $gray-800, +// "900": $gray-900 +// ), $grays); + +// $blue: #007bff; +// $indigo: #6610f2; +// $purple: #6f42c1; +// $pink: #e83e8c; +// $red: #dc3545; +// $orange: #fd7e14; +// $yellow: #ffc107; +// $green: #28a745; +// $teal: #20c997; +// $cyan: #17a2b8; + +// $colors: (); +// $colors: map-merge(( +// "blue": $blue, +// "indigo": $indigo, +// "purple": $purple, +// "pink": $pink, +// "red": $red, +// "orange": $orange, +// "yellow": $yellow, +// "green": $green, +// "teal": $teal, +// "cyan": $cyan, +// "white": $white, +// "gray": $gray-600, +// "gray-dark": $gray-800 +// ), $colors); + +// $primary: $blue; +// $secondary: $gray-600; +// $success: $green; +// $info: $cyan; +// $warning: $yellow; +// $danger: $red; +// $light: $gray-100; +// $dark: $gray-800; + +// $theme-colors: (); +// $theme-colors: map-merge(( +// "primary": $primary, +// "secondary": $secondary, +// "success": $success, +// "info": $info, +// "warning": $warning, +// "danger": $danger, +// "light": $light, +// "dark": $dark +// ), $theme-colors); +// stylelint-enable + +// Set a specific jump point for requesting color jumps +// $theme-color-interval: 8%; + +// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. +// $yiq-contrasted-threshold: 150; + +// Customize the light and dark text colors for use in our YIQ color contrast function. +// $yiq-text-dark: $gray-900; +// $yiq-text-light: $white; + +// Options +// +// Quickly modify global styling by enabling or disabling optional features. + +// $enable-caret: true; +// $enable-rounded: true; +// $enable-shadows: false; +// $enable-gradients: false; +// $enable-transitions: true; +// $enable-hover-media-query: false; // Deprecated, no longer affects any compiled CSS +// $enable-grid-classes: true; +// $enable-print-styles: true; + + +// Spacing +// +// Control the default styling of most Bootstrap elements by modifying these +// variables. Mostly focused on spacing. +// You can add more entries to the $spacers map, should you need more variation. + +// stylelint-disable +// $spacer: 1rem; +// $spacers: (); +// $spacers: map-merge(( +// 0: 0, +// 1: ($spacer * .25), +// 2: ($spacer * .5), +// 3: $spacer, +// 4: ($spacer * 1.5), +// 5: ($spacer * 3) +// ), $spacers); + +// This variable affects the `.h-*` and `.w-*` classes. +// $sizes: (); +// $sizes: map-merge(( +// 25: 25%, +// 50: 50%, +// 75: 75%, +// 100: 100% +// ), $sizes); +// stylelint-enable + +// Body +// +// Settings for the `` element. + +$body-bg: $body-bg; +$body-color: $gray-87; + +// Links +// +// Style anchor elements. + +// $link-color: theme-color("primary"); +// $link-decoration: none; +// $link-hover-color: darken($link-color, 15%); +// $link-hover-decoration: underline; + +// Paragraphs +// +// Style p element. + +// $paragraph-margin-bottom: 1rem; + + +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. + +$grid-breakpoints: ( + xxs: 0, + xs: 480px, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px +); + +// @include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +// @include _assert-starts-at-zero($grid-breakpoints); + + +// Grid containers +// +// Define the maximum width of `.container` for different screen sizes. + +// $container-max-widths: ( +// sm: 540px, +// md: 720px, +// lg: 960px, +// xl: 1140px +// ); + +// @include _assert-ascending($container-max-widths, "$container-max-widths"); + + +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +// $grid-columns: 12; +$grid-gutter-width: $gap; + +// Components +// +// Define common padding and border radius sizes and more. + +// $line-height-lg: 1.5; +// $line-height-sm: 1.5; + +// $border-width: 1px; +// $border-color: $gray-300; + +$border-radius: 0; +// $border-radius-lg: .3rem; +// $border-radius-sm: .2rem; + +// $component-active-color: $white; +// $component-active-bg: theme-color("primary"); + +// $caret-width: .3em; + +// $transition-base: all .2s ease-in-out; +// $transition-fade: opacity .15s linear; +// $transition-collapse: height .35s ease; + + +// Fonts +// +// Font, line-height, and color for body text, headings, and more. + +// stylelint-disable value-keyword-case +$font-family-sans-serif: 'Lato', Helvetica, Arial, sans-serif; +// $font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +// $font-family-base: $font-family-sans-serif; +// stylelint-enable value-keyword-case + +$font-size-base: 1.125rem; +// $font-size-lg: ($font-size-base * 1.25); +// $font-size-sm: ($font-size-base * .875); + +// $font-weight-light: 300; +// $font-weight-normal: 400; +// $font-weight-bold: 700; + +// $font-weight-base: $font-weight-normal; +// $line-height-base: 1.5; + +$h1-font-size: 3.5rem; +$h2-font-size: 2.625rem; +$h3-font-size: 2rem; +$h4-font-size: 1.5rem; +$h5-font-size: 1.25rem; +$h6-font-size: 1.125rem; + +// $headings-margin-bottom: ($spacer / 2); +// $headings-font-family: inherit; +$headings-font-weight: 900; +// $headings-line-height: 1.2; +// $headings-color: inherit; + +// $display1-size: 6rem; +// $display2-size: 5.5rem; +// $display3-size: 4.5rem; +// $display4-size: 3.5rem; + +// $display1-weight: 300; +// $display2-weight: 300; +// $display3-weight: 300; +// $display4-weight: 300; +// $display-line-height: $headings-line-height; + +// $lead-font-size: ($font-size-base * 1.25); +// $lead-font-weight: 300; + +// $small-font-size: 80%; + +// $text-muted: $gray-600; + +// $blockquote-small-color: $gray-600; +// $blockquote-font-size: ($font-size-base * 1.25); + +// $hr-border-color: rgba($black, .1); +// $hr-border-width: $border-width; + +// $mark-padding: .2em; + +// $dt-font-weight: $font-weight-bold; + +// $kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25); +// $nested-kbd-font-weight: $font-weight-bold; + +// $list-inline-padding: .5rem; + +// $mark-bg: #fcf8e3; + +// $hr-margin-y: $spacer; + + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +// $table-cell-padding: .75rem; +// $table-cell-padding-sm: .3rem; + +// $table-bg: transparent; +// $table-accent-bg: rgba($black, .05); +// $table-hover-bg: rgba($black, .075); +// $table-active-bg: $table-hover-bg; + +// $table-border-width: $border-width; +// $table-border-color: $gray-300; + +// $table-head-bg: $gray-200; +// $table-head-color: $gray-700; + +// $table-dark-bg: $gray-900; +// $table-dark-accent-bg: rgba($white, .05); +// $table-dark-hover-bg: rgba($white, .075); +// $table-dark-border-color: lighten($gray-900, 7.5%); +// $table-dark-color: $body-bg; + + +// Buttons + Forms +// +// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. + +// $input-btn-padding-y: .375rem; +// $input-btn-padding-x: .75rem; +// $input-btn-line-height: $line-height-base; + +// $input-btn-focus-width: .2rem; +// $input-btn-focus-color: rgba($component-active-bg, .25); +// $input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color; + +// $input-btn-padding-y-sm: .25rem; +// $input-btn-padding-x-sm: .5rem; +// $input-btn-line-height-sm: $line-height-sm; + +// $input-btn-padding-y-lg: .5rem; +// $input-btn-padding-x-lg: 1rem; +// $input-btn-line-height-lg: $line-height-lg; + +// $input-btn-border-width: $border-width; + + +// Buttons +// +// For each of Bootstrap's buttons, define text, background, and border color. + +// $btn-padding-y: $input-btn-padding-y; +// $btn-padding-x: $input-btn-padding-x; +// $btn-line-height: $input-btn-line-height; + +// $btn-padding-y-sm: $input-btn-padding-y-sm; +// $btn-padding-x-sm: $input-btn-padding-x-sm; +// $btn-line-height-sm: $input-btn-line-height-sm; + +// $btn-padding-y-lg: $input-btn-padding-y-lg; +// $btn-padding-x-lg: $input-btn-padding-x-lg; +// $btn-line-height-lg: $input-btn-line-height-lg; + +// $btn-border-width: $input-btn-border-width; + +// $btn-font-weight: $font-weight-normal; +// $btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075); +// $btn-focus-width: $input-btn-focus-width; +// $btn-focus-box-shadow: $input-btn-focus-box-shadow; +// $btn-disabled-opacity: .65; +// $btn-active-box-shadow: inset 0 3px 5px rgba($black, .125); + +// $btn-link-disabled-color: $gray-600; + +// $btn-block-spacing-y: .5rem; + +// Allows for customizing button radius independently from global border radius +// $btn-border-radius: $border-radius; +// $btn-border-radius-lg: $border-radius-lg; +// $btn-border-radius-sm: $border-radius-sm; + +// $btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; + + +// Forms + +// $input-padding-y: $input-btn-padding-y; +// $input-padding-x: $input-btn-padding-x; +// $input-line-height: $input-btn-line-height; + +// $input-padding-y-sm: $input-btn-padding-y-sm; +// $input-padding-x-sm: $input-btn-padding-x-sm; +// $input-line-height-sm: $input-btn-line-height-sm; + +// $input-padding-y-lg: $input-btn-padding-y-lg; +// $input-padding-x-lg: $input-btn-padding-x-lg; +// $input-line-height-lg: $input-btn-line-height-lg; + +// $input-bg: $white; +// $input-disabled-bg: $gray-200; + +// $input-color: $gray-700; +// $input-border-color: $gray-400; +// $input-border-width: $input-btn-border-width; +// $input-box-shadow: inset 0 1px 1px rgba($black, .075); + +// $input-border-radius: $border-radius; +// $input-border-radius-lg: $border-radius-lg; +// $input-border-radius-sm: $border-radius-sm; + +// $input-focus-bg: $input-bg; +// $input-focus-border-color: lighten($component-active-bg, 25%); +// $input-focus-color: $input-color; +// $input-focus-width: $input-btn-focus-width; +// $input-focus-box-shadow: $input-btn-focus-box-shadow; + +// $input-placeholder-color: $gray-600; + +// $input-height-border: $input-border-width * 2; + +// $input-height-inner: ($font-size-base * $input-btn-line-height) + ($input-btn-padding-y * 2); +// $input-height: calc(#{$input-height-inner} + #{$input-height-border}); + +// $input-height-inner-sm: ($font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2); +// $input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}); + +// $input-height-inner-lg: ($font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2); +// $input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}); + +// $input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; + +// $form-text-margin-top: .25rem; + +// $form-check-input-gutter: 1.25rem; +// $form-check-input-margin-y: .3rem; +// $form-check-input-margin-x: .25rem; + +// $form-check-inline-margin-x: .75rem; +// $form-check-inline-input-margin-x: .3125rem; + +// $form-group-margin-bottom: 1rem; + +// $input-group-addon-color: $input-color; +// $input-group-addon-bg: $gray-200; +// $input-group-addon-border-color: $input-border-color; + +// $custom-control-gutter: 1.5rem; +// $custom-control-spacer-x: 1rem; + +// $custom-control-indicator-size: 1rem; +// $custom-control-indicator-bg: $gray-300; +// $custom-control-indicator-bg-size: 50% 50%; +// $custom-control-indicator-box-shadow: inset 0 .25rem .25rem rgba($black, .1); + +// $custom-control-indicator-disabled-bg: $gray-200; +// $custom-control-label-disabled-color: $gray-600; + +// $custom-control-indicator-checked-color: $component-active-color; +// $custom-control-indicator-checked-bg: $component-active-bg; +// $custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5); +// $custom-control-indicator-checked-box-shadow: none; + +// $custom-control-indicator-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow; + +// $custom-control-indicator-active-color: $component-active-color; +// $custom-control-indicator-active-bg: lighten($component-active-bg, 35%); +// $custom-control-indicator-active-box-shadow: none; + +// $custom-checkbox-indicator-border-radius: $border-radius; +// $custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E"), "#", "%23"); + +// $custom-checkbox-indicator-indeterminate-bg: $component-active-bg; +// $custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color; +// $custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3E%3C/svg%3E"), "#", "%23"); +// $custom-checkbox-indicator-indeterminate-box-shadow: none; + +// $custom-radio-indicator-border-radius: 50%; +// $custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3E%3C/svg%3E"), "#", "%23"); + +// $custom-select-padding-y: .375rem; +// $custom-select-padding-x: .75rem; +// $custom-select-height: $input-height; +// $custom-select-indicator-padding: 1rem; // Extra padding to account for the presence of the background-image based indicator +// $custom-select-line-height: $input-btn-line-height; +// $custom-select-color: $input-color; +// $custom-select-disabled-color: $gray-600; +// $custom-select-bg: $white; +// $custom-select-disabled-bg: $gray-200; +// $custom-select-bg-size: 8px 10px; // In pixels because image dimensions +// $custom-select-indicator-color: $gray-800; +// $custom-select-indicator: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E"), "#", "%23"); +// $custom-select-border-width: $input-btn-border-width; +// $custom-select-border-color: $input-border-color; +// $custom-select-border-radius: $border-radius; + +// $custom-select-focus-border-color: $input-focus-border-color; +// $custom-select-focus-box-shadow: inset 0 1px 2px rgba($black, .075), 0 0 5px rgba($custom-select-focus-border-color, .5); + +// $custom-select-font-size-sm: 75%; +// $custom-select-height-sm: $input-height-sm; + +// $custom-select-font-size-lg: 125%; +// $custom-select-height-lg: $input-height-lg; + +// $custom-file-height: $input-height; +// $custom-file-focus-border-color: $input-focus-border-color; +// $custom-file-focus-box-shadow: $input-btn-focus-box-shadow; + +// $custom-file-padding-y: $input-btn-padding-y; +// $custom-file-padding-x: $input-btn-padding-x; +// $custom-file-line-height: $input-btn-line-height; +// $custom-file-color: $input-color; +// $custom-file-bg: $input-bg; +// $custom-file-border-width: $input-btn-border-width; +// $custom-file-border-color: $input-border-color; +// $custom-file-border-radius: $input-border-radius; +// $custom-file-box-shadow: $input-box-shadow; +// $custom-file-button-color: $custom-file-color; +// $custom-file-button-bg: $input-group-addon-bg; +// $custom-file-text: ( +// en: "Browse" +// ); + + +// Form validation +// $form-feedback-margin-top: $form-text-margin-top; +// $form-feedback-font-size: $small-font-size; +// $form-feedback-valid-color: theme-color("success"); +// $form-feedback-invalid-color: theme-color("danger"); + + +// Dropdowns +// +// Dropdown menu container and contents. + +// $dropdown-min-width: 10rem; +// $dropdown-padding-y: .5rem; +// $dropdown-spacer: .125rem; +// $dropdown-bg: $white; +// $dropdown-border-color: rgba($black, .15); +// $dropdown-border-radius: $border-radius; +// $dropdown-border-width: $border-width; +// $dropdown-divider-bg: $gray-200; +// $dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175); + +// $dropdown-link-color: $gray-900; +// $dropdown-link-hover-color: darken($gray-900, 5%); +// $dropdown-link-hover-bg: $gray-100; + +// $dropdown-link-active-color: $component-active-color; +// $dropdown-link-active-bg: $component-active-bg; + +// $dropdown-link-disabled-color: $gray-600; + +// $dropdown-item-padding-y: .25rem; +// $dropdown-item-padding-x: 1.5rem; + +// $dropdown-header-color: $gray-600; + + +// Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. + +// $zindex-dropdown: 1000; +// $zindex-sticky: 1020; +// $zindex-fixed: 1030; +// $zindex-modal-backdrop: 1040; +// $zindex-modal: 1050; +// $zindex-popover: 1060; +// $zindex-tooltip: 1070; + +// Navs + +// $nav-link-padding-y: .5rem; +// $nav-link-padding-x: 1rem; +// $nav-link-disabled-color: $gray-600; + +// $nav-tabs-border-color: $gray-300; +// $nav-tabs-border-width: $border-width; +// $nav-tabs-border-radius: $border-radius; +// $nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color; +// $nav-tabs-link-active-color: $gray-700; +// $nav-tabs-link-active-bg: $body-bg; +// $nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg; + +// $nav-pills-border-radius: $border-radius; +// $nav-pills-link-active-color: $component-active-color; +// $nav-pills-link-active-bg: $component-active-bg; + +// Navbar + +// $navbar-padding-y: ($spacer / 2); +// $navbar-padding-x: $spacer; + +// $navbar-nav-link-padding-x: .5rem; + +// $navbar-brand-font-size: $font-size-lg; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +// $nav-link-height: ($font-size-base * $line-height-base + $nav-link-padding-y * 2); +// $navbar-brand-height: $navbar-brand-font-size * $line-height-base; +// $navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2; + +// $navbar-toggler-padding-y: .25rem; +// $navbar-toggler-padding-x: .75rem; +// $navbar-toggler-font-size: $font-size-lg; +// $navbar-toggler-border-radius: $btn-border-radius; + +// $navbar-dark-color: rgba($white, .5); +// $navbar-dark-hover-color: rgba($white, .75); +// $navbar-dark-active-color: $white; +// $navbar-dark-disabled-color: rgba($white, .25); +// $navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23"); +// $navbar-dark-toggler-border-color: rgba($white, .1); + +// $navbar-light-color: rgba($black, .5); +// $navbar-light-hover-color: rgba($black, .7); +// $navbar-light-active-color: rgba($black, .9); +// $navbar-light-disabled-color: rgba($black, .3); +// $navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23"); +// $navbar-light-toggler-border-color: rgba($black, .1); + +// Pagination + +// $pagination-padding-y: .5rem; +// $pagination-padding-x: .75rem; +// $pagination-padding-y-sm: .25rem; +// $pagination-padding-x-sm: .5rem; +// $pagination-padding-y-lg: .75rem; +// $pagination-padding-x-lg: 1.5rem; +// $pagination-line-height: 1.25; + +// $pagination-color: $link-color; +// $pagination-bg: $white; +// $pagination-border-width: $border-width; +// $pagination-border-color: $gray-300; + +// $pagination-focus-box-shadow: $input-btn-focus-box-shadow; + +// $pagination-hover-color: $link-hover-color; +// $pagination-hover-bg: $gray-200; +// $pagination-hover-border-color: $gray-300; + +// $pagination-active-color: $component-active-color; +// $pagination-active-bg: $component-active-bg; +// $pagination-active-border-color: $pagination-active-bg; + +// $pagination-disabled-color: $gray-600; +// $pagination-disabled-bg: $white; +// $pagination-disabled-border-color: $gray-300; + + +// Jumbotron + +// $jumbotron-padding: 2rem; +// $jumbotron-bg: $gray-200; + + +// Cards + +// $card-spacer-y: .75rem; +// $card-spacer-x: 1.25rem; +// $card-border-width: $border-width; +// $card-border-radius: $border-radius; +// $card-border-color: rgba($black, .125); +// $card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}); +// $card-cap-bg: rgba($black, .03); +// $card-bg: $white; + +// $card-img-overlay-padding: 1.25rem; + +// $card-group-margin: ($grid-gutter-width / 2); +// $card-deck-margin: $card-group-margin; + +// $card-columns-count: 3; +// $card-columns-gap: 1.25rem; +// $card-columns-margin: $card-spacer-y; + + +// Tooltips + +// $tooltip-font-size: $font-size-sm; +// $tooltip-max-width: 200px; +// $tooltip-color: $white; +// $tooltip-bg: $black; +// $tooltip-border-radius: $border-radius; +// $tooltip-opacity: .9; +// $tooltip-padding-y: .25rem; +// $tooltip-padding-x: .5rem; +// $tooltip-margin: 0; + +// $tooltip-arrow-width: .8rem; +// $tooltip-arrow-height: .4rem; +// $tooltip-arrow-color: $tooltip-bg; + + +// Popovers + +// $popover-font-size: $font-size-sm; +// $popover-bg: $white; +// $popover-max-width: 276px; +// $popover-border-width: $border-width; +// $popover-border-color: rgba($black, .2); +// $popover-border-radius: $border-radius-lg; +// $popover-box-shadow: 0 .25rem .5rem rgba($black, .2); + +// $popover-header-bg: darken($popover-bg, 3%); +// $popover-header-color: $headings-color; +// $popover-header-padding-y: .5rem; +// $popover-header-padding-x: .75rem; + +// $popover-body-color: $body-color; +// $popover-body-padding-y: $popover-header-padding-y; +// $popover-body-padding-x: $popover-header-padding-x; + +// $popover-arrow-width: 1rem; +// $popover-arrow-height: .5rem; +// $popover-arrow-color: $popover-bg; + +// $popover-arrow-outer-color: fade-in($popover-border-color, .05); + + +// Badges + +// $badge-font-size: 75%; +// $badge-font-weight: $font-weight-bold; +// $badge-padding-y: .25em; +// $badge-padding-x: .4em; +// $badge-border-radius: $border-radius; + +// $badge-pill-padding-x: .6em; +// Use a higher than normal value to ensure completely rounded edges when +// customizing padding or font-size on labels. +// $badge-pill-border-radius: 10rem; + + +// Modals + +// Padding applied to the modal body +// $modal-inner-padding: 1rem; + +// $modal-dialog-margin: .5rem; +// $modal-dialog-margin-y-sm-up: 1.75rem; + +// $modal-title-line-height: $line-height-base; + +// $modal-content-bg: $white; +// $modal-content-border-color: rgba($black, .2); +// $modal-content-border-width: $border-width; +// $modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5); +// $modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5); + +// $modal-backdrop-bg: $black; +// $modal-backdrop-opacity: .5; +// $modal-header-border-color: $gray-200; +// $modal-footer-border-color: $modal-header-border-color; +// $modal-header-border-width: $modal-content-border-width; +// $modal-footer-border-width: $modal-header-border-width; +// $modal-header-padding: 1rem; + +// $modal-lg: 800px; +// $modal-md: 500px; +// $modal-sm: 300px; + +// $modal-transition: transform .3s ease-out; + + +// Alerts +// +// Define alert colors, border radius, and padding. + +// $alert-padding-y: .75rem; +// $alert-padding-x: 1.25rem; +// $alert-margin-bottom: 1rem; +// $alert-border-radius: $border-radius; +// $alert-link-font-weight: $font-weight-bold; +// $alert-border-width: $border-width; + +// $alert-bg-level: -10; +// $alert-border-level: -9; +// $alert-color-level: 6; + + +// Progress bars + +// $progress-height: 1rem; +// $progress-font-size: ($font-size-base * .75); +// $progress-bg: $gray-200; +// $progress-border-radius: $border-radius; +// $progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1); +// $progress-bar-color: $white; +// $progress-bar-bg: theme-color("primary"); +// $progress-bar-animation-timing: 1s linear infinite; +// $progress-bar-transition: width .6s ease; + +// List group + +// $list-group-bg: $white; +// $list-group-border-color: rgba($black, .125); +// $list-group-border-width: $border-width; +// $list-group-border-radius: $border-radius; + +// $list-group-item-padding-y: .75rem; +// $list-group-item-padding-x: 1.25rem; + +// $list-group-hover-bg: $gray-100; +// $list-group-active-color: $component-active-color; +// $list-group-active-bg: $component-active-bg; +// $list-group-active-border-color: $list-group-active-bg; + +// $list-group-disabled-color: $gray-600; +// $list-group-disabled-bg: $list-group-bg; + +// $list-group-action-color: $gray-700; +// $list-group-action-hover-color: $list-group-action-color; + +// $list-group-action-active-color: $body-color; +// $list-group-action-active-bg: $gray-200; + + +// Image thumbnails + +// $thumbnail-padding: .25rem; +// $thumbnail-bg: $body-bg; +// $thumbnail-border-width: $border-width; +// $thumbnail-border-color: $gray-300; +// $thumbnail-border-radius: $border-radius; +// $thumbnail-box-shadow: 0 1px 2px rgba($black, .075); + + +// Figures + +// $figure-caption-font-size: 90%; +// $figure-caption-color: $gray-600; + + +// Breadcrumbs + +// $breadcrumb-padding-y: .75rem; +// $breadcrumb-padding-x: 1rem; +// $breadcrumb-item-padding: .5rem; + +// $breadcrumb-margin-bottom: 1rem; + +// $breadcrumb-bg: $gray-200; +// $breadcrumb-divider-color: $gray-600; +// $breadcrumb-active-color: $gray-600; +// $breadcrumb-divider: "/"; + + +// Carousel + +// $carousel-control-color: $white; +// $carousel-control-width: 15%; +// $carousel-control-opacity: .5; + +// $carousel-indicator-width: 30px; +// $carousel-indicator-height: 3px; +// $carousel-indicator-spacer: 3px; +// $carousel-indicator-active-bg: $white; + +// $carousel-caption-width: 70%; +// $carousel-caption-color: $white; + +// $carousel-control-icon-width: 20px; + +// $carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E"), "#", "%23"); +// $carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E"), "#", "%23"); + +// $carousel-transition: transform .6s ease; + + +// Close + +// $close-font-size: $font-size-base * 1.5; +// $close-font-weight: $font-weight-bold; +// $close-color: $black; +// $close-text-shadow: 0 1px 0 $white; + +// Code + +// $code-font-size: 87.5%; +// $code-color: $pink; + +// $kbd-padding-y: .2rem; +// $kbd-padding-x: .4rem; +// $kbd-font-size: $code-font-size; +// $kbd-color: $white; +// $kbd-bg: $gray-900; + +// $pre-color: $gray-900; +// $pre-scrollable-max-height: 340px; + + +// Printing +// $print-page-size: a3; +// $print-body-min-width: map-get($grid-breakpoints, "lg"); diff --git a/src/AppBundle/Resources/sass/content/_content.scss b/src/AppBundle/Resources/sass/content/_content.scss new file mode 100644 index 0000000..f6a4fa5 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/_content.scss @@ -0,0 +1,3 @@ +@import 'item_view_types/view_types'; +@import 'full/full'; +@import 'ezxmltext'; diff --git a/src/AppBundle/Resources/sass/content/_ezxmltext.scss b/src/AppBundle/Resources/sass/content/_ezxmltext.scss new file mode 100644 index 0000000..8ead1d3 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/_ezxmltext.scss @@ -0,0 +1,128 @@ +/* EMBEDED OBJECTS ----------------------------------------------------- */ +.object-left { + float: left; + clear: left; + margin-right: 2.5%; +} +.object-right { + float: right; + clear: right; + margin-left: 2.5%; +} +.object-left, +.object-right { + max-width: 47.5%; +} +.object-center { + .view-type-embed { + max-width: 75%; + margin: 0 auto; + } +} +.view-type-embed { + &.image, + &.ng-gallery { + margin-bottom: 2rem; + } + &.ng-video { + margin: 20px 0; + h4 { + margin: 10px 0; + } + } +} +.clear { + clear: both; +} + +@include media-breakpoint-down(xs) { + .object-left, + .object-right { + width: 100%; + max-width: 100%; + margin-left: 0; + margin-right: 0; + } + .object-center { + .view-type-embed { + max-width: 100%; + } + } +} +/* /EMBEDED OBJECTS */ + +/* ezxmltext elements */ +.ezxmltext-field { + p { + margin: 0 0 2em; + a:not(.btn) { + border-bottom: .25rem solid $primary; + transition: border .3s; + &:hover { + color: inherit; + border-color: darken($primary, 15%); + } + } + } + ul { + list-style-type: none; + margin: 0 0 2em; + padding: 0; + > li { + position: relative; + margin: 0 0 1em; + padding: 0 0 0 1.5em; + &::before { + content: ''; + position: absolute; + left: 0; + top: .2777777778em; + width: .8888888889em; + height: .8888888889em; + background: $primary; + } + } + } + ol { + counter-reset: ol-counter; + list-style-type: none; + margin: 0 0 2em; + padding: 0; + > li { + position: relative; + margin: 0 0 1em; + padding: 0 0 0 1.5em; + &::before { + counter-increment: ol-counter; + content: counter(ol-counter)'.'; + position: absolute; + left: 0; + font-weight: 900; + color: $primary; + } + } + } + blockquote { + background-color: rgba(254, 215, 47, .04); + border-bottom: .375rem solid $primary; + padding: 2rem; + margin-bottom: 2rem; + text-align: center; + .blockquote-body { + font-size: 1.5625rem; + font-style: italic; + &::before { + @extend %fontawesome; + content: '\f10d'; + color: $primary; + font-size: 2.5em; + } + } + p { + margin: 0; + + p { + margin-top: 2em; + } + } + } +} diff --git a/src/AppBundle/Resources/sass/content/full/_article.scss b/src/AppBundle/Resources/sass/content/full/_article.scss new file mode 100644 index 0000000..0c38303 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_article.scss @@ -0,0 +1,91 @@ +/* article full view */ +.full-article-header { + padding-bottom: 14rem; + margin-bottom: -10rem; + text-align: left; +} + +.full-article-image { + @include media-breakpoint-down(md) { + img { + width: 100%; + } + } + margin: 0; + text-align: center; +} + +.full-article-content { + @include media-breakpoint-down(lg) { + padding: 0 8rem; + } + @include media-breakpoint-down(md) { + padding: 0 5rem; + } + @include media-breakpoint-down(sm) { + padding: 0 2rem; + } + @include media-breakpoint-down(xs) { + padding: 0; + } + padding: 0 11.125rem; +} + +.full-article-tags { + @extend %clearfix; + margin: 3rem 0 0; + a { + display: inline-block; + float: left; + font-size: .75rem; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 900; + color: $gray-87; + padding: .1666666667em .8333333333em; + border: 2px solid $primary; + margin: 0 .1666666667em; + } +} + +/* full article body styling */ +.full-article-body { + @extend %clearfix; + padding: 4rem 4rem 2rem; + background: $body-bg; + .article-intro { + font-size: 1.3125rem; + font-style: italic; + color: $gray-54; + } + .object-full { + margin-left: -4rem; + margin-right: -4rem; + } + .object-left > .view-type-embed { + margin-left: -4rem; + } + .object-right > .view-type-embed { + margin-right: -4rem; + } + div:not([class^='object-']) > .view-type-embed { + margin-left: -4rem; + margin-right: -4rem; + } +} + +/* single column article layout */ +.vf1 { + .full-article-header { + padding: 4rem 0; + margin-bottom: 4rem; + text-align: center; + } + .full-article-body { + padding: 0; + margin: 0 0 2rem; + } + .full-article-image { + margin: 0 0 4rem; + } +} diff --git a/src/AppBundle/Resources/sass/content/full/_feedback_form.scss b/src/AppBundle/Resources/sass/content/full/_feedback_form.scss new file mode 100644 index 0000000..ac55310 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_feedback_form.scss @@ -0,0 +1,34 @@ +/* feedback gorm full view */ +.full-form-content { + padding: 2rem; + margin: 0 auto 4rem; + background: $white; + max-width: 35rem; + a { + border-bottom: .25rem solid $primary; + } +} + +.full-form-header { + padding-bottom: 10rem; + margin-bottom: -10rem; +} + +.full-form-response { + text-align: center; + min-height: 15rem; + p { + font-size: 2rem; + font-style: italic; + } +} + +.alert { + font-size: 1rem; + padding: 1em; + margin: 0 0 1.5em; + &.alert-danger { + background: hsl(0, 100, 80); + color: $white; + } +} diff --git a/src/AppBundle/Resources/sass/content/full/_full.scss b/src/AppBundle/Resources/sass/content/full/_full.scss new file mode 100644 index 0000000..0eb6933 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_full.scss @@ -0,0 +1,7 @@ +@import 'full_page_elements'; +@import 'article'; +@import 'recipe'; +@import 'video'; +@import 'gallery'; +@import 'feedback_form'; +@import 'search'; diff --git a/src/AppBundle/Resources/sass/content/full/_full_page_elements.scss b/src/AppBundle/Resources/sass/content/full/_full_page_elements.scss new file mode 100644 index 0000000..6bffaf3 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_full_page_elements.scss @@ -0,0 +1,75 @@ +.full-page-header { + background: $primary; + padding: 4rem 0; + text-align: center; + .full-page-title { + font-size: 3.125rem; + margin: 0 0 .5rem; + } + .full-page-intro { + color: $black; + opacity: .54; + p { + margin: 0; + + p { + margin-top: 1em; + } + } + } + .full-page-info { + font-size: 1rem; + margin: 0; + color: $black; + opacity: .54; + > span, + > time { + + span, + + time { + &::before { + content: '-'; + margin: 0 .25em; + } + } + } + a { + transition: border-color .15s; + border-bottom: .125rem solid transparent; + &:hover { + border-bottom-color: currentColor; + } + } + } + .full-page-main-tag, + .full-page-sponsored-tag { + > a, + > span { + display: inline-block; + font-size: .75rem; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 900; + color: $primary; + background: $black; + padding: .3333333333em 1em; + margin: 0 0 .3333333333em; + } + } +} + +/* full page newsletter box */ +.full-page-newsletter-box { + background: $primary; + padding: 2rem; + margin: 0 0 4rem; + text-align: center; + form { + display: flex; + justify-content: center; + max-width: 400px; + margin: 2rem auto 0; + .form-control { + border-color: $white; + background: $white; + } + } +} diff --git a/src/AppBundle/Resources/sass/content/full/_gallery.scss b/src/AppBundle/Resources/sass/content/full/_gallery.scss new file mode 100644 index 0000000..635b6dc --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_gallery.scss @@ -0,0 +1,5 @@ +/* gallery full view */ +.full-gallery-header { + padding-bottom: 14rem; + margin-bottom: -10rem; +} diff --git a/src/AppBundle/Resources/sass/content/full/_recipe.scss b/src/AppBundle/Resources/sass/content/full/_recipe.scss new file mode 100644 index 0000000..775cab8 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_recipe.scss @@ -0,0 +1,38 @@ +/* recipe full view */ +.full-recipe-info { + .recipe-calories { + text-align: center; + font-size: 1.75rem; + font-weight: 900; + } + + .recipe-serving-info { + list-style-type: none; + margin: 2rem 0 0; + padding: 0; + text-align: center; + li { + display: inline-block; + font-size: 1.3125rem; + font-weight: 900; + margin: 0 .7em; + .tt { + display: block; + font-size: .5714285714em; + color: $gray-38; + text-transform: uppercase; + } + } + } + + .recipe-time { + @extend %clearfix; + margin: 2rem 0 0; + padding: 2rem 0 0; + border-top: 2px dashed hsla(0, 0, 0, .12); + time { + float: right; + font-weight: 900; + } + } +} diff --git a/src/AppBundle/Resources/sass/content/full/_search.scss b/src/AppBundle/Resources/sass/content/full/_search.scss new file mode 100644 index 0000000..c7c75e4 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_search.scss @@ -0,0 +1,40 @@ +/* search results full page */ +.full-search-header { + .search-inputs { + margin: 0 auto; + max-width: 45rem; + } + .form-control { + border: 0; + } + .result-message { + margin: 2rem 0 0; + h2 { + font-size: 1.75rem; + margin: 0; + } + } +} + +.full-search-results { + margin: 4rem 0; + .full-no-results-list { + list-style-type: none; + margin: 0 0 2em; + padding: 0; + > li { + position: relative; + margin: 0 0 1em; + padding: 0 0 0 1.5em; + &::before { + content: ''; + position: absolute; + left: 0; + top: .2777777778em; + width: .8888888889em; + height: .8888888889em; + background: $primary; + } + } + } +} diff --git a/src/AppBundle/Resources/sass/content/full/_video.scss b/src/AppBundle/Resources/sass/content/full/_video.scss new file mode 100644 index 0000000..a876b34 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/full/_video.scss @@ -0,0 +1,23 @@ +/* video full view */ +.vf3 { + .full-video-player { + margin: 0 0 2rem; + } + .full-video-header { + .title { + font-size: 2.375rem; + margin: 0 0 .25rem; + line-height: 1.4; + } + .info { + font-size: .75rem; + font-weight: 900; + margin: 0 0 .25rem; + text-transform: uppercase; + letter-spacing: 1px; + } + } + .body { + font-size: 1rem; + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_extends.scss b/src/AppBundle/Resources/sass/content/item_view_types/_extends.scss new file mode 100644 index 0000000..153bd98 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_extends.scss @@ -0,0 +1,67 @@ +%item-header-info { + @extend %clearfix; + margin: 0 0 .25rem; + text-transform: uppercase; + font-size: .8125rem; + letter-spacing: 1px; + > span, + > time, + > a { + display: inline-block; + float: left; + margin-right: .25rem; + + span, + + time, + + a { + &::before { + content: ''; + display: inline-block; + vertical-align: middle; + width: .25rem; + height: .25rem; + background: $primary; + margin: 0 .25rem .125rem 0; + } + } + } + a, + .sponsored-tag { + font-weight: 700; + color: $tertiary; + } + a { + transition: border-color .15s; + border-bottom: .125rem solid transparent; + &:hover { + border-bottom-color: currentColor; + } + } + .recipe-details { + background: $secondary; + padding: 0 .6153846154em; + color: $gray-87; + i { + color: $gray-38; + font-size: .8461538462em; + margin: 0 0 .1538461538em; + } + span + span { + margin-left: 1em; + } + &::before { + display: none; + } + } + @include media-breakpoint-down(lg) { + font-size: .75rem; + } +} + +%item-title-link { + transition: border-color .15s; + border-bottom: 4px solid transparent; + &:hover { + color: inherit; + border-bottom-color: $primary; + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_line.scss b/src/AppBundle/Resources/sass/content/item_view_types/_line.scss new file mode 100644 index 0000000..270f44a --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_line.scss @@ -0,0 +1,71 @@ +/* line item view type */ +.vl4 { + margin: 0 0 2rem; + display: flex; + position: relative; + .image { + width: 44%; + a { + display: block; + position: relative; + height: 0; + padding-bottom: 56.25%; + } + img { + object-fit: cover; + object-position: center; + position: absolute; + width: 100%; + height: 100%; + } + + .article-content { + padding-left: $gap; + } + } + .article-content { + flex: 1; + } + .title { + font-size: 1.5rem; + font-weight: 900; + margin: 0 0 .25rem; + a { + @extend %item-title-link; + } + } + .short { + color: $gray-54; + p { + margin: 0; + } + } + .info { + @extend %item-header-info; + } + .article-icon { + position: absolute; + left: 0; + top: 0; + width: 3rem; + height: 3rem; + line-height: 3rem; + text-align: center; + background: $primary; + color: $black; + z-index: 2; + pointer-events: none; + + .article-content { + padding-left: 4.875rem; + } + } + @include media-breakpoint-down(xxs) { + display: block; + .image { + width: 100%; + + .article-content { + padding-left: 0; + padding-top: 1rem; + } + } + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_listitem.scss b/src/AppBundle/Resources/sass/content/item_view_types/_listitem.scss new file mode 100644 index 0000000..ad3b798 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_listitem.scss @@ -0,0 +1,43 @@ +/* list item view type */ +.vl6 { + margin: 0 0 2rem; + padding: 0 0 2rem; + border-bottom: 1px solid hsla(0, 0, 0, .12); + .title { + font-size: 1.125rem; + line-height: 1.33333333; + font-weight: 900; + margin: 0 0 .25rem; + a { + @extend %item-title-link; + } + } + .short { + margin: .25rem 0 0; + color: $gray-54; + p { + margin: 0; + } + } + .info { + @extend %item-header-info; + } + .article-icon { + position: absolute; + left: 0; + top: 0; + width: 2.125rem; + height: 2.125rem; + line-height: 2.125rem; + text-align: center; + background: $primary; + color: $black; + z-index: 2; + } + + /* with icon */ + &.t1 { + padding-left: 3.125rem; + position: relative; + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_mini.scss b/src/AppBundle/Resources/sass/content/item_view_types/_mini.scss new file mode 100644 index 0000000..c8822a8 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_mini.scss @@ -0,0 +1,49 @@ +/* mini item view type */ +.vl5 { + margin: 0 0 1rem; + display: flex; + .image { + position: relative; + width: 5rem; + height: 5rem; + img { + object-fit: cover; + object-position: center; + position: absolute; + width: 100%; + height: 100%; + } + + .article-header { + padding-left: 1rem; + } + } + .article-header { + flex: 1; + } + .title { + font-size: 1.125rem; + line-height: 1.33333333; + font-weight: 900; + margin: 0 0 .25rem; + a { + @extend %item-title-link; + } + } + .info { + @extend %item-header-info; + } + .article-icon { + position: absolute; + left: 50%; + top: 50%; + transform: translate3d(-50%, -50%, 0); + width: 2.125rem; + height: 2.125rem; + line-height: 2.125rem; + text-align: center; + background: $primary; + color: $black; + z-index: 2; + pointer-events: none; + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_overlay.scss b/src/AppBundle/Resources/sass/content/item_view_types/_overlay.scss new file mode 100644 index 0000000..9951a5a --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_overlay.scss @@ -0,0 +1,117 @@ +/* overlay item view type */ +.vl2 { + margin: 0 0 2rem; + position: relative; + a { + color: inherit; + &:hover { + color: inherit; + } + } + .image-16by9 { + display: block; + position: relative; + height: 0; + padding-bottom: 56.25%; + overflow: hidden; + img { + object-fit: cover; + object-position: center; + position: absolute; + width: 100%; + height: 100%; + transition: transform .75s ease-out; + will-change: transform; + } + &::before { + content: ''; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + background: linear-gradient(transparent,rgba(0,0,0,0.9)); + z-index: 2; + transition: opacity .75s ease-out; + } + } + .article-header { + position: absolute; + z-index: 3; + bottom: 1.75rem; + left: 2rem; + right: 2rem; + color: $white; + } + .title { + font-size: 1.3125rem; + margin: 0 0 .25rem; + line-height: 1.25; + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + max-height: 5em; + a { + @extend %item-title-link; + } + } + .info { + @extend %item-header-info; + margin: 0; + .recipe-details { + background: hsla(0, 0, 100, .25); + color: $white; + } + } + .article-icon { + position: absolute; + left: 0; + top: 0; + width: 3em; + height: 3em; + font-size: 1rem; + line-height: 3; + text-align: center; + background: $primary; + color: $black; + z-index: 3; + pointer-events: none; + } + &:hover, + &:focus { + .image-16by9 { + &::before { + opacity: .75; + } + img { + transform: scale(1.08); + } + } + } + @include media-breakpoint-down(lg) { + .article-header { + bottom: 1.25rem; + left: 1.5rem; + right: 1.5rem; + } + .title { + font-size: 1.25rem; + } + } + @include media-breakpoint-down(sm) { + .article-header { + bottom: 1rem; + left: 1.25rem; + right: 1.25rem; + } + .title { + -webkit-line-clamp: 3; + max-height: 3.75em; + } + .article-icon { + font-size: .75rem; + } + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_search.scss b/src/AppBundle/Resources/sass/content/item_view_types/_search.scss new file mode 100644 index 0000000..f271f40 --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_search.scss @@ -0,0 +1,40 @@ +/* search result item */ +.vl7 { + background: $secondary; + margin: 0 0 2rem; + padding: 2rem; + .article-content { + display: flex; + } + .image { + width: 10rem; + + .article-content-text { + padding-left: $gap; + } + } + .article-content-text { + flex: 1; + } + .title { + font-size: 1.5rem; + font-weight: 900; + margin: 0 0 .25rem; + a { + @extend %item-title-link; + } + } + .short { + color: $gray-54; + p { + margin: 0; + } + } + .info { + @extend %item-header-info; + } + .type { + text-transform: uppercase; + font-size: .8125rem; + letter-spacing: 1px; + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_standard.scss b/src/AppBundle/Resources/sass/content/item_view_types/_standard.scss new file mode 100644 index 0000000..57c690d --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_standard.scss @@ -0,0 +1,57 @@ +/* standard item view type */ +.vl1 { + margin: 0 0 2rem; + position: relative; + .image { + position: relative; + width: 100%; + height: 0; + padding-bottom: 56.25%; + margin: 0 0 1rem; + img { + object-fit: cover; + object-position: center; + position: absolute; + width: 100%; + height: 100%; + } + } + .title { + font-size: 1.5rem; + font-weight: 900; + margin: 0 0 .25rem; + a { + @extend %item-title-link; + } + } + .short { + color: $gray-54; + p { + margin: 0; + } + } + .info { + @extend %item-header-info; + } + .article-icon { + position: absolute; + left: 0; + top: 0; + width: 3rem; + height: 3rem; + line-height: 3rem; + text-align: center; + background: $primary; + color: $black; + z-index: 2; + pointer-events: none; + + .article-header { + padding-top: 3.5rem; + } + } + @include media-breakpoint-down(lg) { + .title { + font-size: 1.25rem; + } + } +} diff --git a/src/AppBundle/Resources/sass/content/item_view_types/_view_types.scss b/src/AppBundle/Resources/sass/content/item_view_types/_view_types.scss new file mode 100644 index 0000000..20c7e3b --- /dev/null +++ b/src/AppBundle/Resources/sass/content/item_view_types/_view_types.scss @@ -0,0 +1,7 @@ +@import 'extends'; +@import 'standard'; +@import 'overlay'; +@import 'listitem'; +@import 'mini'; +@import 'line'; +@import 'search'; diff --git a/src/AppBundle/Resources/sass/layout/_footer.scss b/src/AppBundle/Resources/sass/layout/_footer.scss new file mode 100644 index 0000000..80950ec --- /dev/null +++ b/src/AppBundle/Resources/sass/layout/_footer.scss @@ -0,0 +1,74 @@ +.site-footer { + background: $footer-bg; + color: $white; + padding: 4rem 0; + text-align: center; + a:not(.site-logo) { + &:hover, + &:focus { + color: $gray-38; + } + } + .site-logo { + margin: 0 0 1.5rem; + } + + /* footer menu */ + .footer-menu { + .navbar-nav { + list-style-type: none; + display: flex; + justify-content: center; + margin: 0 0 1.5rem; + padding: 0; + a { + font-size: .875rem; + text-transform: uppercase; + font-weight: 900; + letter-spacing: 1px; + padding: .5em 1.1428571429em; + } + } + } + + /* footer social */ + .footer-social { + ul { + list-style-type: none; + margin: 0 0 1.5rem; + padding: 0; + display: flex; + justify-content: center; + a { + font-size: 1.125rem; + padding: .5em; + margin: 0 .5em; + } + .tt { + display: none; + } + } + } + + /* footer info */ + .footer-info { + font-size: .875rem; + color: $gray-54; + p { + margin: 0 0 .5714285714em; + } + address { + color: $white; + a { + font-weight: 900; + } + } + } + @include media-breakpoint-down(sm) { + .footer-menu { + .navbar-nav { + display: block; + } + } + } +} diff --git a/src/AppBundle/Resources/sass/layout/_header.scss b/src/AppBundle/Resources/sass/layout/_header.scss new file mode 100644 index 0000000..c2a7bb8 --- /dev/null +++ b/src/AppBundle/Resources/sass/layout/_header.scss @@ -0,0 +1,149 @@ +$header-bg: $white; + +/* site header */ +.site-header { + background: $header-bg; + box-shadow: 0 .5rem 1rem 0 hsla(0, 0, 0, .08); + position: relative; + > .container { + height: $header-height; + display: flex; + align-items: center; + } + @include media-breakpoint-down(md) { + > .container { + height: $header-height-sm; + position: relative; + } + } +} + +/* header language selector */ +.language-selector { + margin: 0 0 0 1em; + a { + @extend %hover-underline; + font-size: .75rem; + text-transform: uppercase; + letter-spacing: 1px; + font-weight: 700; + color: $black; + } + .current-lang { + height: $header-height; + display: flex; + align-items: center; + padding: 0 1em; + transition: color .2s; + i { + font-size: 1.25em; + } + } + .dropdown-menu { + border: 0; + background: $primary; + margin: 0; + text-align: right; + right: 0; + left: auto !important; + box-shadow: 0 .5rem 1rem 0 rgba(0, 0, 0, .1); + a { + padding: .5em 1em; + display: block; + } + .current { + a { + color: $gray-54; + } + } + } + &.show { + .current-lang { + position: relative; + z-index: 1001; + background: $primary; + } + } +} + +/* header-searchbox */ +.header-search { + $btn-width: 4rem; + height: $header-height; + position: relative; + .searchbox-toggle { + @extend %hover-underline; + color: $black; + display: block; + font-size: 1rem; + line-height: $header-height; + width: $btn-width; + text-align: center; + background: $header-bg; + z-index: 2; + transition: color .2s, background .3s; + } + .navbar-search { + padding: 1rem $btn-width 1rem 1rem; + width: 0; + transition: width .4s, opacity .23s; + position: absolute; + right: 0; + top: 0; + bottom: 0; + display: flex; + background: $primary; + opacity: 0; + } + .search-query { + flex: 1; + width: 100%; + background: transparent; + border: 0; + border-bottom: 2px solid $black; + &:focus { + outline: none; + } + } + .search-submit { + width: $btn-width; + position: absolute; + right: 0; + top: 0; + bottom: 0; + cursor: pointer; + } + + /* searchbox opened */ + .searchbox-active & { + .searchbox-toggle { + background: $primary; + transition: color .2s; + } + .navbar-search { + opacity: 1; + width: 18rem; + transition: width .4s; + } + /* entered text in input */ + &.filled { + .searchbox-toggle { + pointer-events: none; + } + } + } + @include media-breakpoint-down(md) { + height: $header-height-sm; + position: absolute; + right: $gutter + $header-height-sm; + .searchbox-toggle { + line-height: $header-height-sm; + } + } + @include media-breakpoint-down(xs) { + right: $header-height-sm; + .searchbox-toggle { + width: 3rem; + } + } +} diff --git a/src/AppBundle/Resources/sass/layout/_layout.scss b/src/AppBundle/Resources/sass/layout/_layout.scss new file mode 100644 index 0000000..575b3ab --- /dev/null +++ b/src/AppBundle/Resources/sass/layout/_layout.scss @@ -0,0 +1,4 @@ +@import 'site_logo'; +@import 'header'; +@import 'navigation'; +@import 'footer'; diff --git a/src/AppBundle/Resources/sass/layout/_navigation.scss b/src/AppBundle/Resources/sass/layout/_navigation.scss new file mode 100644 index 0000000..0e67132 --- /dev/null +++ b/src/AppBundle/Resources/sass/layout/_navigation.scss @@ -0,0 +1,211 @@ +.main-navigation { + flex: 1; + .navbar-nav { + display: flex; + justify-content: center; + list-style-type: none; + margin: 0; + padding: 0 1rem; + text-align: center; + > li { + position: relative; + > a, + > span { + @extend %hover-underline; + display: inline-block; + font-weight: 700; + font-size: .75rem; + text-transform: uppercase; + letter-spacing: 1px; + padding: 0 1.3333333333em; + } + } + } + /* main submenu */ + .menu_level_1 { + list-style-type: none; + padding: 1rem 0; + margin: 0; + display: none; + a { + display: block; + padding: .5em 1.5em; + } + } + /* large screen sizes */ + @include media-breakpoint-up(lg) { + .navbar-nav { + > li:hover, + .active { + > a, + > span { + color: $black; + &::after { + transform: scaleY(1); + } + } + } + > li { + > a, + > span { + display: flex; + height: $header-height; + align-items: center; + justify-content: center; + color: $gray-54; + } + &:hover { + .menu_level_1 { + display: block; + } + } + } + } + .menu_level_1 { + position: absolute; + top: 100%; + left: 0; + width: 16rem; + z-index: 20; + background: $primary; + box-shadow: 0 .5rem 1rem hsla(0, 0, 0, .12); + a { + font-size: .75rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 1px; + &:hover { + background: hsla(0, 0, 0, .05); + } + } + } + } + .submenu-trigger { + @extend %fontawesome; + display: none; + } + /* small screen sizes */ + @include media-breakpoint-down(md) { + display: none; + position: absolute; + left: $gutter; + right: $gutter; + top: $header-height-sm; + z-index: 1000; + background: $primary; + box-shadow: 0 .5rem 1rem hsla(0, 0, 0, .12); + .navbar-nav { + display: block; + margin: 0; + padding: 1rem 0; + > li { + > a, + > span { + padding: .5em 1em; + color: $gray-87; + &::after { + display: none; + } + } + &[data-submenu='true'] { + > a { + margin: 0 1.875rem; + } + } + &.submenu-active { + .menu_level_1 { + display: block; + } + .submenu-trigger { + &::before { + transform: rotate(180deg); + } + } + } + } + } + .mainnav-active & { + display: block; + } + .submenu-trigger { + display: inline-block; + position: absolute; + right: 0; + top: 0; + cursor: pointer; + width: 1.875rem; + height: 1.875rem; + line-height: 1.875rem; + font-size: .875rem; + &::before { + display: block; + content: '\f078'; + } + } + .menu_level_1 { + padding: 0 0 1rem; + a { + color: $gray-54; + font-size: .875rem; + } + } + } + @include media-breakpoint-down(xs) { + left: 0; + right: 0; + } +} + +.mainnav-toggle { + display: none; + position: absolute; + right: $gutter; + width: $header-height-sm; + height: $header-height-sm; + .hamburger { + display: block; + width: 1.25rem; + height: .125rem; + position: absolute; + background: currentColor; + left: 50%; + top: 50%; + margin: -.0625rem 0 0 -.625rem; + transition: background 400ms ease-out 200ms; + &::before, + &::after { + display: block; + content: ''; + width: 100%; + height: 100%; + position: absolute; + background: currentColor; + transition: all 400ms; + } + &::before { + top: -.375rem; + } + &::after { + bottom: -.375rem; + } + } + .mainnav-active & { + background: $primary; + .hamburger { + background: transparent; + transition: background 100ms ease-out; + &::before { + transform: translate(0, .375rem) rotate(135deg); + } + &::after { + transform: translate(0, -.375rem) rotate(-135deg); + } + } + } + @include media-breakpoint-down(md) { + display: block; + } + @include media-breakpoint-down(xs) { + right: 0; + } +} diff --git a/src/AppBundle/Resources/sass/layout/_site_logo.scss b/src/AppBundle/Resources/sass/layout/_site_logo.scss new file mode 100644 index 0000000..acee429 --- /dev/null +++ b/src/AppBundle/Resources/sass/layout/_site_logo.scss @@ -0,0 +1,13 @@ +.site-logo { + display: inline-block; + width: 14rem; + img { + width: 100%; + } + @include media-breakpoint-down(lg) { + width: 12rem; + } + @include media-breakpoint-down(md) { + width: 10rem; + } +} diff --git a/src/AppBundle/Resources/sass/style.scss b/src/AppBundle/Resources/sass/style.scss new file mode 100644 index 0000000..77adcfa --- /dev/null +++ b/src/AppBundle/Resources/sass/style.scss @@ -0,0 +1,15 @@ +@charset 'UTF-8'; +//IMPORTANT: only add imports to this file + +@import '@fortawesome/fontawesome-free/css/all'; +@import 'swiper/dist/css/swiper'; +@import 'magnific-popup/src/css/main'; +@import 'variables'; + +@import 'bootstrap_import/bootstrap_import'; + +@import 'typography'; +@import 'layout/layout'; +@import 'blocks/blocks'; +@import 'content/content'; +@import 'cookie_control'; diff --git a/src/AppBundle/Resources/symlink/root/offline_cro.html b/src/AppBundle/Resources/symlink/root/offline_cro.html new file mode 100644 index 0000000..b51ca9b --- /dev/null +++ b/src/AppBundle/Resources/symlink/root/offline_cro.html @@ -0,0 +1,27 @@ + + + + Održavanje stranica + + + + + + +
+

Web stranice trenutno nisu dostupne!

+ +
+

Upravo radimo na održavanju web stranica pa Vas molimo za strpljenje, uskoro ćemo opet biti dostupni.

+

— Tim

+
+
+ + diff --git a/src/AppBundle/Resources/symlink/root/offline_eng.html b/src/AppBundle/Resources/symlink/root/offline_eng.html new file mode 100644 index 0000000..672c5af --- /dev/null +++ b/src/AppBundle/Resources/symlink/root/offline_eng.html @@ -0,0 +1,27 @@ + + + + Site maintenance + + + + + + +
+

We’ll be back soon!

+ +
+

We’re performing some maintenance at the moment. You can always contact us if you need to, otherwise we’ll be back online shortly. Sorry for the inconvenience!

+

— The Team

+
+
+ + diff --git a/src/AppBundle/Resources/symlink/root_dev/.htaccess b/src/AppBundle/Resources/symlink/root_dev/.htaccess new file mode 100644 index 0000000..de1af87 --- /dev/null +++ b/src/AppBundle/Resources/symlink/root_dev/.htaccess @@ -0,0 +1,101 @@ +## eZ Platform/Symfony ENVIRONMENT variables, for customizing app.php* execution +# * Only SYMFONY_ENV and SYMFONY_DEBUG supported by console command, rest are eZ Platform features in app.php. + +# Environment. +# Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration +# Defaults to "prod" if omitted (uses SetEnvIf so value can be used in rewrite rules) +SetEnvIf Request_URI ".*" SYMFONY_ENV=dev + +# Optional: Whether to use debugging. +# Possible values: 0, 1 or "" +# Defaults to enabled if SYMFONY_ENV is set to "dev" if env value is omitted or empty +#SetEnv SYMFONY_DEBUG "0" + +# Optional: Whether to use Symfony's builtin HTTP Caching Proxy. +# Disable it if you are using an external reverse proxy (e.g. Varnish) +# Possible values: 0, 1 or "" +# Defaults to disabled if SYMFONY_ENV is set to "dev" or SYMFONY_TRUSTED_PROXIES is set, +# and if this env value is omitted or empty +#SetEnv SYMFONY_HTTP_CACHE "1" + +# Optional: Defines the proxies to trust +# Needed when using Varnish as proxy, if so disable SYMFONY_HTTP_CACHE. +# Separate entries by a comma, example: "ip1,ip2" +# Defaults to not be set if env value is omitted or empty +#SetEnv SYMFONY_TRUSTED_PROXIES "127.0.0.1" + +# TIP: There are many more environment variables supported by eZ Platform. However unlike those listed above +# they should in most cases rather be set in the environment then in vhost config to make sure cronjobs +# and cli command usage takes them into account as well. + +# NOTE: Using gzip on text/html can be a security issue. See http://breachattack.com. +# AddOutputFilterByType DEFLATE text/html +AddOutputFilterByType DEFLATE text/plain +AddOutputFilterByType DEFLATE text/xml +AddOutputFilterByType DEFLATE text/css +AddOutputFilterByType DEFLATE application/xml +AddOutputFilterByType DEFLATE application/json +AddOutputFilterByType DEFLATE application/xhtml+xml +AddOutputFilterByType DEFLATE application/rss+xml +AddOutputFilterByType DEFLATE application/javascript +AddOutputFilterByType DEFLATE application/x-javascript + +AddDefaultCharset UTF-8 + +DirectoryIndex app.php + +Options +FollowSymlinks +Options -Indexes + +RewriteEngine On + +RewriteCond %{ENV:REDIRECT_STATUS} ^$ +RewriteRule ^app(_.+)?\.php(/(.*)|$) /$3 [R=301,L] + +# Let's Encrypt support +RewriteRule ^\.well-known/acme-challenge/ - [L] + +# START: Multisite rewrite rules for robots.txt + +# RewriteRule ^robots_site1.txt$ - [L] +# RewriteCond %{HTTP_HOST} ^site1.example.com$ [NC] +# RewriteRule ^robots.txt$ robots_site1.txt [L] + +# RewriteRule ^robots_site2.txt$ - [L] +# RewriteCond %{HTTP_HOST} ^site2.example.com$ [NC] +# RewriteRule ^robots.txt$ robots_site2.txt [L] + +# END: Multisite rewrite rules for robots.txt + +# START: Maintenance mode + +# RewriteRule ^offline_eng.html$ - [L] + +# RewriteRule .* offline_eng.html [R=503,L] +# ErrorDocument 503 /offline_eng.html + +# END: Maintenance mode + +# Disable .php(3) and other executable extensions in the var directory +RewriteRule ^var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ - [F] + +RewriteRule ^var/([^/]+/)?storage/images(-versioned)?/.* - [L] +RewriteRule ^var/([^/]+/)?storage/original/image/(.*)\.svg - [L] +RewriteRule ^var/([^/]+/)?cache/(texttoimage|public)/.* - [L] +RewriteRule ^design/[^/]+/(stylesheets|images|fonts|javascript)/.* - [L] +RewriteRule ^share/icons/.* - [L] +RewriteRule ^extension/[^/]+/design/[^/]+/(stylesheets|flash|images|fonts|lib|javascripts?)/.* - [L] + +# Makes it possible to placed your favicon and robots.txt at the root of your web folder +RewriteRule ^favicon\.ico - [L] +RewriteRule ^robots\.txt - [L] + +# The following rules are needed to correctly display bundle and project assets +RewriteRule ^bundles/ - [L] +RewriteRule ^assets/ - [L] + +# Prevent access to website with direct usage of app.php in URL +# Does not work in .htaccess for some reason +# RewriteRule ^([^/]+/)?app\.php([/?#]|$) - [R=404,L] + +RewriteRule .* app\.php diff --git a/src/AppBundle/Resources/symlink/root_dev/robots.txt b/src/AppBundle/Resources/symlink/root_dev/robots.txt new file mode 100644 index 0000000..bc6330b --- /dev/null +++ b/src/AppBundle/Resources/symlink/root_dev/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: /layout/ diff --git a/src/AppBundle/Resources/symlink/root_prod/.htaccess b/src/AppBundle/Resources/symlink/root_prod/.htaccess new file mode 100644 index 0000000..c0d04ae --- /dev/null +++ b/src/AppBundle/Resources/symlink/root_prod/.htaccess @@ -0,0 +1,101 @@ +## eZ Platform/Symfony ENVIRONMENT variables, for customizing app.php* execution +# * Only SYMFONY_ENV and SYMFONY_DEBUG supported by console command, rest are eZ Platform features in app.php. + +# Environment. +# Possible values: "prod" and "dev" out-of-the-box, other values possible with proper configuration +# Defaults to "prod" if omitted (uses SetEnvIf so value can be used in rewrite rules) +#SetEnvIf Request_URI ".*" SYMFONY_ENV=prod + +# Optional: Whether to use debugging. +# Possible values: 0, 1 or "" +# Defaults to enabled if SYMFONY_ENV is set to "dev" if env value is omitted or empty +#SetEnv SYMFONY_DEBUG "0" + +# Optional: Whether to use Symfony's builtin HTTP Caching Proxy. +# Disable it if you are using an external reverse proxy (e.g. Varnish) +# Possible values: 0, 1 or "" +# Defaults to disabled if SYMFONY_ENV is set to "dev" or SYMFONY_TRUSTED_PROXIES is set, +# and if this env value is omitted or empty +SetEnv SYMFONY_HTTP_CACHE "0" + +# Optional: Defines the proxies to trust +# Needed when using Varnish as proxy, if so disable SYMFONY_HTTP_CACHE. +# Separate entries by a comma, example: "ip1,ip2" +# Defaults to not be set if env value is omitted or empty +#SetEnv SYMFONY_TRUSTED_PROXIES "127.0.0.1" + +# TIP: There are many more environment variables supported by eZ Platform. However unlike those listed above +# they should in most cases rather be set in the environment then in vhost config to make sure cronjobs +# and cli command usage takes them into account as well. + +# NOTE: Using gzip on text/html can be a security issue. See http://breachattack.com. +# AddOutputFilterByType DEFLATE text/html +AddOutputFilterByType DEFLATE text/plain +AddOutputFilterByType DEFLATE text/xml +AddOutputFilterByType DEFLATE text/css +AddOutputFilterByType DEFLATE application/xml +AddOutputFilterByType DEFLATE application/json +AddOutputFilterByType DEFLATE application/xhtml+xml +AddOutputFilterByType DEFLATE application/rss+xml +AddOutputFilterByType DEFLATE application/javascript +AddOutputFilterByType DEFLATE application/x-javascript + +AddDefaultCharset UTF-8 + +DirectoryIndex app.php + +Options +FollowSymlinks +Options -Indexes + +RewriteEngine On + +RewriteCond %{ENV:REDIRECT_STATUS} ^$ +RewriteRule ^app(_.+)?\.php(/(.*)|$) /$3 [R=301,L] + +# Let's Encrypt support +RewriteRule ^\.well-known/acme-challenge/ - [L] + +# START: Multisite rewrite rules for robots.txt + +# RewriteRule ^robots_site1.txt$ - [L] +# RewriteCond %{HTTP_HOST} ^site1.example.com$ [NC] +# RewriteRule ^robots.txt$ robots_site1.txt [L] + +# RewriteRule ^robots_site2.txt$ - [L] +# RewriteCond %{HTTP_HOST} ^site2.example.com$ [NC] +# RewriteRule ^robots.txt$ robots_site2.txt [L] + +# END: Multisite rewrite rules for robots.txt + +# START: Maintenance mode + +# RewriteRule ^offline_eng.html$ - [L] + +# RewriteRule .* offline_eng.html [R=503,L] +# ErrorDocument 503 /offline_eng.html + +# END: Maintenance mode + +# Disable .php(3) and other executable extensions in the var directory +RewriteRule ^var/.*(?i)\.(php3?|phar|phtml|sh|exe|pl|bin)$ - [F] + +RewriteRule ^var/([^/]+/)?storage/images(-versioned)?/.* - [L] +RewriteRule ^var/([^/]+/)?storage/original/image/(.*)\.svg - [L] +RewriteRule ^var/([^/]+/)?cache/(texttoimage|public)/.* - [L] +RewriteRule ^design/[^/]+/(stylesheets|images|fonts|javascript)/.* - [L] +RewriteRule ^share/icons/.* - [L] +RewriteRule ^extension/[^/]+/design/[^/]+/(stylesheets|flash|images|fonts|lib|javascripts?)/.* - [L] + +# Makes it possible to placed your favicon and robots.txt at the root of your web folder +RewriteRule ^favicon\.ico - [L] +RewriteRule ^robots\.txt - [L] + +# The following rules are needed to correctly display bundle and project assets +RewriteRule ^bundles/ - [L] +RewriteRule ^assets/ - [L] + +# Prevent access to website with direct usage of app.php in URL +# Does not work in .htaccess for some reason +# RewriteRule ^([^/]+/)?app\.php([/?#]|$) - [R=404,L] + +RewriteRule .* app\.php diff --git a/src/AppBundle/Resources/symlink/root_prod/robots.txt b/src/AppBundle/Resources/symlink/root_prod/robots.txt new file mode 100644 index 0000000..bc6330b --- /dev/null +++ b/src/AppBundle/Resources/symlink/root_prod/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: /layout/ diff --git a/src/AppBundle/Resources/translations/messages.en.yml b/src/AppBundle/Resources/translations/messages.en.yml new file mode 100644 index 0000000..cbefbbc --- /dev/null +++ b/src/AppBundle/Resources/translations/messages.en.yml @@ -0,0 +1,32 @@ +ngsite.layout.search: "Search" +ngsite.layout.search.button: "Go" +ngsite.layout.search_site: "Search %site_name%" +ngsite.layout.site_frontpage: "%site_name% front page" +ngsite.layout.meta_generator: "eZ Platform powered by Netgen" +ngsite.layout.powered_by: "Powered by" +ngsite.layout.cookie_settings: "Cookie settings" +ngsite.layout.sponsored: 'Sponsored' + +ngsite.search.title: 'Search' +ngsite.search.placeholder: 'Search' +ngsite.search.button: 'Search' + +ngsite.search.results: 'Search for "%searchText%" returned %searchCount% matches' +ngsite.search.no_results: 'No results were found when searching for "%searchText%".' + +ngsite.search.no_results.check_spelling: 'Check spelling of keywords.' +ngsite.search.no_results.change_keywords: 'Try changing some keywords (eg, "car" instead of "cars").' +ngsite.search.no_results.less_specific_keywords: 'Try searching with less specific keywords.' +ngsite.search.no_results.reduce_keywords: 'Reduce number of keywords to get more results.' + +ngsite.collected_info.success_text: 'Thank you for your feedback.' +ngsite.collected_info.return_to_site: 'Return to site' +ngsite.collected_info.button.send: 'Send form' +ngsite.collected_info.information_collected: 'The following information was collected' + +ngsite.layout.recipe.min: 'min' +ngsite.layout.recipe.cal: 'cal' +ngsite.layout.recipe.preparation_time: 'Preparation time' +ngsite.layout.recipe.fat: 'fat' +ngsite.layout.recipe.carbs: 'carbs' +ngsite.layout.recipe.protein: 'protein' diff --git a/src/AppBundle/Resources/translations/nglayouts.en.yml b/src/AppBundle/Resources/translations/nglayouts.en.yml new file mode 100644 index 0000000..147c59c --- /dev/null +++ b/src/AppBundle/Resources/translations/nglayouts.en.yml @@ -0,0 +1,4 @@ +block.plugin.background_color.primary: 'Primary (Yellow)' +block.plugin.background_color.secondary: 'Secondary (Light gray)' +block.plugin.background_color.white: 'White' +block.plugin.background_color.black: 'Black' diff --git a/src/AppBundle/Resources/translations/ngsite_errors.de.yml b/src/AppBundle/Resources/translations/ngsite_errors.de.yml new file mode 100644 index 0000000..b466c53 --- /dev/null +++ b/src/AppBundle/Resources/translations/ngsite_errors.de.yml @@ -0,0 +1,8 @@ +ngsite.errors.403.title: "Dies ist ein eingeschränkter Bereich" +ngsite.errors.403.message: "Sie haben keine Berechtigungen auf diese Seite zuzugreifen." +ngsite.errors.404.title: "Diese Seite existiert nicht" +ngsite.errors.404.message: "Die angeforderte Seite konnte nicht gefunden werden. Bitte benutzen Sie die Hauptnavigation oder suchen Sie nach, wonach Sie suchen." +ngsite.errors.500.title: "Etwas ist schief gelaufen" +ngsite.errors.500.message: "Es gibt ein Problem mit der von Ihnen gesuchten Seite und kann nicht angezeigt werden. Bitte versuchen Sie es später erneut." +ngsite.errors.default.title: "Ein Problem ist aufgetreten" +ngsite.errors.default.message: "Es tut uns leid, ein Problem ist aufgetreten. Bitte versuchen Sie es später erneut. Bleibt das Problem bestehen, kontaktieren Sie uns bitte." diff --git a/src/AppBundle/Resources/translations/ngsite_errors.en.yml b/src/AppBundle/Resources/translations/ngsite_errors.en.yml new file mode 100644 index 0000000..26750ad --- /dev/null +++ b/src/AppBundle/Resources/translations/ngsite_errors.en.yml @@ -0,0 +1,8 @@ +ngsite.errors.403.title: "This is a restricted area" +ngsite.errors.403.message: "You don't have necessary permissions to access this page." +ngsite.errors.404.title: "This page does not exist" +ngsite.errors.404.message: "The requested page could not be found. Please use main navigation or search to find what you are looking for." +ngsite.errors.500.title: "Something went wrong" +ngsite.errors.500.message: "There is a problem with the page you are looking for, and it cannot be displayed. Please try again later." +ngsite.errors.default.title: "A problem occurred" +ngsite.errors.default.message: "We are sorry, a problem occurred. Please try again later. If the problem persists please contact us." diff --git a/src/AppBundle/Resources/translations/ngsite_errors.fr.yml b/src/AppBundle/Resources/translations/ngsite_errors.fr.yml new file mode 100644 index 0000000..a7b4a31 --- /dev/null +++ b/src/AppBundle/Resources/translations/ngsite_errors.fr.yml @@ -0,0 +1,8 @@ +ngsite.errors.403.title: "Vous n'avez pas les permissions nécessaires pour accéder à cet espace." +ngsite.errors.403.message: "Vous n'avez pas les permissions nécessaires pour accéder à cette page." +ngsite.errors.404.title: "Cette page n'existe pas." +ngsite.errors.404.message: "La page demandée n'a pas pu être trouvée. Veuillez utiliser la navigation principale ou la recherche pour trouver ce que vous cherchez." +ngsite.errors.500.title: "Quelque chose ne fonctionne pas. Si le problème persiste, veuillez nous contacter." +ngsite.errors.500.message: "Il y a un problème avec la page que vous recherchez. Veuillez réessayer plus tard." +ngsite.errors.default.title: "Un problème est survenu." +ngsite.errors.default.message: "Nous sommes désolés, un problème est survenu. Veuillez réessayer plus tard et si le problème persiste, veuillez nous contacter." diff --git a/src/AppBundle/Resources/translations/ngsite_mail.en.yml b/src/AppBundle/Resources/translations/ngsite_mail.en.yml new file mode 100644 index 0000000..370befd --- /dev/null +++ b/src/AppBundle/Resources/translations/ngsite_mail.en.yml @@ -0,0 +1,32 @@ +ngsite.user.welcome.subject: "Welcome" +ngsite.user.welcome.text: "Thank you for registering at our site." + +ngsite.user.activate.subject: "Account activation" +ngsite.user.activate.text: "Click the following link to activate your account:" +ngsite.user.activate.already_active.subject: "Account activation attempt" +ngsite.user.activate.already_active.text: "Your account is already active." +ngsite.user.activate.disabled.subject: "Account activation attempt" +ngsite.user.activate.disabled.text: "You have attempted to activate your account, but your account has been previously disabled." +ngsite.user.activate.not_registered.subject: "Account activation attempt" +ngsite.user.activate.not_registered.text: "You (or someone else) entered this e-mail address to receive an account activation link. However, this e-mail address is not registered on our site. If this was you, you probably used some other e-mail address during registration. If not, please ignore this e-mail." + +ngsite.user.activate.admin_activation_pending.subject: "Account activation pending" +ngsite.user.activate.admin_activation_pending.text: "Your account is waiting activation" + +ngsite.user.activate.admin_activation_required.subject: "Account activation required" +ngsite.user.activate.admin_activation_required.text: "This account is waiting for your activation" + +ngsite.user.forgot_password.subject: "Password reset" +ngsite.user.forgot_password.text: "Click the following link to reset your password:" +ngsite.user.forgot_password.disabled.subject: "Password reset attempt" +ngsite.user.forgot_password.disabled.text: "You have attempted to reset your password, but your account has been previously disabled." +ngsite.user.forgot_password.not_active.subject: "Password reset attempt" +ngsite.user.forgot_password.not_active.text: "You have attempted to reset your password, but your account is not active yet." +ngsite.user.forgot_password.not_registered.subject: "Password reset attempt" +ngsite.user.forgot_password.not_registered.text: "You (or someone else) entered this e-mail address to receive a password reset link. However, this e-mail address is not registered on our site. If this was you, you probably used some other e-mail address during registration. If not, please ignore this e-mail." +ngsite.user.forgot_password.password_changed.subject: "Password changed" +ngsite.user.forgot_password.password_changed.text: "Your password has been successfully changed." + +ngsite.user.account_information: "Your account information" +ngsite.user.username: "Username" +ngsite.user.email: "E-mail" diff --git a/src/AppBundle/Resources/translations/ngsite_user.en.yml b/src/AppBundle/Resources/translations/ngsite_user.en.yml new file mode 100644 index 0000000..7c4b445 --- /dev/null +++ b/src/AppBundle/Resources/translations/ngsite_user.en.yml @@ -0,0 +1,47 @@ +ngsite.user.login.title: 'Login' +ngsite.user.login.username.label: 'Username or e-mail' +ngsite.user.login.username.placeholder: 'Enter your username or e-mail' +ngsite.user.login.password.label: 'Password' +ngsite.user.login.password.placeholder: 'Enter your password' +ngsite.user.login.submit: 'Login' +ngsite.user.login.forgot_password_link: 'Forgot password?' +ngsite.user.login.register_text: "Don't have an account?" +ngsite.user.login.register_link: 'Register.' + +ngsite.user.register.title: 'Register' +ngsite.user.register.submit: 'Register' +ngsite.user.register.error.email_in_use: 'E-mail has already been registered.' +ngsite.user.register.error.username_taken: 'Username has already been taken.' +ngsite.user.register.error.other: 'Unspecified error occurred.' +ngsite.user.register.success.title: 'You have been registered!' +ngsite.user.register.success.text: 'Your account has successfully been created! You can now go ahead and log in.' + +ngsite.user.activate.title: 'Account activation' +ngsite.user.activate.text: 'Enter your e-mail address below and we will send you an e-mail so you activate your account.' +ngsite.user.activate.email.label: 'E-mail' +ngsite.user.activate.submit: 'Send' +ngsite.user.activate.sent.title: 'Account activation' +ngsite.user.activate.sent.text: 'We have sent you an e-mail with further instructions. Please check your inbox (and spam folder). If you have not received the mail, click here to send it again.' +ngsite.user.activate.done.title: 'Account activation' +ngsite.user.activate.done.text: 'Your account has been activated. You can now log in here.' +ngsite.user.activate.done.error.hash_expired: 'Provided hash key has expired. Please request a new one here.' +ngsite.user.activate.done.error.other: 'Unspecified error occurred.' +ngsite.user.activate.admin_activation_pending.title: 'Account activation' +ngsite.user.activate.admin_activation_pending.text: 'Your account was successfully created. Before you can log into the site, your account must be activated by the site administrator. You will receive an email confirming activation of your account soon.' + +ngsite.user.forgot_password.title: 'Forgot password?' +ngsite.user.forgot_password.text: 'Enter your e-mail address below and we will send you an e-mail so you can reset your password.' +ngsite.user.forgot_password.email.label: 'E-mail' +ngsite.user.forgot_password.submit: 'Send' +ngsite.user.forgot_password.sent.title: 'Forgot password?' +ngsite.user.forgot_password.sent.text: 'We have sent you an e-mail with further instructions. Please check your inbox (and spam folder). If you have not received the mail, click here to send it again.' + +ngsite.user.reset_password.title: 'Reset your password' +ngsite.user.reset_password.text: 'Enter your new password into the fields below and we will change it for you.' +ngsite.user.reset_password.first.label: 'New password' +ngsite.user.reset_password.second.label: 'Repeat new password' +ngsite.user.reset_password.submit: 'Reset password' +ngsite.user.reset_password.done.title: 'Reset your password' +ngsite.user.reset_password.done.text: 'Your password has been successfully changed. You can now login with your new password.' +ngsite.user.reset_password.done.error.hash_expired: 'Provided hash key has expired. Please request a new one here.' +ngsite.user.reset_password.done.error.other: 'Unspecified error occurred.' diff --git a/src/AppBundle/Resources/views/nglayouts/app/item/ezcontent.html.twig b/src/AppBundle/Resources/views/nglayouts/app/item/ezcontent.html.twig new file mode 100644 index 0000000..09efb33 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/app/item/ezcontent.html.twig @@ -0,0 +1,6 @@ +{% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: item.object.content, + location: item.object.mainLocation, + view_type: 'nglayouts_app_preview', + params: { 'nglayouts_item': item } +} only %} diff --git a/src/AppBundle/Resources/views/nglayouts/app/item/ezlocation.html.twig b/src/AppBundle/Resources/views/nglayouts/app/item/ezlocation.html.twig new file mode 100644 index 0000000..88f0b2c --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/app/item/ezlocation.html.twig @@ -0,0 +1,6 @@ +{% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: item.object.content, + location: item.object, + view_type: 'nglayouts_app_preview', + params: { 'nglayouts_item': item } +} only %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/block/block.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/block/block.html.twig new file mode 100644 index 0000000..d2a8728 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/block/block.html.twig @@ -0,0 +1,60 @@ +{# + WARNING: This template overrides base block.html.twig template from Netgen Layouts + + When upgrading to new versions of Netgen Layouts, check for any modifications to this + template and apply them here. +#} + +{% set css_id = css_id|default(block.parameter('css_id').value) %} +{% set set_container = block.parameter('set_container').value %} +{% set container_size = block.parameter('set_container:size').value %} + +{% set use_whitespace = block.parameter('vertical_whitespace:enabled').value is same as(true) %} +{% set whitespace_top = block.parameter('vertical_whitespace:top').value %} +{% set whitespace_bottom = block.parameter('vertical_whitespace:bottom').value %} + +{% set bg_image = block.dynamicParameter('background_image:image_content') %} +{% set use_bg_image = block.hasParameter('background_image:enabled') and block.parameter('background_image:enabled').value is same as(true) %} +{% set use_bg_image = use_bg_image and bg_image is not null and bg_image.fields.image is defined %} + +{% set bg_color = block.hasParameter('background_color:color') ? block.parameter('background_color:color').value : null %} +{% set use_bg_color = block.hasParameter('background_color:enabled') and block.parameter('background_color:enabled').value is same as(true) %} +{% set use_bg_color = use_bg_color and bg_color is not empty %} + +{% set css_classes = ['ngl-block', 'ngl-' ~ block.definition.identifier, 'ngl-vt-' ~ block.viewType, css_class|default(block.parameter('css_class').value)] %} + +{% if use_whitespace %} + {% set css_classes = css_classes|merge(['whitespace-top-' ~ whitespace_top]) %} + {% set css_classes = css_classes|merge(['whitespace-bottom-' ~ whitespace_bottom]) %} +{% endif %} + +{% if use_bg_image %} + {% set css_classes = css_classes|merge(['with-bg-image']) %} +{% endif %} + +{% if use_bg_color %} + {% set css_classes = css_classes|merge(['bg-color-' ~ bg_color]) %} +{% endif %} + +{% if show_empty_wrapper is not defined %} + {% set show_empty_wrapper = false %} +{% endif %} + +{% set block_content = (block('content') is defined ? block('content') : '')|trim %} + +{% if block_content is not empty or show_empty_wrapper %} +
+ {% if set_container %}
{% endif %} + + {{ block_content|raw }} + + {% if set_container %}
{% endif %} +
+{% endif %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/block/list/grid_featured.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/block/list/grid_featured.html.twig new file mode 100644 index 0000000..1cefba7 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/block/list/grid_featured.html.twig @@ -0,0 +1,13 @@ +{% extends '@nglayouts/block/block.html.twig' %} + +{% block content %} + {% if collections.default is defined %} + + {% endif %} +{% endblock %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/block/list/numbered.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/block/list/numbered.html.twig new file mode 100644 index 0000000..8f67d1c --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/block/list/numbered.html.twig @@ -0,0 +1,3 @@ +{% extends '@nglayouts/block/list/list.html.twig' %} + +{% set css_class = 'list-numbered ' ~ block.parameter('css_class').value %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/block/title.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title.html.twig new file mode 100644 index 0000000..cb9b0f3 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title.html.twig @@ -0,0 +1,27 @@ +{% extends '@nglayouts/block/block.html.twig' %} + +{% import '@NetgenLayouts/parts/macros.html.twig' as macros %} + +{% set tag = block.parameter('tag').value|default('h1') %} +{% set link = block.parameter('link') %} + +{% set icon_css_class = block.hasParameter('title_icon:css_class') ? block.parameter('title_icon:css_class').value : null %} +{% set use_icon = block.hasParameter('title_icon:enabled') and block.parameter('title_icon:enabled').value is same as(true) %} +{% set use_icon = use_icon and icon_css_class is not empty %} + +{% block content %} + {# Located inside the "content" block to include the context from the parent template #} + {% set title = macros.inline_template(block.parameter('title').value, _context) %} + + <{{ tag }} class="title"> + {% if use_icon %} +
+ {% endif %} + + {% if block.parameter('use_link').value and not link.empty %} + {{ nglayouts_render_parameter(link, {content: title}) }} + {% else %} + {{ title }} + {% endif %} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/centered.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/centered.html.twig new file mode 100644 index 0000000..3bcac42 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/centered.html.twig @@ -0,0 +1,3 @@ +{% extends '@nglayouts/block/title.html.twig' %} + +{% set css_class = 'text-center ' ~ block.parameter('css_class').value %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/section.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/section.html.twig new file mode 100644 index 0000000..5e597ba --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/section.html.twig @@ -0,0 +1,3 @@ +{% extends '@nglayouts/block/title.html.twig' %} + +{% set css_class = 'section-title ' ~ block.parameter('css_class').value %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/section_centered.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/section_centered.html.twig new file mode 100644 index 0000000..a6f95b5 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/block/title/section_centered.html.twig @@ -0,0 +1,3 @@ +{% extends '@nglayouts/block/title.html.twig' %} + +{% set css_class = 'section-title section-title-centered ' ~ block.parameter('css_class').value %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/item/ezcontent.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/item/ezcontent.html.twig new file mode 100644 index 0000000..fdae519 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/item/ezcontent.html.twig @@ -0,0 +1,6 @@ +{% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: item.object.content, + location: item.object.mainLocation, + view_type: view_type, + params: { 'nglayouts_item': item }|merge(ezparams|default({})) +} only %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/item/ezlocation.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/item/ezlocation.html.twig new file mode 100644 index 0000000..7078b6c --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/item/ezlocation.html.twig @@ -0,0 +1,6 @@ +{% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: item.object.content, + location: item.object, + view_type: view_type, + params: { 'nglayouts_item': item }|merge(ezparams|default({})) +} only %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/item/gallery_thumb/ezcontent.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/item/gallery_thumb/ezcontent.html.twig new file mode 100644 index 0000000..c792709 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/item/gallery_thumb/ezcontent.html.twig @@ -0,0 +1,11 @@ +{% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: item.object.content, + location: item.object.mainLocation, + view_type: 'gallery_thumb', + params: { + 'nglayouts_item': item, + 'image_type': image_type, + 'show_details': show_details, + 'show_details_on_hover': show_details_on_hover + }|merge(ezparams|default({})) +} only %} diff --git a/src/AppBundle/Resources/views/nglayouts/themes/app/item/gallery_thumb/ezlocation.html.twig b/src/AppBundle/Resources/views/nglayouts/themes/app/item/gallery_thumb/ezlocation.html.twig new file mode 100644 index 0000000..6dc1ad5 --- /dev/null +++ b/src/AppBundle/Resources/views/nglayouts/themes/app/item/gallery_thumb/ezlocation.html.twig @@ -0,0 +1,11 @@ +{% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: item.object.content, + location: item.object, + view_type: 'gallery_thumb', + params: { + 'nglayouts_item': item, + 'image_type': image_type, + 'show_details': show_details, + 'show_details_on_hover': show_details_on_hover + }|merge(ezparams|default({})) +} only %} diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/file.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/file.html.twig new file mode 100644 index 0000000..dc91331 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/file.html.twig @@ -0,0 +1,8 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +
+
+ {{ ng_render_field(content.fields.file) }} +
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/image.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/image.html.twig new file mode 100644 index 0000000..0744f7a --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/image.html.twig @@ -0,0 +1,27 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% if not content.fields.image.empty %} +
+
+ {{ ng_render_field( + content.fields.image, { + 'parameters': { + 'alias': objectParameters.align|default('') is not empty ? 'i770' : 'i1200', + 'link_href': link_href|default(''), + 'link_class': objectParameters.link_class|default(''), + 'link_id': objectParameters.link_id|default(''), + 'link_title': objectParameters.link_title|default(''), + 'link_target': objectParameters.link_target|default('') + } + } + ) }} + + {% if not content.fields.caption.empty %} +
+ {{ ng_render_field(content.fields.caption) }} +
+ {% endif %} +
+
+{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_article.html.twig new file mode 100644 index 0000000..b215c9e --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_article.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ +

{{ content_fields.title(content) }}

+ + {{ content_fields.image(content, null, 'i320') }} + +
diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_audio.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_audio.html.twig new file mode 100644 index 0000000..759d5c6 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_audio.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+

{{ content_fields.title(content) }}

+ + {% if not content.fields.file.empty %} + + {% endif %} + + {% if not content.fields.description.empty %} +
+ {{ ng_render_field(content.fields.description) }} +
+ {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_banner.html.twig new file mode 100644 index 0000000..259fde9 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_banner.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import "@ezdesign/parts/macros.html.twig" as macros %} + +{% block content %} +
+

+ {{ macros.content_link(content, content.fields.title.value.text) }} +

+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_blog_post.html.twig new file mode 100644 index 0000000..73c30ac --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_blog_post.html.twig @@ -0,0 +1,20 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+

{{ content_fields.title(content) }}

+ +
+ {{ content.fields.publish_date.value.value|date('j. n. Y.') }} +
+ + {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {{ content_fields.image(content, null, 'i320') }} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_category.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_category.html.twig new file mode 100644 index 0000000..17a5f59 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_category.html.twig @@ -0,0 +1,10 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+

{{ content_fields.title(content) }}

+ + {{ content_fields.image(content, null, 'i320') }} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_feedback_form.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_feedback_form.html.twig new file mode 100644 index 0000000..f9bef8f --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_feedback_form.html.twig @@ -0,0 +1,8 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_frontpage.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_frontpage.html.twig new file mode 100644 index 0000000..fcb4d88 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_frontpage.html.twig @@ -0,0 +1,6 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_gallery.html.twig new file mode 100644 index 0000000..2058d9a --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_gallery.html.twig @@ -0,0 +1,15 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_htmlbox.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_htmlbox.html.twig new file mode 100644 index 0000000..4e573fa --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_htmlbox.html.twig @@ -0,0 +1,6 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +
+ {{ content.fields.html_code.value.text|raw }} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_landing_page.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_landing_page.html.twig new file mode 100644 index 0000000..908360a --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_landing_page.html.twig @@ -0,0 +1,8 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_news.html.twig new file mode 100644 index 0000000..4907c5a --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_news.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, null, 'i320') }} + +

{{ content_fields.title(content) }}

+ +
diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_shortcut.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_shortcut.html.twig new file mode 100644 index 0000000..1700ce3 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_shortcut.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import "@ezdesign/parts/macros.html.twig" as macros %} + +{% block content %} +
+

+ {{ macros.content_link(content, content.fields.title.value.text) }} +

+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/embed/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/embed/ng_video.html.twig new file mode 100644 index 0000000..6dcd2d3 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/embed/ng_video.html.twig @@ -0,0 +1,10 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/video.html.twig' as video %} + +
+ + {{ video.player(content, true) }} + +
diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_article.html.twig new file mode 100644 index 0000000..f33e413 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_article.html.twig @@ -0,0 +1,118 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set show_path = false %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% elseif not content.fields.full_intro.empty %} + {% set meta_data = {'description': content.fields.full_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block content %} +
+ {% block article_header %} +
+
+ {% if not content.fields.sponsored_content_disclosure.empty %} +
+ {{ content.fields.sponsored_content_disclosure.value.text }} +
+ {% elseif not content.fields.main_topic.empty %} + + {% endif %} +

{{ ng_render_field(content.fields.title) }}

+
+ {% if not content.fields.authors.empty %} + By + {% for author in content.fieldRelations('authors') %} + + {% endfor %} – + {% endif %} + {% if content.contentInfo.publishedDate %} + + {% endif %} +
+
+
+ {% endblock %} + +
+ {% block image %} + {% if not content.fields.image.empty or not content.fields.related_multimedia.empty %} +
+ {{ render( + controller( + 'ngsite.controller.parts:viewRelatedMultimediaItems', { + 'locationId': location.id, + 'includeChildren': true, + 'contentTypeIdentifiers': ['image', 'ng_video'], + 'template': '@ezdesign/parts/related_multimedia.html.twig' + } + ) + ) }} +
+ {% endif %} + {% endblock %} + +
+ + {% block body %} +
+ {% if not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} + + {% if not content.fields.body.empty %} + {{ ng_render_field(content.fields.body) }} + {% endif %} + + {% if not content.fields.tags.empty %} + + {% endif %} +
+ {% endblock %} + +
+
+
+{% endblock %} + +{% block structuredData %} + {# structured data #} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_audio.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_audio.html.twig new file mode 100644 index 0000000..1859fe4 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_audio.html.twig @@ -0,0 +1,35 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block content %} +
+ +

{{ ng_render_field(content.fields.title) }}

+ + {% if not content.fields.teaser_intro.empty %} +
+ {{ ng_render_field(content.fields.teaser_intro) }} +
+ {% endif %} + + {% if not content.fields.file.empty %} + + {% endif %} + + {% if not content.fields.description.empty %} +
+ {{ ng_render_field(content.fields.description) }} +
+ {% endif %} + +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_blog_post.html.twig new file mode 100644 index 0000000..17e68bf --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_blog_post.html.twig @@ -0,0 +1,118 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set show_path = false %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% elseif not content.fields.full_intro.empty %} + {% set meta_data = {'description': content.fields.full_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block content %} +
+ {% block article_header %} +
+
+ {% if not content.fields.sponsored_content_disclosure.empty %} +
+ {{ content.fields.sponsored_content_disclosure.value.text }} +
+ {% elseif not content.fields.main_topic.empty %} + + {% endif %} +

{{ ng_render_field(content.fields.title) }}

+
+ {% if not content.fields.authors.empty %} + By + {% for author in content.fieldRelations('authors') %} + + {% endfor %} – + {% endif %} + {% if content.contentInfo.publishedDate %} + + {% endif %} +
+
+
+ {% endblock %} + +
+ {% block image %} + {% if not content.fields.image.empty %} +
+ {{ render( + controller( + 'ngsite.controller.parts:viewRelatedMultimediaItems', { + 'locationId': location.id, + 'includeChildren': true, + 'contentTypeIdentifiers': ['image', 'ng_video'], + 'template': '@ezdesign/parts/related_multimedia.html.twig' + } + ) + ) }} +
+ {% endif %} + {% endblock %} + +
+ + {% block body %} +
+ {% if not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} + + {% if not content.fields.body.empty %} + {{ ng_render_field(content.fields.body) }} + {% endif %} + + {% if not content.fields.tags.empty %} + + {% endif %} +
+ {% endblock %} + +
+
+
+{% endblock %} + +{% block structuredData %} + {# structured data #} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_category.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_category.html.twig new file mode 100644 index 0000000..af5dadd --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_category.html.twig @@ -0,0 +1,90 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% elseif not content.fields.full_intro.empty %} + {% set meta_data = {'description': content.fields.full_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block pre_content %} +
+
+

{{ ng_render_field(content.fields.title) }}

+ {% if not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} +
+
+{% endblock %} + +{% block content %} +
+ {% if not content.fields.body.empty %} +
+ {{ ng_render_field(content.fields.body) }} +
+ {% endif %} + + + + {% if content.fields.show_children.value.bool %} +
+ {% if pager|length > 0 %} + {% set children_view_type = content.fields.view_type.value.identifiers[0]|default('standard') %} + {% set columns = content.fields.grid_columns.value.identifiers[0]|default('3') %} + {% set column_css_class = { + '1': 'col-12', + '2': 'col-sm-6', + '3': 'col-md-4 col-sm-6', + '4': 'col-lg-3 col-md-4 col-sm-6' + } %} + + {% if children_view_type == 'listitem' %} +
    + {% for pager_item in pager %} +
  • + {% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: pager_item.content, + location: pager_item, + view_type: children_view_type + } only %} +
  • + {% endfor %} +
+ {% else %} +
+ {% for pager_item in pager %} +
+ {% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: pager_item.content, + location: pager_item, + view_type: children_view_type + } only %} +
+ {% endfor %} +
+ {% endif %} + {% endif %} +
+ + {% if pager.haveToPaginate() %} + {{ pagerfanta(pager, 'ngsite') }} + {% endif %} + {% endif %} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_feedback_form.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_feedback_form.html.twig new file mode 100644 index 0000000..66ac46c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_feedback_form.html.twig @@ -0,0 +1,76 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% form_theme form '@ezdesign/forms/theme.html.twig' %} + +{% set show_path = false %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% elseif not content.fields.full_intro.empty %} + {% set meta_data = {'description': content.fields.full_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block success %} +
+ {% if not content.fields.success_text.empty %} + {{ ng_render_field(content.fields.success_text) }} + {% else %} +

{{ 'ngsite.collected_info.success_text'|trans }}

+ {% endif %} + + {# +

{{ 'ngsite.collected_info.information_collected'|trans }}:

+ + {% for collected_field, collected_field_value in collected_fields %} +

{{ content.fields[collected_field].name }}: {{ collected_field_value }}

+ {% endfor %} + #} + + {{ 'ngsite.collected_info.return_to_site'|trans }} +
+{% endblock %} + +{% block pre_content %} +
+
+

{{ ng_render_field(content.fields.title) }}

+ {% if not is_valid and not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} +
+
+{% endblock %} + +{% block content %} +
+
+ {% if not is_valid %} + {% if not content.fields.body.empty %} + {{ ng_render_field(content.fields.body) }} + {% endif %} + + {{ form_start(form) }} + {{ form_errors(form) }} + +
+ {{ form_row(form.sender_name, {attr: {class: 'form-control'}}) }} + {{ form_row(form.email, {attr: {class: 'form-control'}}) }} + {{ form_row(form.subject, {attr: {class: 'form-control'}}) }} + {{ form_row(form.message, {attr: {class: 'form-control'}}) }} + + +
+ + {{ form_rest(form) }} + {{ form_end(form) }} + {% else %} + {{ block('success') }} + {% endif %} +
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_frontpage.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_frontpage.html.twig new file mode 100644 index 0000000..7220df5 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_frontpage.html.twig @@ -0,0 +1,11 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% set show_path = false %} + +{% block content %} +
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_gallery.html.twig new file mode 100644 index 0000000..389af0a --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_gallery.html.twig @@ -0,0 +1,59 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% elseif not content.fields.description.empty %} + {% set meta_data = {'description': content.fields.description.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block pre_content %} + +{% endblock %} + +{% block content %} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_htmlbox.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_htmlbox.html.twig new file mode 100644 index 0000000..9bb54d8 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_htmlbox.html.twig @@ -0,0 +1,10 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% block content %} +
+ {{ content.fields.html_code.value.text|raw }} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_landing_page.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_landing_page.html.twig new file mode 100644 index 0000000..e6257c3 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_landing_page.html.twig @@ -0,0 +1,11 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% set show_path = false %} + +{% block content %} +
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_news.html.twig new file mode 100644 index 0000000..165c094 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_news.html.twig @@ -0,0 +1,118 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set show_path = false %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% elseif not content.fields.full_intro.empty %} + {% set meta_data = {'description': content.fields.full_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block content %} +
+ {% block article_header %} +
+
+ {% if not content.fields.sponsored_content_disclosure.empty %} +
+ {{ content.fields.sponsored_content_disclosure.value.text }} +
+ {% elseif not content.fields.main_topic.empty %} + + {% endif %} +

{{ ng_render_field(content.fields.title) }}

+
+ {% if not content.fields.authors.empty %} + By + {% for author in content.fieldRelations('authors') %} + + {% endfor %} – + {% endif %} + {% if content.contentInfo.publishedDate %} + + {% endif %} +
+
+
+ {% endblock %} + +
+ {% block image %} + {% if not content.fields.image.empty or not content.fields.related_multimedia.empty %} +
+ {{ render( + controller( + 'ngsite.controller.parts:viewRelatedMultimediaItems', { + 'locationId': location.id, + 'includeChildren': true, + 'contentTypeIdentifiers': ['image', 'ng_video'], + 'template': '@ezdesign/parts/related_multimedia.html.twig' + } + ) + ) }} +
+ {% endif %} + {% endblock %} + +
+ + {% block body %} +
+ {% if not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} + + {% if not content.fields.body.empty %} + {{ ng_render_field(content.fields.body) }} + {% endif %} + + {% if not content.fields.tags.empty %} + + {% endif %} +
+ {% endblock %} + +
+
+
+{% endblock %} + +{% block structuredData %} + {# structured data #} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_recipe.html.twig new file mode 100644 index 0000000..86aec19 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_recipe.html.twig @@ -0,0 +1,153 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set show_path = false %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% elseif not content.fields.full_intro.empty %} + {% set meta_data = {'description': content.fields.full_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block content %} +
+ {% block article_header %} +
+
+ {% if not content.fields.sponsored_content_disclosure.empty %} +
+ {{ content.fields.sponsored_content_disclosure.value.text }} +
+ {% elseif not content.fields.main_topic.empty %} + + {% endif %} +

{{ ng_render_field(content.fields.title) }}

+
+ {% if not content.fields.authors.empty %} + By + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} +
+
+
+ {% endblock %} + +
+ {% block image %} + {% if not content.fields.image.empty or not content.fields.related_multimedia.empty %} +
+ {{ render( + controller( + 'ngsite.controller.parts:viewRelatedMultimediaItems', { + 'locationId': location.id, + 'includeChildren': true, + 'contentTypeIdentifiers': ['image', 'ng_video'], + 'template': '@ezdesign/parts/related_multimedia.html.twig' + } + ) + ) }} +
+ {% endif %} + {% endblock %} + +
+ + {% block body %} +
+ {% if not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} + + {% if not content.fields.body.empty %} + {{ ng_render_field(content.fields.body) }} + {% endif %} + + {% if not content.fields.tags.empty %} + + {% endif %} +
+ {% endblock %} + + {% block recipe_info %} +
+ {% if not content.fields.serving_calories.empty %} +
+ {{ ng_render_field(content.fields.serving_calories) }} {{ 'ngsite.layout.recipe.cal'|trans }} +
+ {% endif %} + +
    + {% if not content.fields.serving_fat.empty %} +
  • {{ ng_render_field(content.fields.serving_fat) }} {{ 'ngsite.layout.recipe.fat'|trans }}
  • + {% endif %} + {% if not content.fields.serving_carbohydrates.empty %} +
  • {{ ng_render_field(content.fields.serving_carbohydrates) }} {{ 'ngsite.layout.recipe.carbs'|trans }}
  • + {% endif %} + {% if not content.fields.serving_protein.empty %} +
  • {{ ng_render_field(content.fields.serving_protein) }} {{ 'ngsite.layout.recipe.protein'|trans }}
  • + {% endif %} +
+ + {% if not content.fields.preparation_time.empty %} +
+ {{ 'ngsite.layout.recipe.preparation_time'|trans }} + +
+ {% endif %} +
+ {% endblock %} + +
+
+
+{% endblock %} + +{% block structuredData %} + {# structured data #} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_topic.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_topic.html.twig new file mode 100644 index 0000000..6b14bd5 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_topic.html.twig @@ -0,0 +1,39 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set show_path = false %} + +{% if not content.fields.full_intro.empty %} + {% set meta_data = {'description': content.fields.full_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% set topic_tag = content.fields.title.value.text|trim %} + +{% block content %} +
+ {% block page_header %} +
+
+

{{ ng_render_field(content.fields.title) }}

+ {% if not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} +
+
+ {% endblock %} + +
+ {% block body %} + {% if not content.fields.body.empty %} + {{ ng_render_field(content.fields.body) }} + {% endif %} + {% endblock %} +
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/full/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/full/ng_video.html.twig new file mode 100644 index 0000000..ffcc505 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/full/ng_video.html.twig @@ -0,0 +1,39 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% extends nglayouts.layoutTemplate %} + +{% import '@ezdesign/parts/video.html.twig' as video %} + +{% if not content.fields.teaser_intro.empty %} + {% set meta_data = {'description': content.fields.teaser_intro.value.xml.saveXML()|striptags|trim|truncate(152)} %} +{% endif %} + +{% block content %} +
+
+ {{ video.player(content, true) }} +
+ +
+

{{ ng_render_field(content.fields.title) }}

+ {% if content.contentInfo.publishedDate %} +

+ +

+ {% endif %} +
+ + {% if not content.fields.teaser_intro.empty %} +
+ {{ ng_render_field(content.fields.teaser_intro) }} +
+ {% endif %} + + {% if not content.fields.description.empty %} +
+ {{ ng_render_field(content.fields.description) }} +
+ {% endif %} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_grid.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_grid.html.twig new file mode 100644 index 0000000..db30c18 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_grid.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% if content.hasField('image') and not content.fields.image.empty %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_grid/image.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/image.html.twig new file mode 100644 index 0000000..6c1ca48 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/image.html.twig @@ -0,0 +1,13 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/slide.html.twig' as slide %} +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {% set title = content_fields.title(content) %} + + + {{ slide.image(content) }} + +
diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_article.html.twig new file mode 100644 index 0000000..ef5a365 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_article.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% if not content.fields.image.empty %} +
+ {% set title = content_fields.title(content) %} + + + {{ ng_render_field( + content.fields.image, { + parameters: { + alias: 'i1200', + alt_text: title + } + } + ) }} + +
+{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_banner.html.twig new file mode 100644 index 0000000..22064b1 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_banner.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% if not content.fields.image.empty %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_blog_post.html.twig new file mode 100644 index 0000000..a4ba775 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_blog_post.html.twig @@ -0,0 +1,28 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% if not content.fields.image.empty %} +
+ {% if not content.fields.authors.empty %} + {% set author = content.fieldRelations('authors')[0].name %} + {% else %} + {% set author = content.owner.name %} + {% endif %} + + {% set date = content.fields.publish_date.value.value|date('j. n. Y.') %} + {% set title = content_fields.title(content) %} + + + {{ ng_render_field( + content.fields.image, { + parameters: { + alias: 'i1200', + alt_text: title + } + } + ) }} + +
+{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_news.html.twig new file mode 100644 index 0000000..c8a4985 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_news.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% if not content.fields.image.empty %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_video.html.twig new file mode 100644 index 0000000..c7ebd23 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_grid/ng_video.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import "@ezdesign/parts/video.html.twig" as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_thumb.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb.html.twig new file mode 100644 index 0000000..e960d39 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb.html.twig @@ -0,0 +1,19 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/slide.html.twig' as slide %} +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {% if image_type == 'main' %} + {{ slide.image(content, 'image', 'i1200', true) }} + + {% if show_details %} + + {% endif %} + {% elseif image_type == 'thumb' %} + {{ slide.image(content, 'image', 'i320') }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/image.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/image.html.twig new file mode 100644 index 0000000..acbffb4 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/image.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {% if image_type == 'main' %} + {{ slide.image(content, 'image', 'i1200', true) }} + {% elseif image_type == 'thumb' %} + {{ slide.image(content, 'image', 'i320') }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_article.html.twig new file mode 100644 index 0000000..c01d4ca --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_article.html.twig @@ -0,0 +1,19 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {% if image_type == 'main' %} + {{ slide.image(content, 'image', 'i1200', true) }} + + {% if show_details %} + + {% endif %} + {% elseif image_type == 'thumb' %} + {{ slide.image(content, 'image', 'i320') }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_banner.html.twig new file mode 100644 index 0000000..dc49f16 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_banner.html.twig @@ -0,0 +1,23 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/slide.html.twig' as slide %} +{% import "@ezdesign/parts/macros.html.twig" as macros %} + +{% block content %} +
+ {% if image_type == 'main' %} + {{ slide.image(content, 'image', 'i1200', true) }} + + {% if show_details %} +
+

+ {{ macros.content_link(content, content.fields.title.value.text) }} +

+
+ {% endif %} + {% elseif image_type == 'thumb' %} + {{ slide.image(content, 'image', 'i320') }} + {% endif %} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_blog_post.html.twig new file mode 100644 index 0000000..be6930c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_blog_post.html.twig @@ -0,0 +1,28 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {% if image_type == 'main' %} + {{ slide.image(content, 'image', 'i1200', true) }} + + {% if show_details %} +
+

{{ content_fields.title(content) }}

+ +
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} | + {% endif %} + {{ content.fields.publish_date.value.value|date('j. n. Y.') }} +
+
+ {% endif %} + {% elseif image_type == 'thumb' %} + {{ slide.image(content, 'image', 'i320') }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_news.html.twig new file mode 100644 index 0000000..3ba118c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_news.html.twig @@ -0,0 +1,22 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {% if image_type == 'main' %} + {{ slide.image(content, 'image', 'i1200', true) }} + + {% if show_details %} +
+
+ {{ content.fields.publish_date.value.value|date('j. n. Y.') }} +
+

{{ content_fields.title(content) }}

+
+ {% endif %} + {% elseif image_type == 'thumb' %} + {{ slide.image(content, 'image', 'i320') }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_video.html.twig new file mode 100644 index 0000000..bfc18a2 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/gallery_thumb/ng_video.html.twig @@ -0,0 +1,24 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import "@ezdesign/parts/video.html.twig" as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} +
+ {% if image_type == 'main' %} + {{ video.poster_slide(content, true, content.fields.title.value.text) }} + + {% if show_details %} + + {% endif %} + {% elseif image_type == 'thumb' %} + {{ video.poster_slide(content, false, content.fields.title.value.text) }} + {% endif %} +
+{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/line.html.twig b/src/AppBundle/Resources/views/themes/app/content/line.html.twig new file mode 100644 index 0000000..045aa46 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line.html.twig @@ -0,0 +1,19 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/line/file.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/file.html.twig new file mode 100644 index 0000000..b5566db --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/file.html.twig @@ -0,0 +1,14 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_article.html.twig new file mode 100644 index 0000000..c2c2a49 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_article.html.twig @@ -0,0 +1,30 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, 'i320') }} + +
+
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
+ {{ content_fields.intro(content) }} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_audio.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_audio.html.twig new file mode 100644 index 0000000..7a990ad --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_audio.html.twig @@ -0,0 +1,18 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_blog_post.html.twig new file mode 100644 index 0000000..4e2b885 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_blog_post.html.twig @@ -0,0 +1,31 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, 'i320') }} + +
+
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
+ {{ content_fields.intro(content) }} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_category.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_category.html.twig new file mode 100644 index 0000000..02371da --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_category.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_feedback_form.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_feedback_form.html.twig new file mode 100644 index 0000000..ffa4882 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_feedback_form.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_gallery.html.twig new file mode 100644 index 0000000..2fdfa63 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_gallery.html.twig @@ -0,0 +1,38 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set children = location.filterChildren(['image'], 1).currentPageResults %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_landing_page.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_landing_page.html.twig new file mode 100644 index 0000000..a7135e0 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_landing_page.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_news.html.twig new file mode 100644 index 0000000..c18e48e --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_news.html.twig @@ -0,0 +1,31 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, 'i320') }} + +
+
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
+ {{ content_fields.intro(content) }} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_recipe.html.twig new file mode 100644 index 0000000..a9eb6f6 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_recipe.html.twig @@ -0,0 +1,38 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, 'i320') }} + +
+
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} + + {% if not content.fields.preparation_time.empty %} + {{ ng_render_field(content.fields.preparation_time) }} {{ 'ngsite.layout.recipe.min'|trans }} + {% endif %} + {% if not content.fields.serving_calories.empty %} + {{ ng_render_field(content.fields.serving_calories) }} {{ 'ngsite.layout.recipe.cal'|trans }} + {% endif %} + +
+
+
+ {{ content_fields.intro(content) }} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/line/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/line/ng_video.html.twig new file mode 100644 index 0000000..732c403 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/line/ng_video.html.twig @@ -0,0 +1,27 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/video.html.twig' as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem.html.twig new file mode 100644 index 0000000..faba639 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem.html.twig @@ -0,0 +1,11 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/file.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/file.html.twig new file mode 100644 index 0000000..178f425 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/file.html.twig @@ -0,0 +1,10 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_article.html.twig new file mode 100644 index 0000000..c891fdd --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_article.html.twig @@ -0,0 +1,20 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/ng_audio.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_audio.html.twig new file mode 100644 index 0000000..e7e6ec1 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_audio.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_blog_post.html.twig new file mode 100644 index 0000000..34cda55 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_blog_post.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_gallery.html.twig new file mode 100644 index 0000000..e5ff9fb --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_gallery.html.twig @@ -0,0 +1,19 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_news.html.twig new file mode 100644 index 0000000..4cc6d53 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_news.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_recipe.html.twig new file mode 100644 index 0000000..023a8b9 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_recipe.html.twig @@ -0,0 +1,28 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} + + {% if not content.fields.preparation_time.empty %} + {{ ng_render_field(content.fields.preparation_time) }} {{ 'ngsite.layout.recipe.min'|trans }} + {% endif %} + {% if not content.fields.serving_calories.empty %} + {{ ng_render_field(content.fields.serving_calories) }} {{ 'ngsite.layout.recipe.cal'|trans }} + {% endif %} + +
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/listitem/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_video.html.twig new file mode 100644 index 0000000..3de36db --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/listitem/ng_video.html.twig @@ -0,0 +1,19 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/mini.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini.html.twig new file mode 100644 index 0000000..a042478 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini.html.twig @@ -0,0 +1,14 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/file.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/file.html.twig new file mode 100644 index 0000000..f8a3803 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/file.html.twig @@ -0,0 +1,10 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% set location_path = path(location) %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/ng_article.html.twig new file mode 100644 index 0000000..4448611 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/ng_article.html.twig @@ -0,0 +1,25 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/ng_audio.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/ng_audio.html.twig new file mode 100644 index 0000000..3aa89e8 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/ng_audio.html.twig @@ -0,0 +1,24 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set location_path = path(location) %} + +
+
+ + {{ ng_render_field( + content.fields.image, { + 'parameters': { + 'alias': 'i160', + 'link_href': location_path + } + } + ) }} +
+ +
+

{{ content_fields.title(content) }}

+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/ng_blog_post.html.twig new file mode 100644 index 0000000..f4ba49f --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/ng_blog_post.html.twig @@ -0,0 +1,26 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, 'i160') }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/ng_gallery.html.twig new file mode 100644 index 0000000..f6f18f3 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/ng_gallery.html.twig @@ -0,0 +1,36 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set location_path = path(location) %} +{% set children = location.filterChildren(['image'], 1).currentPageResults %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/ng_news.html.twig new file mode 100644 index 0000000..131200b --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/ng_news.html.twig @@ -0,0 +1,26 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, 'i160') }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/ng_recipe.html.twig new file mode 100644 index 0000000..6797839 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/ng_recipe.html.twig @@ -0,0 +1,33 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, 'i160') }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} + + {% if not content.fields.preparation_time.empty %} + {{ ng_render_field(content.fields.preparation_time) }} {{ 'ngsite.layout.recipe.min'|trans }} + {% endif %} + {% if not content.fields.serving_calories.empty %} + {{ ng_render_field(content.fields.serving_calories) }} {{ 'ngsite.layout.recipe.cal'|trans }} + {% endif %} + +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/mini/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/mini/ng_video.html.twig new file mode 100644 index 0000000..582bded --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/mini/ng_video.html.twig @@ -0,0 +1,27 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/video.html.twig' as video %} + +{% set location_path = path(location) %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay.html.twig new file mode 100644 index 0000000..cdbdf52 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_article.html.twig new file mode 100644 index 0000000..8e54183 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_article.html.twig @@ -0,0 +1,24 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_banner.html.twig new file mode 100644 index 0000000..0f092ed --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_banner.html.twig @@ -0,0 +1,27 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import "@ezdesign/parts/macros.html.twig" as macros %} + +{% set content_link = macros.content_link_parameters(content) %} + +{% block content %} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_blog_post.html.twig new file mode 100644 index 0000000..00c6e35 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_blog_post.html.twig @@ -0,0 +1,25 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {{ content_fields.image(content, location, null, null, 'image-16by9') }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_gallery.html.twig new file mode 100644 index 0000000..ef98ddd --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_gallery.html.twig @@ -0,0 +1,37 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set children = location.filterChildren(['image'], 1).currentPageResults %} + +
+ + {% if children.searchHits is not empty %} + {% set first_image = children[0].content %} + + +
+ {{ ng_render_field( + first_image.fields.image, { + parameters: { + alias: 'i480', + alt_text: first_image.fields.name.value, + } + } + ) }} +
+
+ {% endif %} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_news.html.twig new file mode 100644 index 0000000..5f13d3c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_news.html.twig @@ -0,0 +1,25 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {{ content_fields.image(content, location, null, null, 'image-16by9') }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_recipe.html.twig new file mode 100644 index 0000000..3951488 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_recipe.html.twig @@ -0,0 +1,32 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {{ content_fields.image(content, location, null, null, 'image-16by9') }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} + + {% if not content.fields.preparation_time.empty %} + {{ ng_render_field(content.fields.preparation_time) }} {{ 'ngsite.layout.recipe.min'|trans }} + {% endif %} + {% if not content.fields.serving_calories.empty %} + {{ ng_render_field(content.fields.serving_calories) }} {{ 'ngsite.layout.recipe.cal'|trans }} + {% endif %} + +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/overlay/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_video.html.twig new file mode 100644 index 0000000..5a18856 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/overlay/ng_video.html.twig @@ -0,0 +1,23 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/video.html.twig' as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} +
+ + {{ video.poster(content, location) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+
+{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/search.html.twig b/src/AppBundle/Resources/views/themes/app/content/search.html.twig new file mode 100644 index 0000000..bf2f2ac --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/search.html.twig @@ -0,0 +1,48 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/slide.html.twig b/src/AppBundle/Resources/views/themes/app/content/slide.html.twig new file mode 100644 index 0000000..05610da --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/slide.html.twig @@ -0,0 +1,13 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/slide.html.twig' as slide %} +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {{ slide.image(content) }} + + +
diff --git a/src/AppBundle/Resources/views/themes/app/content/slide/image.html.twig b/src/AppBundle/Resources/views/themes/app/content/slide/image.html.twig new file mode 100644 index 0000000..c1f38b2 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/slide/image.html.twig @@ -0,0 +1,8 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {{ slide.image(content) }} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/slide/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/slide/ng_article.html.twig new file mode 100644 index 0000000..17204a1 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/slide/ng_article.html.twig @@ -0,0 +1,13 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {{ slide.image(content) }} + + +
diff --git a/src/AppBundle/Resources/views/themes/app/content/slide/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/app/content/slide/ng_banner.html.twig new file mode 100644 index 0000000..63c655f --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/slide/ng_banner.html.twig @@ -0,0 +1,17 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/slide.html.twig' as slide %} +{% import '@ezdesign/parts/macros.html.twig' as macros %} + +{% block content %} +
+ {{ slide.image(content) }} + +
+

+ {{ macros.content_link(content, content.fields.title.value.text) }} +

+
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/slide/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/slide/ng_blog_post.html.twig new file mode 100644 index 0000000..d9d41cf --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/slide/ng_blog_post.html.twig @@ -0,0 +1,22 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {{ slide.image(content) }} + +
+

{{ content_fields.title(content) }}

+ +
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} | + {% endif %} + {{ content.fields.publish_date.value.value|date('j. n. Y.') }} +
+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/slide/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/slide/ng_news.html.twig new file mode 100644 index 0000000..59da43d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/slide/ng_news.html.twig @@ -0,0 +1,16 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/slide.html.twig' as slide %} + +
+ {{ slide.image(content) }} + +
+
+ {{ content.fields.publish_date.value.value|date('j. n. Y.') }} +
+

{{ content_fields.title(content) }}

+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/slide/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/slide/ng_video.html.twig new file mode 100644 index 0000000..54f4a58 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/slide/ng_video.html.twig @@ -0,0 +1,19 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import "@ezdesign/parts/video.html.twig" as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} +
+ {{ video.poster_slide(content, use_lazy_load|default(false), content_fields.title(content)) }} + + +
+{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/content/standard.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard.html.twig new file mode 100644 index 0000000..e7b15b7 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard.html.twig @@ -0,0 +1,17 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location) }} + +
+

{{ content_fields.title(content) }}

+
+ + {% if with_intro|default(false) %} + {{ content_fields.intro(content) }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/file.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/file.html.twig new file mode 100644 index 0000000..68360d3 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/file.html.twig @@ -0,0 +1,12 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/image.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/image.html.twig new file mode 100644 index 0000000..98a4539 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/image.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +
+ +
+ {{ ng_render_field( + content.fields.image, { + parameters: { + alias: 'i480', + alt_text: content.fields.name.value.text, + link_href: path(location) + } + } + ) }} +
+ +
+

{{ ng_render_field(content.fields.name) }}

+
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_article.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_article.html.twig new file mode 100644 index 0000000..85fa477 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_article.html.twig @@ -0,0 +1,28 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+ {% if with_intro|default(false) %} + {{ content_fields.intro(content) }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_audio.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_audio.html.twig new file mode 100644 index 0000000..e7bd5c3 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_audio.html.twig @@ -0,0 +1,21 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_banner.html.twig new file mode 100644 index 0000000..9fff388 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_banner.html.twig @@ -0,0 +1,27 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import "@ezdesign/parts/macros.html.twig" as macros %} + +{% block content %} +
+ + {% if not content.fields.image.empty %} +
+ {{ macros.image_link(content, 'image', 'i480') }} +
+ {% endif %} + +
+

+ {{ macros.content_link(content, content.fields.title.value.text) }} +

+
+ + {% if with_intro|default(false) %} +
+ {{ ng_render_field(content.fields.short_description) }} +
+ {% endif %} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_blog_post.html.twig new file mode 100644 index 0000000..6ca26de --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_blog_post.html.twig @@ -0,0 +1,30 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+ + {% if with_intro|default(false) %} + {{ content_fields.intro(content) }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_category.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_category.html.twig new file mode 100644 index 0000000..fba6ae0 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_category.html.twig @@ -0,0 +1,14 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_feedback_form.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_feedback_form.html.twig new file mode 100644 index 0000000..12f5f35 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_feedback_form.html.twig @@ -0,0 +1,14 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_frontpage.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_frontpage.html.twig new file mode 100644 index 0000000..bcaec76 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_frontpage.html.twig @@ -0,0 +1,8 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_gallery.html.twig new file mode 100644 index 0000000..6cf8787 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_gallery.html.twig @@ -0,0 +1,40 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set location_path = path(location) %} +{% set children = location.filterChildren(['image'], 1).currentPageResults %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_htmlbox.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_htmlbox.html.twig new file mode 100644 index 0000000..329eee0 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_htmlbox.html.twig @@ -0,0 +1,8 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +
+
+ {{ content.fields.html_code.value.text|raw }} +
+
diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_landing_page.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_landing_page.html.twig new file mode 100644 index 0000000..f1b8738 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_landing_page.html.twig @@ -0,0 +1,14 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_news.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_news.html.twig new file mode 100644 index 0000000..a34f6d0 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_news.html.twig @@ -0,0 +1,30 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+ + {% if with_intro|default(false) %} + {{ content_fields.intro(content) }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_recipe.html.twig new file mode 100644 index 0000000..d004c19 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_recipe.html.twig @@ -0,0 +1,36 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {{ content_fields.image(content, location) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} + + {% if not content.fields.preparation_time.empty %} + {{ ng_render_field(content.fields.preparation_time) }} {{ 'ngsite.layout.recipe.min'|trans }} + {% endif %} + {% if not content.fields.serving_calories.empty %} + {{ ng_render_field(content.fields.serving_calories) }} {{ 'ngsite.layout.recipe.cal'|trans }} + {% endif %} + +
+
+ + {% if with_intro|default(false) %} + {{ content_fields.intro(content) }} + {% endif %} +
diff --git a/src/AppBundle/Resources/views/themes/app/content/standard/ng_video.html.twig b/src/AppBundle/Resources/views/themes/app/content/standard/ng_video.html.twig new file mode 100644 index 0000000..11cb057 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/content/standard/ng_video.html.twig @@ -0,0 +1,28 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/video.html.twig' as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} +
+ +
+ {{ video.poster(content, location, null, content_fields.title(content)) }} +
+ +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+ {% if with_intro|default(false) %} + {{ content_fields.intro(content) }} + {% endif %} +
+{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/errors/403.html.twig b/src/AppBundle/Resources/views/themes/app/errors/403.html.twig new file mode 100644 index 0000000..9b8fec8 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/errors/403.html.twig @@ -0,0 +1,13 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain 'ngsite_errors' %} + +{% set site_title = 'ngsite.errors.403.title'|trans %} + +{% block content %} +
+

{{ 'ngsite.errors.403.title'|trans }}

+ +
{{ 'ngsite.errors.403.message'|trans }}
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/errors/404.html.twig b/src/AppBundle/Resources/views/themes/app/errors/404.html.twig new file mode 100644 index 0000000..c3a2499 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/errors/404.html.twig @@ -0,0 +1,13 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain 'ngsite_errors' %} + +{% set site_title = 'ngsite.errors.404.title'|trans %} + +{% block content %} +
+

{{ 'ngsite.errors.404.title'|trans }}

+ +
{{ 'ngsite.errors.404.message'|trans }}
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/errors/500.html.twig b/src/AppBundle/Resources/views/themes/app/errors/500.html.twig new file mode 100644 index 0000000..a9875fd --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/errors/500.html.twig @@ -0,0 +1,13 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain 'ngsite_errors' %} + +{% set site_title = 'ngsite.errors.500.title'|trans %} + +{% block content %} +
+

{{ 'ngsite.errors.500.title'|trans }}

+ +
{{ 'ngsite.errors.500.message'|trans }}
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/errors/default.html.twig b/src/AppBundle/Resources/views/themes/app/errors/default.html.twig new file mode 100644 index 0000000..073738a --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/errors/default.html.twig @@ -0,0 +1,13 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain 'ngsite_errors' %} + +{% set site_title = 'ngsite.errors.default.title'|trans %} + +{% block content %} +
+

{{ 'ngsite.errors.default.title'|trans }}

+ +
{{ 'ngsite.errors.default.message'|trans }}
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/forms/theme.html.twig b/src/AppBundle/Resources/views/themes/app/forms/theme.html.twig new file mode 100644 index 0000000..da5de1c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/forms/theme.html.twig @@ -0,0 +1,42 @@ +{% extends 'form_div_layout.html.twig' %} + +{%- block form_row -%} +
+ {%- if 'checkbox' in block_prefixes or 'radio' in block_prefixes -%} + {{- form_widget(form) -}} + {{- form_label(form) -}} + {{- form_errors(form) -}} + {%- else -%} + {{- form_label(form) -}} + {{- form_widget(form) -}} + {{- form_errors(form) -}} + {%- endif -%} +
+{%- endblock form_row -%} + +{%- block form_errors -%} + {%- if errors|length > 0 -%} +
    + {%- for error in errors -%} +
  • {{ error.message }}
  • + {%- endfor -%} +
+ {%- endif -%} +{%- endblock form_errors -%} + +{%- block _ezforms_create_user_user_account_row -%} + {{- form_errors(form) -}} + {{- form_widget(form) -}} +{%- endblock -%} + +{%- block _ezforms_create_user_user_account_widget -%} + {% for identifier, child in form %} + {% if identifier == 'password' %} + {{ form_row(child.first, {attr: attr}) }} + + {{ form_row(child.second, {attr: attr}) }} + {% else %} + {{ form_row(child, {attr: attr}) }} + {% endif %} + {% endfor %} +{%- endblock -%} diff --git a/src/AppBundle/Resources/views/themes/app/info_collection/email.html.twig b/src/AppBundle/Resources/views/themes/app/info_collection/email.html.twig new file mode 100644 index 0000000..c1a4e4c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/info_collection/email.html.twig @@ -0,0 +1,53 @@ +{% block subject %}{% apply spaceless %} + {% set site_name = ngsite.siteInfoContent.fields.site_name.value.text|trim %} + {{ site_name }} – {{ ez_content_name(content) }} [{{ collected_fields.email }}] +{% endapply %}{% endblock %} + +{#% block sender %}{{ collected_fields.email }}{% endblock %#} + +{% block recipient %}{{ ez_field_value(content, 'recipient') }}{% endblock %} + +{% block email %} + + + + + + + + + + + +
+ +
{{ ez_content_name(content) }}
+ +
+ +{{ 'ngsite.collected_info.information_collected'|trans }}: + +

+ + +{% for collected_field, collected_field_value in collected_fields %} + + + + +{% endfor %} +
+ {{ ez_field_name(content, collected_field) }}: + + {{ collected_field_value }} +
+ +



+ + + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/link.html.twig b/src/AppBundle/Resources/views/themes/app/link.html.twig new file mode 100644 index 0000000..4cab509 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/link.html.twig @@ -0,0 +1,27 @@ +{% set root_location_path = path(ezpublish.rootLocation) %} + +{% if canonical_url|default('') is not empty %} + +{% endif %} + + + + + + + + + + + + + + + +{% if available_hreflang_translations|default|length > 1 %} + {% set locale_conversion_map = ezpublish.configResolver.getParameter('locale.conversion_map', 'ngsite') %} + + {% for language, url in available_hreflang_translations %} + + {% endfor %} +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/menu.html.twig b/src/AppBundle/Resources/views/themes/app/menu.html.twig new file mode 100644 index 0000000..1e683f2 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/menu.html.twig @@ -0,0 +1,3 @@ +{% extends '@KnpMenu/menu.html.twig' %} + +{# To override this template, copy and paste relevant blocks from '@KnpMenu/menu.html.twig' and 'knp_menu.html.twig' #} diff --git a/src/AppBundle/Resources/views/themes/app/page_footer.html.twig b/src/AppBundle/Resources/views/themes/app/page_footer.html.twig new file mode 100644 index 0000000..b835cc7 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_footer.html.twig @@ -0,0 +1,57 @@ +{% set site_info = ngsite.siteInfoContent %} + +
+
+ {% include '@ezdesign/parts/site_logo.html.twig' %} + + + + + + + +
+
diff --git a/src/AppBundle/Resources/views/themes/app/page_footer_script.html.twig b/src/AppBundle/Resources/views/themes/app/page_footer_script.html.twig new file mode 100644 index 0000000..a423941 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_footer_script.html.twig @@ -0,0 +1 @@ +{# This file is intentionally left blank #} diff --git a/src/AppBundle/Resources/views/themes/app/page_head.html.twig b/src/AppBundle/Resources/views/themes/app/page_head.html.twig new file mode 100644 index 0000000..6877d12 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_head.html.twig @@ -0,0 +1,58 @@ +{% set site_info_metadata = ngsite.siteInfoContent.fields.metadata.value %} + +{% set default_meta_data = { + keywords: site_info_metadata.keywords, + description: site_info_metadata.description +} %} + +{% set meta_data = default_meta_data|merge(meta_data|default([])) %} + +{% if content is defined %} + {% if content.hasField('metadata') and not content.fields.metadata.empty %} + {% set content_meta_data = content.fields.metadata.value %} + {% for key in default_meta_data|keys %} + {% if content_meta_data[key]|default('') is not empty %} + {% set meta_data = meta_data|merge({(key): content_meta_data[key]}) %} + {% endif %} + {% endfor %} + {% endif %} +{% endif %} + +{% if site_title is not defined %} + {% set site_title = '' %} + + {% if path_array is not empty %} + {% if not ezpublish.configResolver.getParameter('site_settings.show_path_in_title', 'ngsite') %} + {% set site_title = path_array[path_array|length - 1].text %} + {% elseif path_array|length > 1 %} + {% for path_item in path_array %} + {% if not loop.first %} + {% set site_title = path_item.text ~ (site_title is not empty ? ' - ' ~ site_title : '') %} + {% endif %} + {% endfor %} + {% endif %} + {% endif %} +{% endif %} + +{% if site_title is not empty %} + {% set site_title = site_title ~ (site_name is not empty ? ' - ' ~ site_name : '') %} +{% else %} + {% set site_title = site_name|default('') %} +{% endif %} + +{% if content_meta_data.title|default('') is not empty %} + {% set site_title = content_meta_data.title %} +{% endif %} + +{{ site_title }} + +{% for key in default_meta_data|keys %} + {% if meta_data[key]|default('') is not empty %} + + {% endif %} +{% endfor %} + + + + +{% include '@ezdesign/link.html.twig' %} diff --git a/src/AppBundle/Resources/views/themes/app/page_head_script.html.twig b/src/AppBundle/Resources/views/themes/app/page_head_script.html.twig new file mode 100644 index 0000000..c5c77f2 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_head_script.html.twig @@ -0,0 +1,3 @@ +{{ encore_entry_script_tags('app', null, 'app') }} + + diff --git a/src/AppBundle/Resources/views/themes/app/page_head_style.html.twig b/src/AppBundle/Resources/views/themes/app/page_head_style.html.twig new file mode 100644 index 0000000..66e2fa9 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_head_style.html.twig @@ -0,0 +1,5 @@ + + +{{ encore_entry_link_tags('app', null, 'app') }} + + diff --git a/src/AppBundle/Resources/views/themes/app/page_header.html.twig b/src/AppBundle/Resources/views/themes/app/page_header.html.twig new file mode 100644 index 0000000..c2adff5 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_header.html.twig @@ -0,0 +1,13 @@ + diff --git a/src/AppBundle/Resources/views/themes/app/page_header_languages.html.twig b/src/AppBundle/Resources/views/themes/app/page_header_languages.html.twig new file mode 100644 index 0000000..76f600b --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_header_languages.html.twig @@ -0,0 +1,25 @@ +{% if available_translations|length > 1 %} + {% set prioritized_languages = ezpublish.configResolver.getParameter('languages') %} + + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/page_header_searchbox.html.twig b/src/AppBundle/Resources/views/themes/app/page_header_searchbox.html.twig new file mode 100644 index 0000000..c96ab95 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_header_searchbox.html.twig @@ -0,0 +1,10 @@ + diff --git a/src/AppBundle/Resources/views/themes/app/page_path.html.twig b/src/AppBundle/Resources/views/themes/app/page_path.html.twig new file mode 100644 index 0000000..d2341ab --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_path.html.twig @@ -0,0 +1,13 @@ +{% if show_path and path_array|length > 1 %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/app/page_topmenu.html.twig b/src/AppBundle/Resources/views/themes/app/page_topmenu.html.twig new file mode 100644 index 0000000..be02b68 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/page_topmenu.html.twig @@ -0,0 +1,12 @@ + diff --git a/src/AppBundle/Resources/views/themes/app/pagelayout.html.twig b/src/AppBundle/Resources/views/themes/app/pagelayout.html.twig new file mode 100644 index 0000000..1f93525 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/pagelayout.html.twig @@ -0,0 +1,63 @@ +{% extends '@ezdesign/pagelayout_variables.html.twig' %} + +{% block pagelayout_content %} + + + + + + {% block page_head %} + {% include '@ezdesign/page_head.html.twig' %} + {% endblock %} + + {% block page_head_style %} + {% include '@ezdesign/page_head_style.html.twig' %} + {% endblock %} + + {% block page_head_script %} + {% include '@ezdesign/page_head_script.html.twig' %} + {% endblock %} + + {% block open_graph %} + {% include '@NetgenSite/parts/opengraph.html.twig' %} + {% endblock %} + + {% include '@NetgenSite/parts/jwplayer.html.twig' %} + + {% include '@NetgenSite/parts/google_tag_manager_code.html.twig' %} + + {% block structuredData %}{% endblock %} + + + +{% include '@NetgenSite/parts/facebook_api.html.twig' %} + +
+ {% block layout %} + {% block header %} + {% include '@ezdesign/page_header.html.twig' %} + {% endblock %} + + {% block breadcrumb %} + {% include '@ezdesign/page_path.html.twig' %} + {% endblock %} + +
+ {% block content %}{% endblock %} +
+ + {% block footer %} + {% include '@ezdesign/page_footer.html.twig' %} + {% endblock %} + {% endblock %} +
+ +{% block page_footer_script %} + {% include '@ezdesign/page_footer_script.html.twig' %} +{% endblock %} + +{% include '@ezdesign/parts/cookie_control.html.twig' %} + + + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/pagelayout_legacy.html.twig b/src/AppBundle/Resources/views/themes/app/pagelayout_legacy.html.twig new file mode 100644 index 0000000..5bf1d13 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/pagelayout_legacy.html.twig @@ -0,0 +1,59 @@ +{% extends nglayouts.layoutTemplate %} + +{# PERSISTENT VARIABLE #} + +{% set content_info = null %} +{% if ezpublish.legacy.has('content_info') %} + {% set content_info = ezpublish.legacy.get('content_info') %} +{% endif %} + +{% if module_result.content_info is defined %} + {% set content_info = module_result.content_info %} +{% endif %} + +{% set persistent_variable = null %} +{% if content_info.persistent_variable is defined %} + {% set persistent_variable = content_info.persistent_variable %} +{% endif %} + +{# SHOWING OR HIDING PATH #} + +{% if persistent_variable.show_path|default(true) is same as(false) %} + {% set show_path = false %} +{% endif %} + +{# OPENGRAPH #} + +{% if persistent_variable.opengraph is defined %} + {% set open_graph = persistent_variable.opengraph %} +{% endif %} + +{# SITE TITLE #} + +{% if persistent_variable.site_title is defined %} + {% set site_title = persistent_variable.site_title %} +{% endif %} + +{# METADATA #} + +{% set config_meta_data = ezpublish.configResolver.getParameter('site_settings.meta_data', 'ngsite') %} +{% set meta_data = [] %} +{% for key in config_meta_data|keys %} + {% if persistent_variable[key] is defined %} + {% set meta_data = meta_data|merge({(key): persistent_variable[key]}) %} + {% endif %} +{% endfor %} + +{# CANONICAL URL #} + +{% if persistent_variable.canonical_url is defined %} + {% set canonical_url = persistent_variable.canonical_url %} +{% elseif persistent_variable.canonical_language_url is defined %} + {% set canonical_url = persistent_variable.canonical_language_url %} +{% endif %} + +{# CONTENT BLOCK #} + +{% block content %} + {{ module_result.content|raw }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/pagelayout_module.html.twig b/src/AppBundle/Resources/views/themes/app/pagelayout_module.html.twig new file mode 100644 index 0000000..ee66433 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/pagelayout_module.html.twig @@ -0,0 +1,38 @@ +{% extends '@ezdesign/pagelayout_legacy.html.twig' %} + +{# MAKE PARENT TEMPLATES AWARE OF ANY ERROR #} + +{% if module_result.errorCode is defined %} + {% set status_code = module_result.errorCode %} +{% endif %} + +{# PATH ARRAY #} + +{% set legacy_path_array = ezpublish.legacy.has('path') ? ezpublish.legacy.get('path') : [] %} +{% set path_array = [] %} + +{% for legacy_path_item in legacy_path_array %} + {% set path_array = path_array|merge([{ + url: legacy_path_item.url ? path('ez_legacy', {'module_uri': legacy_path_item.url}) : false, + text: legacy_path_item.text + }]) %} +{% endfor %} + +{# AVAILABLE TRANSLATIONS #} + +{% set available_translations = [] %} + +{% if not (module_result is defined and module_result.errorCode is defined) %} + {% for language in ezpublish.availableLanguages %} + {% set translation_site_access = ezpublish.translationSiteAccess(language) %} + + {% if translation_site_access is not empty %} + {% set url = url(ez_route(params={'siteaccess': translation_site_access})) %} + {% set available_translations = available_translations|merge({(language): url}) %} + {% endif %} + {% endfor %} +{% endif %} + +{% block content %} + {{ module_result.content|raw }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/pagelayout_variables.html.twig b/src/AppBundle/Resources/views/themes/app/pagelayout_variables.html.twig new file mode 100644 index 0000000..19adc46 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/pagelayout_variables.html.twig @@ -0,0 +1,75 @@ +{% apply spaceless %} + +{# SITE NAME #} + +{% if site_name is not defined %} + {% set site_name = ngsite.siteInfoContent.fields.site_name.value.text|trim %} +{% endif %} + +{# PATH ARRAY #} + +{% if show_path is not defined %} + {% set show_path = true %} +{% endif %} + +{% if path_array is not defined %} + {% if content is defined and location|default(null) is not empty and not location.innerLocation.isDraft %} + {% set path_array = ngsite_location_path(location.id) %} + {% if path_array is not empty %} + {% set main_category_location_id = path_array[1].location.id ?? path_array[0].location.id %} + {% endif %} + {% else %} + {% set path_array = [] %} + {% set main_category_location_id = 0 %} + {% endif %} +{% endif %} + +{# AVAILABLE TRANSLATIONS #} + +{% if available_translations is not defined %} + {% set available_translations = [] %} + {% set available_hreflang_translations = [] %} + {% set current_content_language = null %} + + {% if content is defined %} + {% for language in ezpublish.configResolver.parameter('languages') %} + {% if current_content_language is empty and language in content.versionInfo.languageCodes %} + {% set current_content_language = language %} + {% endif %} + {% endfor %} + + {% if current_content_language is empty %} + {% set current_content_language = content.contentInfo.mainLanguageCode %} + {% endif %} + {% endif %} + + {% for language in ezpublish.availableLanguages %} + {% set translation_site_access = ezpublish.translationSiteAccess(language) %} + + {% if translation_site_access is not empty %} + {% set siteaccess_languages = ezpublish.configResolver.parameter('languages', null, translation_site_access) %} + {% set route_reference = ez_route(params={'siteaccess': translation_site_access}) %} + {% set homepage_url = url(ezpublish.rootLocation, {siteaccess: translation_site_access}) %} + + {% if route_reference.route is not empty %} + {% if content is not defined %} + {% set url = url(route_reference) %} + {% set available_translations = available_translations|merge({(language): url}) %} + {% set available_hreflang_translations = available_hreflang_translations|merge({(language): url}) %} + {% elseif language in content.versionInfo.languageCodes or content.contentInfo.alwaysAvailable %} + {% set url = url(route_reference, {'language': language}) %} + {% if '/view/content/' not in url %} + {% set available_translations = available_translations|merge({(language): url}) %} + {% set available_hreflang_translations = available_hreflang_translations|merge({(language): url}) %} + {% endif %} + {% else %} + {% set available_translations = available_translations|merge({(language): homepage_url}) %} + {% endif %} + {% else %} + {% set available_translations = available_translations|merge({(language): homepage_url}) %} + {% endif %} + {% endif %} + {% endfor %} +{% endif %} + +{% endapply %}{% block pagelayout_content %}{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/search/search.html.twig b/src/AppBundle/Resources/views/themes/app/search/search.html.twig new file mode 100644 index 0000000..0cb951b --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/search/search.html.twig @@ -0,0 +1,77 @@ +{% extends nglayouts.layoutTemplate %} + +{% set show_path = false %} + +{% block pre_content %} + +{% endblock %} + +{% block content %} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/tag/view.html.twig b/src/AppBundle/Resources/views/themes/app/tag/view.html.twig new file mode 100644 index 0000000..1e60afe --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/tag/view.html.twig @@ -0,0 +1,37 @@ +{% extends nglayouts.layoutTemplate %} + +{% set tag_keyword = netgen_tags_tag_keyword(tag) %} +{% set topic_tag = tag_keyword %} + +{% set show_path = false %} +{% set site_title = tag_keyword %} + +{% block pre_content %} +
+
+

{{ tag_keyword }}

+
+
+{% endblock %} + +{% block content %} +
+ {% if related_content|length > 0 %} +
+ {% for related_content_item in related_content %} +
+ {% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: related_content_item, + location_id: related_content_item.contentInfo.mainLocationId, + view_type: 'standard_with_intro' + } only %} +
+ {% endfor %} +
+ + {% if related_content.haveToPaginate() %} + {{ pagerfanta(related_content, 'ngsite') }} + {% endif %} + {% endif %} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/activate.html.twig b/src/AppBundle/Resources/views/themes/app/user/activate.html.twig new file mode 100644 index 0000000..fb8b603 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/activate.html.twig @@ -0,0 +1,23 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block content %} + + +

{{ 'ngsite.user.activate.text'|trans }}

+ + {{ form_start(form) }} + +
+
+ {{ form_row(form.email, {'label': 'ngsite.user.activate.email.label', 'attr': {'class': 'form-control'}}) }} +
+ + +
+ + {{ form_end(form) }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/activate_admin_activation_pending.html.twig b/src/AppBundle/Resources/views/themes/app/user/activate_admin_activation_pending.html.twig new file mode 100644 index 0000000..fd259a7 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/activate_admin_activation_pending.html.twig @@ -0,0 +1,13 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block content %} + + +

{{ 'ngsite.user.activate.admin_activation_pending.text'|trans }}

+ + +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/activate_done.html.twig b/src/AppBundle/Resources/views/themes/app/user/activate_done.html.twig new file mode 100644 index 0000000..a38e1c1 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/activate_done.html.twig @@ -0,0 +1,21 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block content %} + + + {% if error is defined %} + {% if error == 'hash_expired' %} +
+ {{ 'ngsite.user.activate.done.error.hash_expired'|trans({'%link%': path('ngsite_resend_activation_mail')})|raw }} +
+ {% else %} +
{{ 'ngsite.user.activate.done.error.other'|trans }}
+ {% endif %} + {% else %} +

{{ "ngsite.user.activate.done.text"|trans({'%link%': path('login')})|raw }}

+ {% endif %} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/activate_sent.html.twig b/src/AppBundle/Resources/views/themes/app/user/activate_sent.html.twig new file mode 100644 index 0000000..08de2ff --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/activate_sent.html.twig @@ -0,0 +1,19 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block pre_content %} +
+
+

{{ 'ngsite.user.activate.sent.title'|trans }}

+
+
+{% endblock %} + +{% block content %} +
+
+

{{ 'ngsite.user.activate.sent.text'|trans({'%link%': path('ngsite_resend_activation_mail')})|raw }}

+
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/forgot_password.html.twig b/src/AppBundle/Resources/views/themes/app/user/forgot_password.html.twig new file mode 100644 index 0000000..a6caf01 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/forgot_password.html.twig @@ -0,0 +1,30 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block pre_content %} +
+
+

{{ "ngsite.user.forgot_password.title"|trans }}

+
+

{{ "ngsite.user.forgot_password.text"|trans }}

+
+
+
+{% endblock %} + +{% block content %} +
+ {{ form_start(form) }} + +
+
+ {{ form_row(form.email, {'label': 'ngsite.user.forgot_password.email.label', 'attr': {'class': 'form-control'}}) }} +
+ + +
+ + {{ form_end(form) }} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/forgot_password_sent.html.twig b/src/AppBundle/Resources/views/themes/app/user/forgot_password_sent.html.twig new file mode 100644 index 0000000..68ccb98 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/forgot_password_sent.html.twig @@ -0,0 +1,19 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block pre_content %} +
+
+

{{ "ngsite.user.forgot_password.sent.title"|trans }}

+
+
+{% endblock %} + +{% block content %} +
+
+

{{ "ngsite.user.forgot_password.sent.text"|trans({'%link%': path('ngsite_user_forgot_password')})|raw }}

+
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/login.html.twig b/src/AppBundle/Resources/views/themes/app/user/login.html.twig new file mode 100644 index 0000000..1c81cba --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/login.html.twig @@ -0,0 +1,50 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block pre_content %} +
+
+

{{ 'ngsite.user.login.title'|trans }}

+
+
+{% endblock %} + +{% block content %} + {% block login_content %} +
+ {% if error %} +
{{ error.message|trans }}
+ {% endif %} + +
+ {% block login_fields %} +
+
+ + +
+
+ + +
+ + {% if app.request.attributes.get("csrf_enabled") %} + + {% endif %} + + {# + If you want to control the URL the user + is redirected to on success (more details below) + + #} + +
{{ "ngsite.user.login.forgot_password_link"|trans({'%link%': path('ngsite_user_forgot_password')})|raw }}
+
+ {% endblock %} +
+ +

{{ "ngsite.user.login.register_text"|trans }} {{ "ngsite.user.login.register_link"|trans({'%link%': path('ngsite_user_register')})|raw }}

+
+ {% endblock %} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/activate.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/activate.html.twig new file mode 100644 index 0000000..78147bb --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/activate.html.twig @@ -0,0 +1,23 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ "ngsite.user.activate.text"|trans }} {{ url('ngsite_user_activate', {hash: hash}) }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/activate_admin_activation_pending.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/activate_admin_activation_pending.html.twig new file mode 100644 index 0000000..8a874d2 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/activate_admin_activation_pending.html.twig @@ -0,0 +1,23 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ "ngsite.user.activate.admin_activation_pending.text"|trans }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/activate_admin_activation_required.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/activate_admin_activation_required.html.twig new file mode 100644 index 0000000..1ce66dd --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/activate_admin_activation_required.html.twig @@ -0,0 +1,23 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ "ngsite.user.activate.admin_activation_required.text"|trans }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/activate_already_active.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/activate_already_active.html.twig new file mode 100644 index 0000000..63e0f3b --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/activate_already_active.html.twig @@ -0,0 +1,27 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.activate.already_active.text"|trans }} + +
+ + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/activate_disabled.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/activate_disabled.html.twig new file mode 100644 index 0000000..803fa43 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/activate_disabled.html.twig @@ -0,0 +1,27 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.activate.disabled.text"|trans }} + +
+ + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/activate_not_registered.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/activate_not_registered.html.twig new file mode 100644 index 0000000..e527a70 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/activate_not_registered.html.twig @@ -0,0 +1,15 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.activate.not_registered.text"|trans }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password.html.twig new file mode 100644 index 0000000..17e6c7c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password.html.twig @@ -0,0 +1,23 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ "ngsite.user.forgot_password.text"|trans }} {{ url('ngsite_user_reset_password', {hash: hash}) }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_disabled.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_disabled.html.twig new file mode 100644 index 0000000..5d46aa5 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_disabled.html.twig @@ -0,0 +1,27 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.forgot_password.disabled.text"|trans }} + +
+ + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_not_active.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_not_active.html.twig new file mode 100644 index 0000000..34ff188 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_not_active.html.twig @@ -0,0 +1,27 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.forgot_password.not_active.text"|trans }} + +
+ + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_not_registered.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_not_registered.html.twig new file mode 100644 index 0000000..68d7b29 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_not_registered.html.twig @@ -0,0 +1,15 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.forgot_password.not_registered.text"|trans }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_password_changed.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_password_changed.html.twig new file mode 100644 index 0000000..c68cae0 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/forgot_password_password_changed.html.twig @@ -0,0 +1,27 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.forgot_password.password_changed.text"|trans }} + +
+ + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/layout.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/layout.html.twig new file mode 100644 index 0000000..e5a1f66 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/layout.html.twig @@ -0,0 +1,29 @@ +{% trans_default_domain "ngsite_mail" %} + + + + + + + + + + + + +
+ +
+{% block title %}{% endblock %} +
+ +
+ +{% block content %}{% endblock %} + + + diff --git a/src/AppBundle/Resources/views/themes/app/user/mail/welcome.html.twig b/src/AppBundle/Resources/views/themes/app/user/mail/welcome.html.twig new file mode 100644 index 0000000..322171a --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/mail/welcome.html.twig @@ -0,0 +1,27 @@ +{% extends '@ezdesign/user/mail/layout.html.twig' %} + +{% trans_default_domain "ngsite_mail" %} + +{% block title %} + {{ site_name }} +{% endblock %} + +{% block content %} + {{ "ngsite.user.welcome.text"|trans }} + +
+ + {{ "ngsite.user.account_information"|trans }} + +
+ + {{ "ngsite.user.username"|trans }}: {{ user.login }} + +
+ + {{ "ngsite.user.email"|trans }}: {{ user.email }} + +

+ + {{ site_name }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/register.html.twig b/src/AppBundle/Resources/views/themes/app/user/register.html.twig new file mode 100644 index 0000000..8ed2efe --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/register.html.twig @@ -0,0 +1,39 @@ +{% extends nglayouts.layoutTemplate %} + +{% form_theme form '@ezdesign/forms/theme.html.twig' %} + +{% trans_default_domain "ngsite_user" %} + +{% block pre_content %} +
+
+

{{ 'ngsite.user.register.title'|trans }}

+
+
+{% endblock %} + +{% block content %} +
+ {% if error is defined %} + {% if error == 'email_in_use' %} +
{{ "ngsite.user.register.error.email_in_use"|trans }}
+ {% elseif error == 'username_taken' %} +
{{ "ngsite.user.register.error.username_taken"|trans }}
+ {% else %} +
{{ "ngsite.user.register.error.other"|trans }}
+ {% endif %} + {% endif %} + + {{ form_start(form) }} + +
+ {% for form_child in form.children %} + {{ form_row(form_child, {attr: {class: 'form-control'}}) }} + {% endfor %} + + +
+ + {{ form_end(form) }} +
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/register_success.html.twig b/src/AppBundle/Resources/views/themes/app/user/register_success.html.twig new file mode 100644 index 0000000..62c3f47 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/register_success.html.twig @@ -0,0 +1,19 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block pre_content %} +
+
+

{{ 'ngsite.user.register.success.title'|trans }}

+
+
+{% endblock %} + +{% block content %} +
+
+

{{ 'ngsite.user.register.success.text'|trans({'%link%': path('login')})|raw }}

+
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/reset_password.html.twig b/src/AppBundle/Resources/views/themes/app/user/reset_password.html.twig new file mode 100644 index 0000000..bf63cf9 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/reset_password.html.twig @@ -0,0 +1,27 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block content %} + + +

{{ "ngsite.user.reset_password.text"|trans }}

+ + {{ form_start(form) }} + +
+
+ {{ form_row(form.password.first, {'label': 'ngsite.user.reset_password.first.label', 'attr': {'class': 'form-control'}}) }} +
+ +
+ {{ form_row(form.password.second, {'label': 'ngsite.user.reset_password.second.label', 'attr': {'class': 'form-control'}}) }} +
+ + +
+ + {{ form_end(form) }} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/app/user/reset_password_done.html.twig b/src/AppBundle/Resources/views/themes/app/user/reset_password_done.html.twig new file mode 100644 index 0000000..52792cd --- /dev/null +++ b/src/AppBundle/Resources/views/themes/app/user/reset_password_done.html.twig @@ -0,0 +1,21 @@ +{% extends nglayouts.layoutTemplate %} + +{% trans_default_domain "ngsite_user" %} + +{% block content %} + + + {% if error is defined %} + {% if error == 'hash_expired' %} +
+ {{ "ngsite.user.reset_password.done.error.hash_expired"|trans({'%link%': path('ngsite_user_forgot_password')})|raw }} +
+ {% else %} +
{{ 'ngsite.user.reset_password.done.error.other'|trans }}
+ {% endif %} + {% else %} +

{{ "ngsite.user.reset_password.done.text"|trans({'%link%': path('login')})|raw }}

+ {% endif %} +{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/common/browser/item.html.twig b/src/AppBundle/Resources/views/themes/common/browser/item.html.twig new file mode 100644 index 0000000..d80cc72 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/browser/item.html.twig @@ -0,0 +1,5 @@ +{% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: item.content, + location: item.location, + view_type: 'ngcb_preview' +} only %} diff --git a/src/AppBundle/Resources/views/themes/common/browser/ngcb_preview.html.twig b/src/AppBundle/Resources/views/themes/common/browser/ngcb_preview.html.twig new file mode 100644 index 0000000..12d8b9c --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/browser/ngcb_preview.html.twig @@ -0,0 +1,20 @@ +{% set valid_field_groups = ['', 'content'] %} + +
+ {% for field in content.fields %} + {% if not field.empty and field.innerFieldDefinition.fieldGroup in valid_field_groups %} +
+

{{ field.name }}

+ + {% if field.fieldTypeIdentifier == 'ezxmltext' %} + {# Special handling of ezxmltext field to prevent output of too much text #} + {{ field.value.xml.saveXML()|striptags|trim|truncate(300) }} + {% elseif field.fieldTypeIdentifier == 'ezimage' %} + {{ ng_render_field(field, {parameters: {alias: 'i480'}}) }} + {% else %} + {{ ng_render_field(field) }} + {% endif %} +
+ {% endif %} + {% endfor %} +
diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/image.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/image.html.twig new file mode 100644 index 0000000..bb6731b --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/image.html.twig @@ -0,0 +1,22 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +
+ +
+ {{ ng_render_field( + content.fields.image, { + parameters: { + alias: 'i480', + alt_text: content.fields.name.value.text, + link_href: path(location), + lazy_loading: false + } + } + ) }} +
+ +
+

{{ ng_render_field(content.fields.name) }}

+
+
diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_article.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_article.html.twig new file mode 100644 index 0000000..e1b7498 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_article.html.twig @@ -0,0 +1,27 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, null, false) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+ + {{ content_fields.intro(content) }} +
diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_audio.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_audio.html.twig new file mode 100644 index 0000000..a7d88cb --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_audio.html.twig @@ -0,0 +1,19 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_banner.html.twig new file mode 100644 index 0000000..5a31cc0 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_banner.html.twig @@ -0,0 +1,25 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import "@ezdesign/parts/macros.html.twig" as macros %} + +{% block content %} +
+ + {% if not content.fields.image.empty %} +
+ {{ macros.image_link(content, 'image', 'i480', false) }} +
+ {% endif %} + +
+

+ {{ macros.content_link(content, content.fields.title.value.text) }} +

+
+ +
+ {{ ng_render_field(content.fields.short_description) }} +
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_blog_post.html.twig new file mode 100644 index 0000000..6066c29 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_blog_post.html.twig @@ -0,0 +1,28 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, null, false) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+ + {{ content_fields.intro(content) }} +
diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_gallery.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_gallery.html.twig new file mode 100644 index 0000000..2f1b31d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_gallery.html.twig @@ -0,0 +1,39 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +{% set location_path = path(location) %} +{% set children = location.filterChildren(['image'], 1).currentPageResults %} + + diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_news.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_news.html.twig new file mode 100644 index 0000000..4eccbcb --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_news.html.twig @@ -0,0 +1,28 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ + {{ content_fields.image(content, location, null, false) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} +
+
+ + {{ content_fields.intro(content) }} +
diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_recipe.html.twig new file mode 100644 index 0000000..f8bb70d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_recipe.html.twig @@ -0,0 +1,34 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + +
+ {{ content_fields.image(content, location, null, false) }} + +
+

{{ content_fields.title(content) }}

+
+ {% if not content.fields.authors.empty %} + {% for author in content.fieldRelations('authors') %} + + {% endfor %} + {% endif %} + {% if not content.fields.sponsored_content_disclosure.empty %} + + {% elseif not content.fields.main_topic.empty %} + {{ content.fields.main_topic.value.tags[0].keyword }} + {% endif %} + + {% if not content.fields.preparation_time.empty %} + {{ ng_render_field(content.fields.preparation_time) }} {{ 'ngsite.layout.recipe.min'|trans }} + {% endif %} + {% if not content.fields.serving_calories.empty %} + {{ ng_render_field(content.fields.serving_calories) }} {{ 'ngsite.layout.recipe.cal'|trans }} + {% endif %} + +
+
+ + {{ content_fields.intro(content) }} +
diff --git a/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_video.html.twig b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_video.html.twig new file mode 100644 index 0000000..34ab2bc --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/content/ngcb_preview/ng_video.html.twig @@ -0,0 +1,27 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} +{% import '@ezdesign/parts/video.html.twig' as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/content_fields.html.twig b/src/AppBundle/Resources/views/themes/common/parts/content_fields.html.twig new file mode 100644 index 0000000..f20dbcd --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/content_fields.html.twig @@ -0,0 +1,67 @@ +{% macro image(content, location, alias_name, lazy_loading, link_class) %} + {% set alias_name = alias_name ?? 'i480' %} + {% set lazy_loading = lazy_loading ?? ezpublish.configResolver.getParameter('lazy_loading.enabled', 'ngsite') %} + + {% set image_field = false %} + {% if content.hasField('teaser_image') and not content.fields.teaser_image.empty %} + {% set image_field = content.fields.teaser_image %} + {% elseif content.hasField('image') and not content.fields.image.empty %} + {% set image_field = content.fields.image %} + {% endif %} + + {% if image_field %} +
+ {{ ng_render_field( + image_field, { + 'parameters': { + 'alias': alias_name, + 'link_href': location is not empty ? path(location) : null, + 'lazy_loading': lazy_loading, + 'link_class': link_class ?? null, + } + } + ) }} +
+ {% endif %} +{% endmacro %} + +{% macro title(content) %} +{% apply spaceless %} + {% set title = content.firstNonEmptyField('teaser_title', 'title', 'name') %} + {% if not title.empty %} + {{ title.value.text }} + {% else %} + {{ content.name }} + {% endif %} +{% endapply %} +{% endmacro %} + +{% macro intro(content) %} + {% if content.hasField('teaser_intro') and not content.fields.teaser_intro.empty %} +
+ {{ ng_render_field(content.fields.teaser_intro) }} +
+ {% elseif content.hasField('full_intro') and not content.fields.full_intro.empty %} +
+ {{ ng_render_field(content.fields.full_intro) }} +
+ {% endif %} +{% endmacro %} + +{% macro background_poster(content, field, alias_name) %} +{% apply spaceless %} + {% set alias_name = alias_name|default('original') %} + {% set field = field|default('image') %} + + {% set poster_image = '' %} + {% if not content.fields[field].empty %} + {% set poster_alias = ng_image_alias(content.fields[field], alias_name) %} + + {% if poster_alias %} + {% set poster_image = asset(poster_alias.uri) %} + {% endif %} + {% endif %} + + {{ poster_image }} +{% endapply %} +{% endmacro %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/cookie_control.html.twig b/src/AppBundle/Resources/views/themes/common/parts/cookie_control.html.twig new file mode 100644 index 0000000..b1801ed --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/cookie_control.html.twig @@ -0,0 +1,116 @@ +{% if ngsite.siteInfoContent.hasField('related_cookie_policy') and not ngsite.siteInfoContent.fields.related_cookie_policy.empty %} + {% set cookie_policy = ngsite.siteInfoContent.fieldRelation('related_cookie_policy') %} + +
+
+ +
+ +
+ {% if not cookie_policy.fields.ribbon_heading.empty %} +

{{ ng_render_field(cookie_policy.fields.ribbon_heading) }}

+ {% endif %} + + {% if not cookie_policy.fields.ribbon_description.empty %} + {{ ng_render_field(cookie_policy.fields.ribbon_description) }} + {% endif %} + +
+ +
+ +
    +
  • + + + + {% if not cookie_policy.fields.necessary_description.empty %} + {{ ng_render_field(cookie_policy.fields.necessary_description) }} + {% endif %} +
  • +
+
+
+
+ + +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/macros.html.twig b/src/AppBundle/Resources/views/themes/common/parts/macros.html.twig new file mode 100644 index 0000000..fd458ef --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/macros.html.twig @@ -0,0 +1,90 @@ +{% macro content_link(content, link_name, link_class) %} +{% apply spaceless %} + {% set url = false %} + {% set open_in_new_window = false %} + {% set link_class = link_class|default %} + + {% if not content.fields.url.empty %} + {% set url = content.fields.url.value.link %} + + {% if content.fields.target_blank.value.bool %} + {% set open_in_new_window = true %} + {% endif %} + {% elseif not content.fields.related_object.empty %} + {% set related_content = content.fieldRelation('related_object') %} + + {% if related_content is not null and related_content.id != content.id %} {# dead loop #} + {% set url = path(related_content) %} + {% endif %} + {% endif %} + + {% if url %} + + {% endif %} + + {{ link_name|default }} + + {% if url %} + + {% endif %} +{% endapply %} +{% endmacro %} + +{% macro image_link(content, field, alias, lazy_loading) %} +{% apply spaceless %} + {% set url = '#' %} + {% set open_in_new_window = false %} + {% set lazy_loading = lazy_loading ?? ezpublish.configResolver.getParameter('lazy_loading.enabled', 'ngsite') %} + + {% if not content.fields.url.empty %} + {% set url = content.fields.url.value.link %} + + {% if content.fields.target_blank.value.bool %} + {% set open_in_new_window = true %} + {% endif %} + {% elseif not content.fields.related_object.empty %} + {% set related_content = content.fieldRelation('related_object') %} + + {% if related_content is not null and related_content.id != content.id %} {# dead loop #} + {% set url = path(related_content) %} + {% endif %} + {% endif %} + + {{ ng_render_field( + content.fields[field], { + 'parameters': { + 'alias': alias, + 'link_href': url, + 'link_target': open_in_new_window ? '_blank' : '', + 'lazy_loading': lazy_loading, + } + } + ) }} +{% endapply %} +{% endmacro %} + +{% macro content_link_parameters(content) %} +{% apply spaceless %} + {% set url = '#' %} + {% set open_in_new_window = false %} + + {% if not content.fields.url.empty %} + {% set url = content.fields.url.value.link %} + + {% if content.fields.target_blank.value.bool %} + {% set open_in_new_window = true %} + {% endif %} + {% elseif not content.fields.related_object.empty %} + {% set related_content = content.fieldRelation('related_object') %} + + {% if related_content is not null and related_content.id != content.id %} {# dead loop #} + {% set url = path(related_content) %} + {% endif %} + {% endif %} + + href="{{ url }}"{% if open_in_new_window %} target="_blank" rel="nofollow noopener noreferrer"{% endif %} +{% endapply %} +{% endmacro %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/ng_view_content.html.twig b/src/AppBundle/Resources/views/themes/common/parts/ng_view_content.html.twig new file mode 100644 index 0000000..1fa629b --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/ng_view_content.html.twig @@ -0,0 +1,21 @@ +{% if ezpublish.configResolver.parameter('render_content_directly', 'ngsite') %} + {{ ng_view_content( + location|default(null) is not empty ? location : content, + view_type, { + 'params': params|default([]) + } + ) }} +{% else %} + {{ render( + controller( + 'ng_content:viewAction', { + 'content': content, + 'location': location|default(null), + 'locationId': location_id|default(null), + 'viewType': view_type, + 'layout': false, + 'params': params|default([]) + } + ) + ) }} +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_items.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_items.html.twig new file mode 100644 index 0000000..bcf4bd3 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_items.html.twig @@ -0,0 +1,9 @@ +{% if related_items|length > 0 %} + {% for related_item in related_items %} + {% include '@ezdesign/parts/ng_view_content.html.twig' with { + content: related_item.content, + location: related_item, + view_type: view_type + } only %} + {% endfor %} +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia.html.twig new file mode 100644 index 0000000..decb04f --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia.html.twig @@ -0,0 +1,36 @@ +{% if multimedia_items|default([])|length > 0 %} + {% set is_slider = multimedia_items|length > 1 %} + {% if multimedia_items|length == 2 and multimedia_items[0].content.hasField('image') and multimedia_items[0].content.fields.image.empty %} + {% set is_slider = false %} + {% endif %} + + {% if is_slider %} + + {% endif %} +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/image.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/image.html.twig new file mode 100644 index 0000000..3ce2904 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/image.html.twig @@ -0,0 +1,44 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% if not content.fields.image.empty %} + {% set image = content.fields.image %} + {% set image_alias = ng_image_alias(image, 'i1200') %} + {% set image_uri = image_alias ? image_alias.uri : '//:0' %} + {% set alt_text = image.value.alternativeText|default('') %} + {% set lazy_loading = ezpublish.configResolver.getParameter('lazy_loading.enabled', 'ngsite') %} + + {% if is_slider %} +
+ {% endif %} +
+ {% if is_slider %} + {{ alt_text }} + {% else %} + {{ alt_text }} + {% endif %} + + {% if content.fields.caption is defined and not content.fields.caption.empty %} +
+ {{ ng_render_field(content.fields.caption) }} +
+ {% endif %} +
+ {% if is_slider %} +
+ {% endif %} +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_article.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_article.html.twig new file mode 100644 index 0000000..7175a0d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_article.html.twig @@ -0,0 +1 @@ +{% extends '@ezdesign/parts/related_multimedia/image.html.twig' %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_banner.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_banner.html.twig new file mode 100644 index 0000000..55975e7 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_banner.html.twig @@ -0,0 +1,22 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import "@ezdesign/parts/macros.html.twig" as macros %} + +{% block content %} +
+ {% set image_uri = ng_image_alias(content.fields.image, 'i1200').uri|default('') %} + + {% if is_slider %} + + {% else %} + + {% endif %} + +
+

+ {{ macros.content_link(content, content.fields.title.value.text) }} +

+
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_blog_post.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_blog_post.html.twig new file mode 100644 index 0000000..7175a0d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_blog_post.html.twig @@ -0,0 +1 @@ +{% extends '@ezdesign/parts/related_multimedia/image.html.twig' %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_news.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_news.html.twig new file mode 100644 index 0000000..7175a0d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_news.html.twig @@ -0,0 +1 @@ +{% extends '@ezdesign/parts/related_multimedia/image.html.twig' %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_recipe.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_recipe.html.twig new file mode 100644 index 0000000..7175a0d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_recipe.html.twig @@ -0,0 +1 @@ +{% extends '@ezdesign/parts/related_multimedia/image.html.twig' %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_video.html.twig b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_video.html.twig new file mode 100644 index 0000000..8fd7f3d --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/related_multimedia/ng_video.html.twig @@ -0,0 +1,14 @@ +{# content \Netgen\EzPlatformSiteApi\API\Values\Content #} +{# location \Netgen\EzPlatformSiteApi\API\Values\Location #} + +{% import '@ezdesign/parts/video.html.twig' as video %} + +{% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty or not content.fields.video_identifier.empty %} + {% if is_slider %} +
+ {{ video.player_slide(content, true) }} +
+ {% else %} + {{ video.player(content, true) }} + {% endif %} +{% endif %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/site_logo.html.twig b/src/AppBundle/Resources/views/themes/common/parts/site_logo.html.twig new file mode 100644 index 0000000..dfbbc71 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/site_logo.html.twig @@ -0,0 +1,7 @@ + diff --git a/src/AppBundle/Resources/views/themes/common/parts/slide.html.twig b/src/AppBundle/Resources/views/themes/common/parts/slide.html.twig new file mode 100644 index 0000000..a9c6d66 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/slide.html.twig @@ -0,0 +1,37 @@ +{% macro image(content, field_name, alias_name, use_lazy_load) %} + {% import '@ezdesign/parts/content_fields.html.twig' as content_fields %} + + {% set field_name = field_name|default('image') %} + {% set alias_name = alias_name|default('i1200') %} + {% set use_lazy_load = use_lazy_load|default(false) %} + + {% if content.hasField(field_name) and not content.fields[field_name].empty %} + {% set image_alias = ng_image_alias(content.fields[field_name], alias_name) %} + + {% if use_lazy_load %} + {% if image_alias %} + {{ ng_render_field( + content.fields[field_name], { + parameters: { + alt_text: content_fields.title(content), + disable_src_attribute: true + }, + attr: { + class: 'swiper-lazy', + 'data-src': asset(image_alias.uri) + } + } + ) }} + {% endif %} + {% else %} + {{ ng_render_field( + content.fields[field_name], { + parameters: { + alias: alias_name, + alt_text: content_fields.title(content) + } + } + ) }} + {% endif %} + {% endif %} +{% endmacro %} diff --git a/src/AppBundle/Resources/views/themes/common/parts/video.html.twig b/src/AppBundle/Resources/views/themes/common/parts/video.html.twig new file mode 100644 index 0000000..d4af9f8 --- /dev/null +++ b/src/AppBundle/Resources/views/themes/common/parts/video.html.twig @@ -0,0 +1,182 @@ +{% macro poster(content, location, alias_name, alt_text) %} + {% set alias_name = alias_name|default('i480') %} + {% set alt_text = alt_text ?? null %} + + +
+ {% if not content.fields.poster.empty %} + {{ ng_render_field(content.fields.poster, {'parameters': {'alias': alias_name}}) }} + {% elseif not content.fields.video_identifier.empty %} + {% set video_identifier = content.fields.video_identifier.value.text %} + {% set video_types = content.fields.video_type.value.identifiers %} + + {% if 'youtube' in video_types %} + + {% elseif 'vimeo' in video_types %} + + {% elseif 'dailymotion' in video_types %} + + {% endif %} + {% else %} + + {% endif %} +
+
+{% endmacro %} + +{% macro poster_slide(content, use_lazy_load, alt_text) %} + {% import '@ezdesign/parts/slide.html.twig' as slide %} + + {% set use_lazy_load = use_lazy_load|default(false) %} + {% set alt_text = alt_text ?? null %} + + {% if not content.fields.poster.empty %} + {{ slide.image(content, 'poster', 'i1200', use_lazy_load) }} + {% elseif not content.fields.video_identifier.empty %} + {% set video_identifier = content.fields.video_identifier.value.text %} + {% set video_types = content.fields.video_type.value.identifiers %} + + {% if 'youtube' in video_types %} + + {% elseif 'vimeo' in video_types %} + + {% elseif 'dailymotion' in video_types %} + + {% endif %} + {% else %} + + {% endif %} +{% endmacro %} + +{% macro player(content, use_external_embed) %} + {% set use_external_embed = use_external_embed|default(false) %} + + {% set video_types = content.fields.video_type.value.identifiers %} + {% set autoplay = content.fields.autoplay.value.bool %} + + {% set image_path = asset('bundles/app/images/video_poster.png') %} + {% if not content.fields.poster.empty %} + {% set poster_alias = ng_image_alias(content.fields.poster, 'i1200') %} + + {% if poster_alias %} + {% set image_path = asset(poster_alias.uri) %} + {% endif %} + {% endif %} + + {% if 'upload' in video_types %} + {% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty %} + {% set field_name = content.fields.video_file_hd.empty ? 'video_file' : 'video_file_hd' %} + +
+
+ +
Loading the player ...
+ {% endif %} + {% elseif not content.fields.video_identifier.empty %} + {% set video_identifier = content.fields.video_identifier.value.text %} + + {% if 'youtube' in video_types %} + {% if use_external_embed %} +
+ +
+ {% else %} +
+
+
+ +
Loading the player ...
+
+ {% endif %} + {% elseif 'vimeo' in video_types %} + {# JW Player does not support Vimeo so only embed is available #} +
+ +
+ {% elseif 'dailymotion' in video_types %} + {# JW Player does not support Daily Motion so only embed is available #} +
+ +
+ {% endif %} + {% endif %} +{% endmacro %} + +{% macro player_slide(content, use_external_embed) %} + {% set use_external_embed = use_external_embed|default(false) %} + + {% set video_types = content.fields.video_type.value.identifiers %} + + {% set image_path = asset('bundles/app/images/video_poster.png') %} + {% if not content.fields.poster.empty %} + {% set poster_alias = ng_image_alias(content.fields.poster, 'i1200') %} + + {% if poster_alias %} + {% set image_path = asset(poster_alias.uri) %} + {% endif %} + {% endif %} + + {% if 'upload' in video_types %} + {% if not content.fields.video_file.empty or not content.fields.video_file_hd.empty %} + {% set field_name = content.fields.video_file_hd.empty ? 'video_file' : 'video_file_hd' %} + + + +
Loading the player ...
+ {% endif %} + {% elseif not content.fields.video_identifier.empty %} + {% set video_identifier = content.fields.video_identifier.value.text %} + + {% if 'youtube' in video_types %} + {% if use_external_embed %} +
+ +
+ {% else %} +
+ + +
Loading the player ...
+
+ {% endif %} + {% elseif 'vimeo' in video_types %} + {# JW Player does not support Vimeo so only embed is available #} +
+ +
+ {% elseif 'dailymotion' in video_types %} + {# JW Player does not support Daily Motion so only embed is available #} +
+ +
+ {% endif %} + {% endif %} +{% endmacro %} diff --git a/src/AppBundle/Resources/xsl/ezxml_tags.xsl b/src/AppBundle/Resources/xsl/ezxml_tags.xsl new file mode 100644 index 0000000..e8201a6 --- /dev/null +++ b/src/AppBundle/Resources/xsl/ezxml_tags.xsl @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/src/AppBundle/ezpublish_legacy/app/design/standard/templates/node/view/full.tpl b/src/AppBundle/ezpublish_legacy/app/design/standard/templates/node/view/full.tpl new file mode 100644 index 0000000..e394979 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/design/standard/templates/node/view/full.tpl @@ -0,0 +1 @@ +{redirect('/'|ezurl('no', 'full'))} diff --git a/src/AppBundle/ezpublish_legacy/app/extension.xml b/src/AppBundle/ezpublish_legacy/app/extension.xml new file mode 100644 index 0000000..a8c3493 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/extension.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/AppBundle/ezpublish_legacy/app/root/config.php b/src/AppBundle/ezpublish_legacy/app/root/config.php new file mode 100644 index 0000000..6b2edb6 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/root/config.php @@ -0,0 +1,259 @@ + + ini_set( 'include_path', ini_get( 'include_path' ). ':/usr/lib/FooFramework/' ); + require 'Foo/ClassLoader.php'; + + function fooAutoload( $className ) + { + if ( 'Foo' == substr( $className, 0, 3 ) ) + { + FooClassLoader::loadClass( $className ); + } + } + spl_autoload_register( 'fooAutoload' ); + +*/ + + + +/* + CLUSTERING + ---------- + + In order to serve binary files over HTTP, eZ Publish needs informations about your cluster backend. + Most of these settings will duplicate those found in your file.ini.append.php. + You can optionnaly define those constants in config.cluster.php +*/ + +/** + * Storage backend. Possible values: + * - dfsmysqli (DFS cluster, mysqli based) + * - dfspostgres (DFS cluster, postgresql based) + * - dfsoracle (with appropriate extension) + */ +// define( 'CLUSTER_STORAGE_BACKEND', 'dfsmysqli' ); + +/** + * Custom cluster storage backend + * Root relative path to the custom clustering backend. When provided, the gateway filename won't be built based + * on the default path + CLUSTER_STORAGE_BACKEND. + * + * Example: define( 'CLUSTER_STORAGE_GATEWAY_PATH', 'extension/ezoracle/clusterfilehandlers/gateway/dfs.php' ); + */ +// define( 'CLUSTER_STORAGE_GATEWAY_PATH', 'extension/name/path/to/gateway.php' ); + +/** + * Cluster storage host. + * Required. + */ +// define( 'CLUSTER_STORAGE_HOST', 'localhost' ); + +/** + * Cluster storage port. + * Optional: the default RDBMS port will be used if set to false + */ +// define( 'CLUSTER_STORAGE_PORT', 3306 ); + +/** + * Cluster storage user + * Required + */ +// define( 'CLUSTER_STORAGE_USER', 'dbuser' ); + +/** + * Cluster storage password + * Required + */ +// define( 'CLUSTER_STORAGE_PASS', 'dbpassword' ); + +/** + * Database name + * Required for most RDBMS + */ +// define( 'CLUSTER_STORAGE_DB', 'ezpcluster' ); + +/** + * Charset to use when communicating with the database. + * Must match the value in file.ini + */ +// define( 'CLUSTER_STORAGE_CHARSET', 'utf8' ); + +/** + * NFS share path. + * Required ONLY for DFS based clusters + */ +// define( 'CLUSTER_MOUNT_POINT_PATH', '/media/nfs' ); + +/** + * Enable persistent database connections, for backends with support (currently: Oracle, with appropriate extension) + * Optional. Defaults to false. + */ +// define( 'CLUSTER_PERSISTENT_CONNECTION', false ); + +/** + * Allow cluster index debugging. + * This MAY reveal internal details, and should not be used in a production environnement. + * Optional. Defaults to false. + */ +// define( 'CLUSTER_ENABLE_DEBUG', true ); + +/** + * Enable HTTP cache features: if-modified-since & eTags + * Optional. Defaults to true. + */ +// define( 'CLUSTER_ENABLE_HTTP_CACHE', false ); + +/** + * Enable HTTP range support (partial HTTP downloads) + * Optional. Defaults to true. + * NOTE: This feature is ONLY available for DFS based cluster handlers. + */ +// define( 'CLUSTER_ENABLE_HTTP_RANGE', true ); + +/** + * Enable usage of "Expires" headers. + * Optional. Defaults to 86400 (one day). + * Possible values: false (disable), or a TTL in seconds. + * Can be set to a VERY high value (315569260 for 10 years) as long as you enable + * ezjscore.ini/[Packer]/AppendLastModifiedTime so that the generation timestamp is appended + * to ezjscore pack files + */ +// define( 'CLUSTER_EXPIRY_TIMEOUT', 86400 ); + +/** + * Enable usage of "X-Powered-By" headers. + * Optional. Defaults: eZ Publish. + * Setting it to false will disable the custom header, but you still need to set expose_php to off + * in the php configuration to get rid of the X-Powered-By header completely. + */ +// define( 'CLUSTER_HEADER_X_POWERED_BY', 'eZ Publish' ); + +/** + * DFS/MySQLi only: custom table name for cache files metadata + * Optional. Defaults: "ezdfsfile_cache" + * If set to an existing mysql table, this table will be used for cache files. + * Storage files will always remain inside ezdfsfile. + */ +// define( 'CLUSTER_METADATA_TABLE_CACHE', 'ezdfsfile_cache' ); + +/** + * DFS/MySQLi only: search string to distinguish cache files and storage files + * Optional. Defaults: "/cache/", "/storage/" + * + * This is an advanced setting. + * Changing it only makes sense if FileSettings.CacheDir or FileSettings.StorageDir have been modified. + */ +// define( 'CLUSTER_METADATA_CACHE_PATH', '/cache/' ); +// define( 'CLUSTER_METADATA_STORAGE_PATH', '/storage/' ); + +/* + LOG HANDLING + ------------ + + Those constants allow to change the max log file size and the number of files + to keep while the logs are rotated for files generated by eZ Publish + (eZDebug) and custom log files (eZLog) +*/ + +/** + * Maximum file size in bytes of eZ Publish generated log, ie + * error.log, warning.log, notice.log and strict.log files + * Default is 200Kb + */ +// define( 'EZPUBLISH_LOG_MAX_FILE_SIZE', 204800 ); + +/** + * Number of files to keep while rotating eZ Publish generated log. + * Set this constant to 0 to disable the built-in log rotation. + */ +// define( 'EZPUBLISH_LOG_ROTATE_FILES', 3 ); + +/** + * Maximum file size in bytes of custom log file generated with eZLog class + */ +// define( 'CUSTOM_LOG_MAX_FILE_SIZE', 204800 ); + +/** + * Number of files to keep while rotating custom log file. + * Set this constant to 0 to disable the built-in log rotation. + */ +// define( 'CUSTOM_LOG_ROTATE_FILES', 3 ); + + +?> diff --git a/src/AppBundle/ezpublish_legacy/app/settings/_skeleton_legacy_admin/site.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/_skeleton_legacy_admin/site.ini.append.php new file mode 100644 index 0000000..5fb80a8 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/_skeleton_legacy_admin/site.ini.append.php @@ -0,0 +1,34 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/_skeleton_ngadminui/site.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/_skeleton_ngadminui/site.ini.append.php new file mode 100644 index 0000000..2f9bf3c --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/_skeleton_ngadminui/site.ini.append.php @@ -0,0 +1,36 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/design.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/design.ini.append.php new file mode 100644 index 0000000..b079ff7 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/design.ini.append.php @@ -0,0 +1,5 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/image.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/image.ini.append.php new file mode 100644 index 0000000..ff82982 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/image.ini.append.php @@ -0,0 +1,12 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/site.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/site.ini.append.php new file mode 100644 index 0000000..7c0463f --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/site.ini.append.php @@ -0,0 +1,8 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/content.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/content.ini.append.php new file mode 120000 index 0000000..c630074 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/content.ini.append.php @@ -0,0 +1 @@ +../ngadminui/content.ini.append.php \ No newline at end of file diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/contentstructuremenu.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/contentstructuremenu.ini.append.php new file mode 120000 index 0000000..b6ced8d --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/contentstructuremenu.ini.append.php @@ -0,0 +1 @@ +../ngadminui/contentstructuremenu.ini.append.php \ No newline at end of file diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/dashboard.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/dashboard.ini.append.php new file mode 120000 index 0000000..f7f02ec --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/dashboard.ini.append.php @@ -0,0 +1 @@ +../ngadminui/dashboard.ini.append.php \ No newline at end of file diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/design.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/design.ini.append.php new file mode 120000 index 0000000..ea0efe8 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/design.ini.append.php @@ -0,0 +1 @@ +../ngadminui/design.ini.append.php \ No newline at end of file diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/image.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/image.ini.append.php new file mode 120000 index 0000000..d920a80 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/image.ini.append.php @@ -0,0 +1 @@ +../ngadminui/image.ini.append.php \ No newline at end of file diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/override.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/override.ini.append.php new file mode 120000 index 0000000..03c42d6 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/override.ini.append.php @@ -0,0 +1 @@ +../ngadminui/override.ini.append.php \ No newline at end of file diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/site.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/site.ini.append.php new file mode 100644 index 0000000..735c3da --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/site.ini.append.php @@ -0,0 +1,32 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/toolbar.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/toolbar.ini.append.php new file mode 120000 index 0000000..4a6e13c --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/legacy_admin/toolbar.ini.append.php @@ -0,0 +1 @@ +../ngadminui/toolbar.ini.append.php \ No newline at end of file diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/content.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/content.ini.append.php new file mode 100644 index 0000000..1ae394a --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/content.ini.append.php @@ -0,0 +1,13 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/contentstructuremenu.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/contentstructuremenu.ini.append.php new file mode 100644 index 0000000..8829d6f --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/contentstructuremenu.ini.append.php @@ -0,0 +1,14 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/dashboard.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/dashboard.ini.append.php new file mode 100644 index 0000000..19fb7ab --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/dashboard.ini.append.php @@ -0,0 +1,9 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/design.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/design.ini.append.php new file mode 100644 index 0000000..ac5d46e --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/design.ini.append.php @@ -0,0 +1,5 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/image.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/image.ini.append.php new file mode 100644 index 0000000..0b0e307 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/image.ini.append.php @@ -0,0 +1,23 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/override.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/override.ini.append.php new file mode 100644 index 0000000..8b6be35 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/override.ini.append.php @@ -0,0 +1,38 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/site.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/site.ini.append.php new file mode 100644 index 0000000..74b9092 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/site.ini.append.php @@ -0,0 +1,34 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/toolbar.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/toolbar.ini.append.php new file mode 100644 index 0000000..fe43ce1 --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/siteaccess/ngadminui/toolbar.ini.append.php @@ -0,0 +1,26 @@ + diff --git a/src/AppBundle/ezpublish_legacy/app/settings/transform.ini.append.php b/src/AppBundle/ezpublish_legacy/app/settings/transform.ini.append.php new file mode 100644 index 0000000..6dac30f --- /dev/null +++ b/src/AppBundle/ezpublish_legacy/app/settings/transform.ini.append.php @@ -0,0 +1,17 @@ + diff --git a/var/cache/.gitkeep b/var/cache/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/var/encore/.gitkeep b/var/encore/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/var/logs/.gitkeep b/var/logs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/var/sessions/.gitkeep b/var/sessions/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/web/app.php b/web/app.php new file mode 100644 index 0000000..bc0d354 --- /dev/null +++ b/web/app.php @@ -0,0 +1,66 @@ +server->get('REMOTE_ADDR')], Request::HEADER_X_FORWARDED_ALL); + } else { + Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL); + } +} + +$response = $kernel->handle($request); +$response->send(); +$kernel->terminate($request, $response); diff --git a/web/app_dev.php b/web/app_dev.php new file mode 100644 index 0000000..80b5241 --- /dev/null +++ b/web/app_dev.php @@ -0,0 +1,22 @@ + { + options.includePaths = [path.resolve(__dirname, 'node_modules')]; // eslint-disable-line no-param-reassign + options.outputStyle = Encore.isProduction() ? 'compressed' : 'nested'; + }) + + // allow legacy applications to use $/jQuery as a global variable + // .autoProvidejQuery() + + .enableSourceMaps(!Encore.isProduction()) + + // empty the outputPath dir before each build + .cleanupOutputBeforeBuild() + + // create hashed filenames (e.g. app.css?v=abc123) + .enableVersioning(Encore.isProduction()) + + .enablePostCssLoader((options) => { + options.config = { // eslint-disable-line no-param-reassign + path: 'postcss.config.js', + }; + }) + + .configureTerserPlugin((options) => { + options.cache = true; + options.parallel = true; + options.terserOptions = { + output: { + comments: false, + }, + }; + }) + + .enableSingleRuntimeChunk() +; + +if (Encore.isProduction()) { + Encore.configureFilenames({ + js: '[name].js?v=[contenthash]', + css: '[name].css?v=[contenthash]', + images: 'images/[name].[ext]?v=[hash:8]', + fonts: 'fonts/[name].[ext]?v=[hash:8]', + }); +} + +const config = Encore.getWebpackConfig(); + +config.watchOptions = { poll: true, ignored: /node_modules/ }; +config.name = siteConfig.name; + +if (config.devServer) { + config.devServer.disableHostCheck = true; +} + +// export the final configuration +module.exports = config; diff --git a/webpack.config.ezplatform.js b/webpack.config.ezplatform.js new file mode 100644 index 0000000..22c5196 --- /dev/null +++ b/webpack.config.ezplatform.js @@ -0,0 +1,22 @@ +const Encore = require('@symfony/webpack-encore'); +const path = require('path'); +const getEzConfig = require('./ez.webpack.config.js'); +const eZConfigManager = require('./ez.webpack.config.manager.js'); +const eZConfig = getEzConfig(Encore); +const customConfigs = require('./ez.webpack.custom.configs.js'); + +Encore.reset(); +Encore.setOutputPath('web/assets/build') + .setPublicPath('/assets/build') + .enableSassLoader() + .enableReactPreset() + .enableSingleRuntimeChunk(); + +// Put your config here. + +// uncomment the two lines below, if you added a new entry (by Encore.addEntry() or Encore.addStyleEntry() method) to your own Encore configuration for your project +// const projectConfig = Encore.getWebpackConfig(); +// module.exports = [ eZConfig, ...customConfigs, projectConfig ]; + +// comment-out this line if you've uncommented the above lines +module.exports = [ eZConfig, ...customConfigs ]; diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..138af01 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,9 @@ +// webpack.config.js +const config = require('./webpack.config.default'); + +// for multiple webpack configurations, create another webpack config file and require it here +// const anotherConfig = require('./webpack.config.anotherConfig'); + +// export the final configuration +// for multiple webpack configurations, add imported configuration to export array eg. module.exports = [config, anotherConfig]; +module.exports = [config];