diff --git a/.dockerignore b/.dockerignore index 9b914fafec..95d7045edf 100644 --- a/.dockerignore +++ b/.dockerignore @@ -23,7 +23,7 @@ /datas /docker-compose.* /logs -/nodes_modules +/node_modules /plugins /tmp /vendor diff --git a/.env b/.env index 2fb773529c..75c614e5d6 100644 --- a/.env +++ b/.env @@ -1,3 +1,4 @@ +PHRASEANET_PROJECT_NAME=Phraseanet # Registry from where you pull Docker images PHRASEANET_DOCKER_REGISTRY=local # Tag of the Docker images @@ -70,3 +71,10 @@ PHRASEANET_DB_DIR=./volumes/db PHRASEANET_ELASTICSEARCH_DIR=./volumes/elasticsearch PHRASEANET_THUMBNAILS_DIR=./www/thumbnails PHRASEANET_TMP_DIR=./tmp + +# For dev who don't have SSH_AUTH_SOCK (avoid an empty volume name) +SSH_AUTH_SOCK=/dev/null + +# Plugin support +PHRASEANET_PLUGINS= +PHRASEANET_SSH_PRIVATE_KEY= diff --git a/Dockerfile b/Dockerfile index e900d1aea4..3feefd2d3b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -82,8 +82,19 @@ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \ && apt-get install -y --no-install-recommends \ nodejs \ yarn \ + nano \ + vim \ + iputils-ping \ + zsh \ + ssh \ + telnet \ + autoconf \ + libtool \ + python \ + pkg-config \ && apt-get clean \ && rm -rf /var/lib/apt/lists \ + && git clone https://github.com/robbyrussell/oh-my-zsh.git /bootstrap/.oh-my-zsh \ && mkdir -p /var/alchemy/Phraseanet \ && chown -R app:app /var/alchemy @@ -99,10 +110,28 @@ RUN composer install --prefer-dist --no-dev --no-progress --no-suggest --classma COPY --chown=app . . -RUN rm -rf docker/phraseanet/root \ - && make install +RUN make install -ADD docker/phraseanet/ / +ADD ./docker/builder/root / + +# SSH Private repo +ARG SSH_PRIVATE_KEY +ARG PHRASEANET_PLUGINS + +RUN ( \ + test ! -z "${SSH_PRIVATE_KEY}" \ + && mkdir -p ~/.ssh \ + && echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa \ + # make sure github domain.com is accepted + && ssh-keyscan -H github.com >> ~/.ssh/known_hosts \ + && chmod 600 ~/.ssh/id_rsa \ + ) || echo "Skip SSH key" + +RUN ./docker/phraseanet/plugins/console install + +ENTRYPOINT ["/bootstrap/entrypoint.sh"] + +CMD [] ######################################################################### # Phraseanet web application image diff --git a/README.md b/README.md index 4d9509d731..f394ace118 100644 --- a/README.md +++ b/README.md @@ -56,10 +56,17 @@ export PHRASEANET_APP_PORT=8082 It may be easier to deal with a local file to manage our env variables. -You can add your `env.local` at the root of this project and define a command alias in your `~/.bashrc`: +You can add your `env.local` at the root of this project and define a command function in your `~/.bashrc`: ```bash -alias dc="env $(cat env.local | grep -v '#' | tr '\n' ' ') docker-compose" +# ~/.bashrc or ~/.zshrc +function dc() { + if [ -f env.local ]; then + env $(cat env.local | grep -v '#' | tr '\n' ' ') docker-compose $@ + else + docker-compose $@ + fi +} ``` ### Running the application @@ -105,6 +112,20 @@ This can be made easily from the builder container: > Please note that the phraseanet image does not contain nor `composer` neither `node` tools. This allow the final image to be slim. > If you need to use dev tools, ensure you are running the `builder` image! +### Developer shell + +You can also obtain a shell access in builder container: + +```bash +docker-compose run --rm builder /bin/bash +# or +docker-compose run --rm builder /bin/zsh +``` + +In this container you will have the same libraries (PHP, Node, composer, ...) that are used to build images. +Also you have utils for development like telnet, ping, ssh, git, ... +Your $HOME/.ssh directory is also mounted to builder's home with your ssh agent. + ### Using Xdebug Xdebug is enabled by default with the `docker-compose.override.yml` @@ -132,6 +153,28 @@ XDEBUG_REMOTE_HOST=host.docker.internal > Don't forget to recreate your container (`docker-compose up -d phraseanet`) +### Build images with plugins + +Plugins can be installed during build if you set the `PHRASEANET_PLUGINS` env var as follows: + +```bash +PHRASEANET_PLUGINS="git@github.com:alchemy-fr/Phraseanet-plugin-webgallery.git" + +# You can optionally precise the branch to install +# If not precised, the main branch will be pulled +PHRASEANET_PLUGINS="git@github.com:alchemy-fr/Phraseanet-plugin-webgallery.git(custom-branch)" + +# Plugins are separated by spaces +PHRASEANET_PLUGINS="git@github.com:foo/bar.git(branch-1) git@github.com:baz/42.git" +``` + +If you install private plugins, make sure you export your SSH private key content in order to allow docker build to access the GIT repository: +```bash +export PHRASEANET_SSH_PRIVATE_KEY=$(cat ~/.ssh/id_rsa) +# or if your private key is protected by a passphrase: +export PHRASEANET_SSH_PRIVATE_KEY=$(openssl rsa -in ~/.ssh/id_rsa -out /tmp/id_rsa_raw && cat /tmp/id_rsa_raw && rm /tmp/id_rsa_raw) +``` + # With Vagrant (deprecated) ## Development : diff --git a/docker-compose.override.yml b/docker-compose.override.yml index c9b846aa84..7e2b3dd2b8 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -10,25 +10,34 @@ services: gateway: volumes: + - ../:/var/alchemy - .:/var/alchemy/Phraseanet - ./docker/nginx/root/entrypoint.sh:/entrypoint.sh - ${PHRASEANET_DATA_DIR}:/var/alchemy/Phraseanet/datas:rw - ${PHRASEANET_THUMBNAILS_DIR}:/var/alchemy/Phraseanet/www/thumbnails:rw - ${PHRASEANET_TMP_DIR}:/var/alchemy/Phraseanet/tmp:rw - - builder: build: context: . target: builder - command: exit 0 + args: + - SSH_PRIVATE_KEY=${PHRASEANET_SSH_PRIVATE_KEY} + - PHRASEANET_PLUGINS=${PHRASEANET_PLUGINS} + stdin_open: true + tty: true volumes: + - ../:/var/alchemy - .:/var/alchemy/Phraseanet - ${PHRASEANET_CONFIG_DIR}:/var/alchemy/Phraseanet/config:rw - ${PHRASEANET_LOGS_DIR}:/var/alchemy/Phraseanet/logs:rw - ${PHRASEANET_DATA_DIR}:/var/alchemy/Phraseanet/datas:rw - ${PHRASEANET_THUMBNAILS_DIR}:/var/alchemy/Phraseanet/www/thumbnails:rw + - ${SSH_AUTH_SOCK}:/ssh-auth-sock + - ${HOME}/.ssh:/home/app/.ssh + - dev_vol:/home/app + environment: + - PHRASEANET_PROJECT_NAME phraseanet: environment: @@ -36,6 +45,7 @@ services: - XDEBUG_CONFIG=remote_host=${XDEBUG_REMOTE_HOST} idekey=${IDE_KEY} remote_enable=1 profiler_enable=${XDEBUG_PROFILER_ENABLED} profiler_output_dir=/var/alchemy/Phraseanet/cache/profiler - PHP_IDE_CONFIG volumes: + - ../:/var/alchemy - .:/var/alchemy/Phraseanet - ${PHRASEANET_CONFIG_DIR}:/var/alchemy/Phraseanet/config:rw - ${PHRASEANET_LOGS_DIR}:/var/alchemy/Phraseanet/logs:rw @@ -45,6 +55,7 @@ services: worker: volumes: + - ../:/var/alchemy - .:/var/alchemy/Phraseanet - ${PHRASEANET_CONFIG_DIR}:/var/alchemy/Phraseanet/config:rw - ${PHRASEANET_LOGS_DIR}:/var/alchemy/Phraseanet/logs:rw @@ -72,8 +83,17 @@ services: volumes: - ${PHRASEANET_ELASTICSEARCH_DIR}:/usr/share/elasticsearch/data:rw + kibana: + image: kibana:4.6.6 + ports: + - 5601:5601 + networks: default: ipam: config: - subnet: $PHRASEANET_SUBNET_IPS + +volumes: + dev_vol: + driver: local diff --git a/docker-compose.yml b/docker-compose.yml index 4c6f435ee7..e0bd547fbb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,9 @@ services: build: context: . target: phraseanet-nginx + args: + - SSH_PRIVATE_KEY=${PHRASEANET_SSH_PRIVATE_KEY} + - PHRASEANET_PLUGINS=${PHRASEANET_PLUGINS} image: $PHRASEANET_DOCKER_REGISTRY/phraseanet-nginx:$PHRASEANET_DOCKER_TAG restart: on-failure volumes: @@ -21,6 +24,9 @@ services: build: context: . target: phraseanet-fpm + args: + - SSH_PRIVATE_KEY=${PHRASEANET_SSH_PRIVATE_KEY} + - PHRASEANET_PLUGINS=${PHRASEANET_PLUGINS} image: $PHRASEANET_DOCKER_REGISTRY/phraseanet-fpm:$PHRASEANET_DOCKER_TAG restart: on-failure depends_on: @@ -29,6 +35,7 @@ services: - rabbitmq - elasticsearch environment: + - PHRASEANET_PROJECT_NAME - MAX_BODY_SIZE - MAX_INPUT_VARS - OPCACHE_ENABLED @@ -57,6 +64,9 @@ services: build: context: . target: phraseanet-worker + args: + - SSH_PRIVATE_KEY=${PHRASEANET_SSH_PRIVATE_KEY} + - PHRASEANET_PLUGINS=${PHRASEANET_PLUGINS} image: $PHRASEANET_DOCKER_REGISTRY/phraseanet-worker:$PHRASEANET_DOCKER_TAG restart: on-failure depends_on: @@ -65,6 +75,7 @@ services: - rabbitmq - elasticsearch environment: + - PHRASEANET_PROJECT_NAME - MAX_BODY_SIZE - MAX_INPUT_VARS - OPCACHE_ENABLED diff --git a/docker/builder/root/bootstrap/.oh-my-zsh/themes/alchemy.zsh-theme b/docker/builder/root/bootstrap/.oh-my-zsh/themes/alchemy.zsh-theme new file mode 100644 index 0000000000..807e8b6ef7 --- /dev/null +++ b/docker/builder/root/bootstrap/.oh-my-zsh/themes/alchemy.zsh-theme @@ -0,0 +1,7 @@ +local ret_status="%(?:%{$fg_bold[green]%}➜ :%{$fg_bold[red]%}➜ %s)" +PROMPT='%* %{$fg_bold[green]%}%n%{$fg[grey]%}@%m%{$fg_bold[green]%}%u ${ret_status}%{$fg_bold[green]%}%p %{$fg[cyan]%}%c %{$fg_bold[blue]%}$(git_prompt_info)%{$fg_bold[blue]%} % %{$reset_color%}' + +ZSH_THEME_GIT_PROMPT_PREFIX="[%{$fg[red]%}" +ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%}" +ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}] %{$fg[yellow]%}✗%{$reset_color%}" +ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg[blue]%}]" diff --git a/docker/builder/root/bootstrap/.zshrc b/docker/builder/root/bootstrap/.zshrc new file mode 100644 index 0000000000..ae18e5a4ef --- /dev/null +++ b/docker/builder/root/bootstrap/.zshrc @@ -0,0 +1,56 @@ +export LC_ALL=en_US.UTF-8 +export LANG=en_US.UTF-8 + +export ZSH=$HOME/.oh-my-zsh + +ZSH_THEME="alchemy" + +# Uncomment the following line to use case-sensitive completion. +# CASE_SENSITIVE="true" + +# Uncomment the following line to use hyphen-insensitive completion. Case +# sensitive completion must be off. _ and - will be interchangeable. +# HYPHEN_INSENSITIVE="true" + +# Uncomment the following line to disable bi-weekly auto-update checks. +# DISABLE_AUTO_UPDATE="true" + +# Uncomment the following line to change how often to auto-update (in days). +# export UPDATE_ZSH_DAYS=13 + +# Uncomment the following line to disable colors in ls. +# DISABLE_LS_COLORS="true" + +# Uncomment the following line to disable auto-setting terminal title. +# DISABLE_AUTO_TITLE="true" + +# Uncomment the following line to enable command auto-correction. +# ENABLE_CORRECTION="true" + +# Uncomment the following line to display red dots whilst waiting for completion. +# COMPLETION_WAITING_DOTS="true" + +# Uncomment the following line if you want to disable marking untracked files +# under VCS as dirty. This makes repository status check for large repositories +# much, much faster. +# DISABLE_UNTRACKED_FILES_DIRTY="true" + +# Uncomment the following line if you want to change the command execution time +# stamp shown in the history command output. +# The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" +# HIST_STAMPS="mm/dd/yyyy" + +# Would you like to use another custom folder than $ZSH/custom? +# ZSH_CUSTOM=/path/to/new-custom-folder + +# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) +# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ +# Example format: plugins=(rails git textmate ruby lighthouse) +# Add wisely, as too many plugins slow down shell startup. +plugins=(git symfony2) + +# User configuration + +source $ZSH/oh-my-zsh.sh + +alias ll='ls -alFh' diff --git a/docker/builder/root/bootstrap/entrypoint.d/ohmyzsh.sh b/docker/builder/root/bootstrap/entrypoint.d/ohmyzsh.sh new file mode 100644 index 0000000000..aded04c7c7 --- /dev/null +++ b/docker/builder/root/bootstrap/entrypoint.d/ohmyzsh.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +if [ ! -d "$HOME/.oh-my-zsh" ]; then + cp -r "/bootstrap/.oh-my-zsh" "$HOME/.oh-my-zsh" +fi diff --git a/docker/builder/root/bootstrap/entrypoint.d/zshrc.sh b/docker/builder/root/bootstrap/entrypoint.d/zshrc.sh new file mode 100644 index 0000000000..71d47ed475 --- /dev/null +++ b/docker/builder/root/bootstrap/entrypoint.d/zshrc.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +ZSH_FILE="$HOME/.zshrc" + +if [ ! -f "$HOME/.zshrc" ]; then + cp "/bootstrap/.zshrc" "$HOME/.zshrc" +fi diff --git a/docker/builder/root/bootstrap/entrypoint.sh b/docker/builder/root/bootstrap/entrypoint.sh new file mode 100755 index 0000000000..c8bff0d1bb --- /dev/null +++ b/docker/builder/root/bootstrap/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -d /bootstrap/entrypoint.d ]; then + for i in /bootstrap/entrypoint.d/*.sh; do + if [ -r $i ]; then + . $i + fi + done + unset i +fi + +if [ ! -t 1 ] ; then + echo "No tty available." + exit 0 +fi + +exec "$@" diff --git a/docker/phraseanet/entrypoint.sh b/docker/phraseanet/entrypoint.sh index 1d1fecb989..037fe0aa02 100755 --- a/docker/phraseanet/entrypoint.sh +++ b/docker/phraseanet/entrypoint.sh @@ -26,4 +26,6 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then docker-php-ext-enable xdebug fi +./docker/phraseanet/plugins/console init + bash -e docker-php-entrypoint $@ diff --git a/docker/phraseanet/php.ini.sample b/docker/phraseanet/php.ini.sample index 774389b614..7f5fc97430 100644 --- a/docker/phraseanet/php.ini.sample +++ b/docker/phraseanet/php.ini.sample @@ -935,7 +935,7 @@ cli_server.color = On [Date] ; Defines the default timezone used by the date functions ; http://php.net/date.timezone -date.timezone = Europe/Paris +date.timezone = UTC ; http://php.net/date.default-latitude ;date.default_latitude = 31.7667 diff --git a/docker/phraseanet/plugins/InitCommand.php b/docker/phraseanet/plugins/InitCommand.php new file mode 100644 index 0000000000..23b7d644b7 --- /dev/null +++ b/docker/phraseanet/plugins/InitCommand.php @@ -0,0 +1,29 @@ +setName('init') + ->setDescription('Initialize plugins'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + foreach (glob('./plugins/*') as $dir) { + if (is_dir($dir)) { + $output->writeln(sprintf('Init %s plugin', basename($dir))); + SubCommand::run(sprintf('bin/setup plugin:add %s', $dir)); + } + } + + return 0; + } +} diff --git a/docker/phraseanet/plugins/InstallCommand.php b/docker/phraseanet/plugins/InstallCommand.php new file mode 100644 index 0000000000..7b8a28c4cd --- /dev/null +++ b/docker/phraseanet/plugins/InstallCommand.php @@ -0,0 +1,64 @@ +setName('install') + ->setDescription('Install plugins'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $plugins = trim(getenv('PHRASEANET_PLUGINS')); + if (empty($plugins)) { + $output->writeln('No plugin to install... SKIP'); + + return 0; + } + + $pluginsDir = 'plugins'; + if (!is_dir($pluginsDir)) { + mkdir($pluginsDir); + } + + foreach (explode(' ', $plugins) as $key => $plugin) { + $plugin = trim($plugin); + $repo = $plugin; + $branch = 'master'; + if (1 === preg_match('#^(.+)\(([^)]+)\)$#', $plugin, $matches)) { + $repo = $matches[1]; + $branch = $matches[2]; + } + + $pluginPath = './plugin' . $key; + if (is_dir($pluginPath)) { + SubCommand::run(sprintf('rm -rf %s', $pluginPath)); + } + + $output->writeln(sprintf('Installing %s (branch: %s)', $repo, $branch)); + SubCommand::run(sprintf('git clone --single-branch --branch %s %s %s', $branch, $repo, $pluginPath)); + + $manifestSrc = $pluginPath.'/manifest.json'; + if (!file_exists($manifestSrc)) { + throw new \Exception(sprintf('Cannot install plugin %s: no manifest.json file found', $plugin)); + } + $pluginDestName = json_decode(file_get_contents($manifestSrc), true)['name']; + rename($pluginPath, $pluginsDir.'/'.$pluginDestName); + $pluginPath = $pluginsDir.'/'.$pluginDestName; + + if (file_exists($pluginPath.'/composer.json')) { + SubCommand::run(sprintf('cd %s && composer install --no-dev', $pluginPath)); + } + } + + return 0; + } +} diff --git a/docker/phraseanet/plugins/SubCommand.php b/docker/phraseanet/plugins/SubCommand.php new file mode 100644 index 0000000000..fd2dbc68a1 --- /dev/null +++ b/docker/phraseanet/plugins/SubCommand.php @@ -0,0 +1,26 @@ +add(new InstallCommand()); +$application->add(new InitCommand()); + +$application->run(); diff --git a/docker/phraseanet/worker/entrypoint.sh b/docker/phraseanet/worker/entrypoint.sh index d4d773c829..763a07d8ba 100755 --- a/docker/phraseanet/worker/entrypoint.sh +++ b/docker/phraseanet/worker/entrypoint.sh @@ -15,4 +15,4 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then docker-php-ext-enable xdebug fi -runuser -u app "$@" +runuser -u app -- $@ diff --git a/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php b/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php index 2d9d211612..53e4ffed39 100644 --- a/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php +++ b/lib/Alchemy/Phrasea/Command/Plugin/AbstractPluginCommand.php @@ -15,6 +15,21 @@ use Alchemy\Phrasea\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +function normalizePath($path) { + return array_reduce(explode('/', $path), function ($a, $b) { + if($a === 0) + $a = '/'; + + if($b === '' || $b === '.') + return $a; + + if($b === '..') + return dirname($a); + + return preg_replace('/\/+/', '/', "$a/$b"); + }, 0); +} + abstract class AbstractPluginCommand extends Command { protected function validatePlugins(InputInterface $input, OutputInterface $output) @@ -54,33 +69,42 @@ abstract class AbstractPluginCommand extends Command protected function doInstallPlugin($source, InputInterface $input, OutputInterface $output) { - $temporaryDir = $this->container['temporary-filesystem']->createTemporaryDirectory(); - - $output->write("Importing $source..."); - $this->container['plugins.importer']->import($source, $temporaryDir); - $output->writeln(" OK"); - $output->write("Validating plugin..."); - $manifest = $this->container['plugins.plugins-validator']->validatePlugin($temporaryDir); + $manifest = $this->container['plugins.plugins-validator']->validatePlugin($source); $output->writeln(" OK found ".$manifest->getName().""); $targetDir = $this->container['plugin.path'] . DIRECTORY_SEPARATOR . $manifest->getName(); + if (normalizePath($targetDir) !== normalizePath($source)) { + $temporaryDir = $this->container['temporary-filesystem']->createTemporaryDirectory(); + $output->write("Importing $source..."); + $this->container['plugins.importer']->import($source, $temporaryDir); + $output->writeln(" OK"); + $workingDir = $temporaryDir; + } else { + $workingDir = $targetDir; + } - $output->write("Setting up composer..."); - $this->container['plugins.composer-installer']->install($temporaryDir); - $output->writeln(" OK"); + if (!is_dir($workingDir.'/vendor')) { + $output->write("Setting up composer..."); + $this->container['plugins.composer-installer']->install($workingDir); + $output->writeln(" OK"); + } $output->write("Installing plugin ".$manifest->getName()."..."); - $this->container['filesystem']->mirror($temporaryDir, $targetDir); + if (isset($temporaryDir)) { + $this->container['filesystem']->mirror($temporaryDir, $targetDir); + } $output->writeln(" OK"); $output->write("Copying public files ".$manifest->getName()."..."); $this->container['plugins.assets-manager']->update($manifest); $output->writeln(" OK"); - $output->write("Removing temporary directory..."); - $this->container['filesystem']->remove($temporaryDir); - $output->writeln(" OK"); + if (isset($temporaryDir)) { + $output->write("Removing temporary directory..."); + $this->container['filesystem']->remove($temporaryDir); + $output->writeln(" OK"); + } $output->write("Activating plugin..."); $this->container['conf']->set(['plugins', $manifest->getName(), 'enabled'], true); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php index 6e650aefaa..c9726d5faf 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/PushController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/PushController.php @@ -98,7 +98,7 @@ class PushController extends Controller $Basket->setUser($user_receiver); $Basket->setPusher($this->getAuthenticatedUser()); $Basket->markUnread(); - + $manager->persist($Basket); foreach ($pusher->get_elements() as $element) { @@ -600,6 +600,38 @@ class PushController extends Controller ); } + public function updateExpirationAction(Request $request) + { + $ret = [ + 'success' => false, + 'message' => $this->app->trans('Unable to save the expiration date') + ]; + if (is_null($request->request->get('date'))) { + $ret['message'] = $this->app->trans('The provided date is null!'); + return $this->app->json($ret); + } + $repository = $this->app['repo.baskets']; + $manager = $this->getEntityManager(); + $manager->beginTransaction(); + try { + $basket = $repository->findUserBasket($request->request->get('basket_id'), $this->app->getAuthenticatedUser(), true); + $date = new \DateTime($request->request->get('date') . " 23:59:59"); + $validation = $basket->getValidation(); + if (is_null($validation)) { + return $this->app->json($ret); + } + $validation->setExpires($date); + $manager->persist($validation); + $manager->flush(); + $manager->commit(); + $ret['message'] = $this->app->trans('Expiration date successfully updated!'); + } catch (\Exception $e) { + $ret['message'] = $e->getMessage(); + $manager->rollback(); + } + return $this->app->json($ret); + } + private function formatUser(User $user) { $subtitle = array_filter([$user->getJob(), $user->getCompany()]); @@ -734,4 +766,5 @@ class PushController extends Controller { return $this->app['random.medium']; } + } diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php index 48352e1e39..40b93220c0 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php @@ -59,6 +59,9 @@ class Push implements ControllerProviderInterface, ServiceProviderInterface $controllers->post('/validate/', 'controller.prod.push:validateAction') ->bind('prod_push_validate'); + $controllers->post('/update-expiration/', 'controller.prod.push:updateExpirationAction') + ->bind('prod_push_do_update_expiration'); + $controllers->get('/user/{usr_id}/', 'controller.prod.push:getUserAction') ->assert('usr_id', '\d+'); diff --git a/lib/classes/phraseadate.php b/lib/classes/phraseadate.php index 6acca8b75f..a9732e7822 100644 --- a/lib/classes/phraseadate.php +++ b/lib/classes/phraseadate.php @@ -120,6 +120,16 @@ class phraseadate } } + public function getTranslatedDate(DateTime $date = null) + { + $fmt = new IntlDateFormatter( + $this->app['locale'] ?: 'en', + NULL, NULL, NULL, NULL, 'dd MMMM yyyy' + ); + + return $fmt->format($date); + } + /** * * @param DateTime $date diff --git a/resources/locales/messages.de.xlf b/resources/locales/messages.de.xlf index 9ca23ed2d7..8972dae59c 100644 --- a/resources/locales/messages.de.xlf +++ b/resources/locales/messages.de.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. @@ -192,8 +192,9 @@ %nb_records% records %nb_records% Datensätze + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1689,7 +1690,7 @@ Certaines donnees du panier ont change Einige Daten des Sammelkorbs wurden verändert - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3165,6 +3166,11 @@ Einstellungen von ausführbaren Programme Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Exportieren @@ -6685,6 +6691,11 @@ Die folgende Fehler wurden festgestellt user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped Veröffentlichung wurde gestoppt @@ -7046,6 +7057,11 @@ Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Es ist nicht möglich Dokumente zu senden @@ -11718,7 +11734,13 @@ prod:workzone:basket:creation-date prod:workzone:basket:creation-date - prod/Tooltip/Basket.html.twig + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11826,7 +11848,7 @@ Aktualisieren prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13397,128 +13419,134 @@ workzone:datepicker:april workzone:datepicker:april - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:august workzone:datepicker:august - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:closeText workzone:datepicker:closeText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:currentText workzone:datepicker:currentText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:december workzone:datepicker:december - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:february workzone:datepicker:february - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:friday workzone:datepicker:friday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:january workzone:datepicker:january - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:july workzone:datepicker:july - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:june workzone:datepicker:june - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:march workzone:datepicker:march - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:may workzone:datepicker:may - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:monday workzone:datepicker:monday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:nextText workzone:datepicker:nextText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:november workzone:datepicker:november - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:october workzone:datepicker:october - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:prevText workzone:datepicker:prevText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:saturday workzone:datepicker:saturday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:september workzone:datepicker:september - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:sunday workzone:datepicker:sunday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:thursday workzone:datepicker:thursday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:tuesday workzone:datepicker:tuesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:wednesday workzone:datepicker:wednesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - workzone:feedback:expiration - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig workzone:feedback:update workzone:feedback:update - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/messages.en.xlf b/resources/locales/messages.en.xlf index 95c032bf88..4c9560d4e9 100644 --- a/resources/locales/messages.en.xlf +++ b/resources/locales/messages.en.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. @@ -192,8 +192,9 @@ %nb_records% records %nb_records% records + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1690,7 +1691,7 @@ Certaines donnees du panier ont change This basket has been updated - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3168,6 +3169,11 @@ Executables setting Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Export @@ -6688,6 +6694,11 @@ The following errors have been detected user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped The publication has been stopped. @@ -7049,6 +7060,11 @@ Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Unable to send the documents @@ -11723,8 +11739,14 @@ It is possible to place several search areas prod:workzone:basket:creation-date - prod:workzone:basket:creation-date - prod/Tooltip/Basket.html.twig + Creation + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11832,7 +11854,7 @@ It is possible to place several search areas Refresh prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13400,131 +13422,137 @@ It is possible to place several search areas Thumbnail Tools actions/Tools/videoEditor.html.twig - + workzone:datepicker:april - workzone:datepicker:april - prod/WorkZone/Basket.html.twig + April + prod/WorkZone/Basket.html.twig - + workzone:datepicker:august - workzone:datepicker:august - prod/WorkZone/Basket.html.twig + August + prod/WorkZone/Basket.html.twig workzone:datepicker:closeText workzone:datepicker:closeText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:currentText workzone:datepicker:currentText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - + workzone:datepicker:december - workzone:datepicker:december - prod/WorkZone/Basket.html.twig + December + prod/WorkZone/Basket.html.twig - + workzone:datepicker:february - workzone:datepicker:february - prod/WorkZone/Basket.html.twig + February + prod/WorkZone/Basket.html.twig - + workzone:datepicker:friday - workzone:datepicker:friday - prod/WorkZone/Basket.html.twig + Friday + prod/WorkZone/Basket.html.twig - + workzone:datepicker:january - workzone:datepicker:january - prod/WorkZone/Basket.html.twig + January + prod/WorkZone/Basket.html.twig - + workzone:datepicker:july - workzone:datepicker:july - prod/WorkZone/Basket.html.twig + July + prod/WorkZone/Basket.html.twig - + workzone:datepicker:june - workzone:datepicker:june - prod/WorkZone/Basket.html.twig + June + prod/WorkZone/Basket.html.twig - + workzone:datepicker:march - workzone:datepicker:march - prod/WorkZone/Basket.html.twig + March + prod/WorkZone/Basket.html.twig - + workzone:datepicker:may - workzone:datepicker:may - prod/WorkZone/Basket.html.twig + May + prod/WorkZone/Basket.html.twig - + workzone:datepicker:monday - workzone:datepicker:monday - prod/WorkZone/Basket.html.twig + Monday + prod/WorkZone/Basket.html.twig workzone:datepicker:nextText - workzone:datepicker:nextText - prod/WorkZone/Basket.html.twig + Next + prod/WorkZone/Basket.html.twig - + workzone:datepicker:november - workzone:datepicker:november - prod/WorkZone/Basket.html.twig + November + prod/WorkZone/Basket.html.twig - + workzone:datepicker:october - workzone:datepicker:october - prod/WorkZone/Basket.html.twig + October + prod/WorkZone/Basket.html.twig workzone:datepicker:prevText - workzone:datepicker:prevText - prod/WorkZone/Basket.html.twig + Previous + prod/WorkZone/Basket.html.twig - + workzone:datepicker:saturday - workzone:datepicker:saturday - prod/WorkZone/Basket.html.twig + Saturday + prod/WorkZone/Basket.html.twig - + workzone:datepicker:september - workzone:datepicker:september - prod/WorkZone/Basket.html.twig + September + prod/WorkZone/Basket.html.twig - + workzone:datepicker:sunday - workzone:datepicker:sunday - prod/WorkZone/Basket.html.twig + Sunday + prod/WorkZone/Basket.html.twig - + workzone:datepicker:thursday - workzone:datepicker:thursday - prod/WorkZone/Basket.html.twig + Thursday + prod/WorkZone/Basket.html.twig - + workzone:datepicker:tuesday - workzone:datepicker:tuesday - prod/WorkZone/Basket.html.twig + Tuesday + prod/WorkZone/Basket.html.twig - + workzone:datepicker:wednesday - workzone:datepicker:wednesday - prod/WorkZone/Basket.html.twig + Wednesday + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - Feedback open Until - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig workzone:feedback:update - workzone:feedback:update - prod/WorkZone/Basket.html.twig + Update Date + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/messages.fr.xlf b/resources/locales/messages.fr.xlf index 1b43accabe..be1a6c9a97 100644 --- a/resources/locales/messages.fr.xlf +++ b/resources/locales/messages.fr.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. @@ -192,8 +192,9 @@ %nb_records% records %nb_records% enregistrement(s) + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1689,7 +1690,7 @@ Certaines donnees du panier ont change Certaines données du panier ont changé - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3165,6 +3166,11 @@ Paramètres d'exécutables Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Exporter @@ -6687,6 +6693,11 @@ Pour les utilisateurs authentifiés, la demande de validation est également dis Les erreurs suivantes ont été détectées. user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped La publication a été suspendue @@ -7048,6 +7059,11 @@ Pour les utilisateurs authentifiés, la demande de validation est également dis Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Impossible d'envoyer les documents @@ -10058,14 +10074,14 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le Facettes masquées web/prod/index.html.twig - + index::advance_search: order-by-hits - Par occurrences + Par occurrences web/prod/index.html.twig - + index::advance_search: order-by-hits-asc - Par occurrences asc + Par occurrences asc web/prod/index.html.twig @@ -11726,8 +11742,14 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le prod:workzone:basket:creation-date - prod:workzone:basket:creation-date - prod/Tooltip/Basket.html.twig + Date de création + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11835,7 +11857,7 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le Rafraîchir prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13403,131 +13425,137 @@ Si vous recevez cet e-mail sans l'avoir sollicité, merci de l'ignorer ou de le Outils vidéos actions/Tools/videoEditor.html.twig - + workzone:datepicker:april - workzone:datepicker:april - prod/WorkZone/Basket.html.twig + Avril + prod/WorkZone/Basket.html.twig - + workzone:datepicker:august - workzone:datepicker:august - prod/WorkZone/Basket.html.twig + Aout + prod/WorkZone/Basket.html.twig workzone:datepicker:closeText - workzone:datepicker:closeText - prod/WorkZone/Basket.html.twig + Clore + prod/WorkZone/Basket.html.twig workzone:datepicker:currentText - workzone:datepicker:currentText - prod/WorkZone/Basket.html.twig + courant + prod/WorkZone/Basket.html.twig - + workzone:datepicker:december - workzone:datepicker:december - prod/WorkZone/Basket.html.twig + Décembre + prod/WorkZone/Basket.html.twig - + workzone:datepicker:february - workzone:datepicker:february - prod/WorkZone/Basket.html.twig + Février + prod/WorkZone/Basket.html.twig - + workzone:datepicker:friday - workzone:datepicker:friday - prod/WorkZone/Basket.html.twig + Vendredi + prod/WorkZone/Basket.html.twig - + workzone:datepicker:january - workzone:datepicker:january - prod/WorkZone/Basket.html.twig + Janvier + prod/WorkZone/Basket.html.twig - + workzone:datepicker:july - workzone:datepicker:july - prod/WorkZone/Basket.html.twig + Juillet + prod/WorkZone/Basket.html.twig - + workzone:datepicker:june - workzone:datepicker:june - prod/WorkZone/Basket.html.twig + Juin + prod/WorkZone/Basket.html.twig - + workzone:datepicker:march - workzone:datepicker:march - prod/WorkZone/Basket.html.twig + Mars + prod/WorkZone/Basket.html.twig - + workzone:datepicker:may - workzone:datepicker:may - prod/WorkZone/Basket.html.twig + Mai + prod/WorkZone/Basket.html.twig - + workzone:datepicker:monday - workzone:datepicker:monday - prod/WorkZone/Basket.html.twig + Lundi + prod/WorkZone/Basket.html.twig workzone:datepicker:nextText - workzone:datepicker:nextText - prod/WorkZone/Basket.html.twig + Suivant + prod/WorkZone/Basket.html.twig - + workzone:datepicker:november - workzone:datepicker:november - prod/WorkZone/Basket.html.twig + Novembre + prod/WorkZone/Basket.html.twig - + workzone:datepicker:october - workzone:datepicker:october - prod/WorkZone/Basket.html.twig + Octobre + prod/WorkZone/Basket.html.twig workzone:datepicker:prevText - workzone:datepicker:prevText - prod/WorkZone/Basket.html.twig + Précédent + prod/WorkZone/Basket.html.twig - + workzone:datepicker:saturday - workzone:datepicker:saturday - prod/WorkZone/Basket.html.twig + Samedi + prod/WorkZone/Basket.html.twig - + workzone:datepicker:september - workzone:datepicker:september - prod/WorkZone/Basket.html.twig + Septembre + prod/WorkZone/Basket.html.twig - + workzone:datepicker:sunday - workzone:datepicker:sunday - prod/WorkZone/Basket.html.twig + Dimanche + prod/WorkZone/Basket.html.twig - + workzone:datepicker:thursday - workzone:datepicker:thursday - prod/WorkZone/Basket.html.twig + Jeudi + prod/WorkZone/Basket.html.twig - + workzone:datepicker:tuesday - workzone:datepicker:tuesday - prod/WorkZone/Basket.html.twig + Mardi + prod/WorkZone/Basket.html.twig - + workzone:datepicker:wednesday - workzone:datepicker:wednesday - prod/WorkZone/Basket.html.twig + Mercredi + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - Validation ouverte jusqu'au - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig workzone:feedback:update - workzone:feedback:update - prod/WorkZone/Basket.html.twig + Valider + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/messages.nl.xlf b/resources/locales/messages.nl.xlf index c61524de6a..d5fff61be3 100644 --- a/resources/locales/messages.nl.xlf +++ b/resources/locales/messages.nl.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. @@ -196,8 +196,9 @@ %nb_records% records %nb_records% records + prod/WorkZone/Basket.html.twig prod/Tooltip/Story.html.twig - prod/Tooltip/Basket.html.twig + prod/Tooltip/Basket.html.twig %nb_view% vue @@ -1694,7 +1695,7 @@ Certaines donnees du panier ont change Sommige gegevens in het mandje zijn veranderd - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig Certaines donnees du reportage ont change @@ -3175,6 +3176,11 @@ Executables instellingen Form/Configuration/MainConfigurationFormType.php + + Expiration date successfully updated! + Expiration date successfully updated! + Controller/Prod/PushController.php + Export Exporteer @@ -6695,6 +6701,11 @@ De volgende fouten werden opgemerkt user/import/view.html.twig + + The provided date is null! + The provided date is null! + Controller/Prod/PushController.php + The publication has been stopped Het programma is gestopt @@ -7056,6 +7067,11 @@ Controller/Root/LoginController.php Controller/Api/OAuth2Controller.php + + Unable to save the expiration date + Unable to save the expiration date + Controller/Prod/PushController.php + Unable to send the documents Documenten kunnen niet worden verstuurd @@ -11728,7 +11744,13 @@ prod:workzone:basket:creation-date prod:workzone:basket:creation-date - prod/Tooltip/Basket.html.twig + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + prod:workzone:basket:updated-message + prod:workzone:basket:updated-message + prod/WorkZone/Basket.html.twig prod:workzone:facetstab:search_and_facets_sort_options @@ -11836,7 +11858,7 @@ vernieuwen prod/WorkZone/Story.html.twig prod/WorkZone/Macros.html.twig - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig prod/results/feeds.html.twig prod/results/feeds.html.twig @@ -13407,128 +13429,134 @@ workzone:datepicker:april workzone:datepicker:april - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:august workzone:datepicker:august - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:closeText workzone:datepicker:closeText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:currentText workzone:datepicker:currentText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:december workzone:datepicker:december - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:february workzone:datepicker:february - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:friday workzone:datepicker:friday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:january workzone:datepicker:january - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:july workzone:datepicker:july - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:june workzone:datepicker:june - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:march workzone:datepicker:march - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:may workzone:datepicker:may - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:monday workzone:datepicker:monday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:nextText workzone:datepicker:nextText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:november workzone:datepicker:november - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:october workzone:datepicker:october - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:prevText workzone:datepicker:prevText - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:saturday workzone:datepicker:saturday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:september workzone:datepicker:september - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:sunday workzone:datepicker:sunday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:thursday workzone:datepicker:thursday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:tuesday workzone:datepicker:tuesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig workzone:datepicker:wednesday workzone:datepicker:wednesday - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig - - workzone:feedback:expiration - workzone:feedback:expiration - prod/WorkZone/Basket.html.twig - prod/Tooltip/Basket.html.twig + + workzone:feedback:expiration-closed + workzone:feedback:expiration-closed + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig + + + workzone:feedback:expiration-open + workzone:feedback:expiration-open + prod/WorkZone/Basket.html.twig + prod/Tooltip/Basket.html.twig workzone:feedback:update workzone:feedback:update - prod/WorkZone/Basket.html.twig + prod/WorkZone/Basket.html.twig yes diff --git a/resources/locales/validators.de.xlf b/resources/locales/validators.de.xlf index b7398ca514..4797cbcafd 100644 --- a/resources/locales/validators.de.xlf +++ b/resources/locales/validators.de.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/resources/locales/validators.en.xlf b/resources/locales/validators.en.xlf index f8d0a54e1d..398448e7d5 100644 --- a/resources/locales/validators.en.xlf +++ b/resources/locales/validators.en.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/resources/locales/validators.fr.xlf b/resources/locales/validators.fr.xlf index 6f350ddd76..8d7c716ebd 100644 --- a/resources/locales/validators.fr.xlf +++ b/resources/locales/validators.fr.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/resources/locales/validators.nl.xlf b/resources/locales/validators.nl.xlf index 2218c1ff00..0f8bf37ddc 100644 --- a/resources/locales/validators.nl.xlf +++ b/resources/locales/validators.nl.xlf @@ -1,6 +1,6 @@ - +
The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message. diff --git a/templates/web/prod/Tooltip/Basket.html.twig b/templates/web/prod/Tooltip/Basket.html.twig index 9905cbf49c..49eeec04ba 100644 --- a/templates/web/prod/Tooltip/Basket.html.twig +++ b/templates/web/prod/Tooltip/Basket.html.twig @@ -11,7 +11,11 @@ {% if basket.getValidation() %} {% set dateExpired = app['date-formatter'].getPrettyString(basket.getValidation().getExpires()) %} - {{ 'workzone:feedback:expiration' | trans }} : {{ dateExpired }} + {% if date(dateExpired) < date() %} + {{ 'workzone:feedback:expiration-closed' | trans }} : + {% else %} + {{ 'workzone:feedback:expiration-open' | trans }} : + {% endif %} {{ dateExpired }} {% endif %}
diff --git a/templates/web/prod/WorkZone/Basket.html.twig b/templates/web/prod/WorkZone/Basket.html.twig index fb028812d5..9f9995d634 100644 --- a/templates/web/prod/WorkZone/Basket.html.twig +++ b/templates/web/prod/WorkZone/Basket.html.twig @@ -1,4 +1,4 @@ - +
@@ -99,15 +99,21 @@

{% trans with {'%nb_records%' : nb_records} %}%nb_records% records{% endtrans %}
- {% set dateExpired = app['date-formatter'].getPrettyString(basket.getValidation().getExpires()) %} + {% set dateExpired = app['date-formatter'].getTranslatedDate(basket.getValidation().getExpires()) %}
- {{ 'workzone:feedback:expiration' | trans }} : + {% if date(dateExpired) < date() %} + {{ 'workzone:feedback:expiration-closed' | trans }} : + {% else %} + {{ 'workzone:feedback:expiration-open' | trans }} : + {% endif %} +
- - - - + + + +
+

{{ 'prod:workzone:basket:updated-message' | trans }}

{% endif %} @@ -135,7 +141,25 @@ diff --git a/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php b/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php index 523b4c00da..506c4f104a 100644 --- a/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php +++ b/tests/Alchemy/Tests/Phrasea/Command/Plugin/AddPluginTest.php @@ -69,7 +69,7 @@ class AddPluginTest extends PluginCommandTestCase // the plugin is checked when updating config files self::$DI['cli']['plugins.plugins-validator']->expects($this->at(0)) ->method('validatePlugin') - ->with('tempdir') + ->with('TestPlugin') ->will($this->returnValue($manifest)); self::$DI['cli']['plugins.plugins-validator']->expects($this->at(1)) diff --git a/yarn.lock b/yarn.lock index 4af2ac395c..319e85d277 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5305,10 +5305,14 @@ jquery-simplecolorpicker@^0.3.1: resolved "https://registry.yarnpkg.com/jquery-simplecolorpicker/-/jquery-simplecolorpicker-0.3.1.tgz#4f6befd380ab05470f585d5482e5180556e460eb" integrity sha1-T2vv04CrBUcPWF1UguUYBVbkYOs= -"jquery-treeview@git+https://github.com/alchemy-fr/jquery-treeview.git", "jquery-treeview@git+https://github.com/alchemy-fr/jquery-treeview.git#1e9e5a49d2875b878801e904cd08c2d25e85af1e": +"jquery-treeview@git+https://github.com/alchemy-fr/jquery-treeview.git#1e9e5a49d2875b878801e904cd08c2d25e85af1e": + version "1.4.2" + resolved "git+https://github.com/alchemy-fr/jquery-treeview.git#1e9e5a49d2875b878801e904cd08c2d25e85af1e" + +"jquery-treeview@https://github.com/alchemy-fr/jquery-treeview.git": version "1.4.2" uid "1e9e5a49d2875b878801e904cd08c2d25e85af1e" - resolved "git+https://github.com/alchemy-fr/jquery-treeview.git#1e9e5a49d2875b878801e904cd08c2d25e85af1e" + resolved "https://github.com/alchemy-fr/jquery-treeview.git#1e9e5a49d2875b878801e904cd08c2d25e85af1e" jquery-ui-datepicker-with-i18n@^1.10.4: version "1.10.4"