Merge branch 'PHRAS-3078-Prod_redirect_end_session' of https://github.com/alchemy-fr/Phraseanet into PHRAS-3078-Prod_redirect_end_session
20
.env
@@ -2,7 +2,7 @@ PHRASEANET_PROJECT_NAME=Phraseanet
|
||||
# Registry from where you pull Docker images
|
||||
PHRASEANET_DOCKER_REGISTRY=local
|
||||
# Tag of the Docker images
|
||||
PHRASEANET_DOCKER_TAG=latest
|
||||
PHRASEANET_DOCKER_TAG=4.1.1
|
||||
# APPLICATION PORT
|
||||
PHRASEANET_APP_PORT=8082
|
||||
# RabbitMQ configuration
|
||||
@@ -13,6 +13,8 @@ RABBITMQ_MANAGEMENT_PORT=10811
|
||||
MYSQL_ROOT_PASSWORD=root
|
||||
SERVER_NAME=phraseanet-docker
|
||||
|
||||
# --------------- GATEWAY TIMEOUT -----------------------
|
||||
GATEWAY_SEND_TIMEOUT=120
|
||||
|
||||
# --------------- PHP CONFIGURATION --------------------
|
||||
|
||||
@@ -21,6 +23,9 @@ MAX_BODY_SIZE=2G
|
||||
# Max input var
|
||||
MAX_INPUT_VARS=12000
|
||||
|
||||
MAX_EXECUTION_TIME=120
|
||||
MAX_INPUT_TIME=60
|
||||
|
||||
# Enable opcache ? (0/1)
|
||||
OPCACHE_ENABLED=1
|
||||
# session cache limiter (off/on)
|
||||
@@ -34,6 +39,8 @@ PHP_LOG_LEVEL=warning
|
||||
# These variables are used in the configuration.yml .
|
||||
|
||||
# set here the first user / email couple
|
||||
#set to id of Phraseanet root account, if you want activate a sync for Phraseanet root account password provide by PHRASEANET_ADMIN_ACCOUNT_PASSWORD env value.
|
||||
PHRASEANET_ADMIN_ACCOUNT_ID=
|
||||
PHRASEANET_ADMIN_ACCOUNT_EMAIL=admin@alchemy.fr
|
||||
PHRASEANET_ADMIN_ACCOUNT_PASSWORD=iJRqXU0MwbyJewQLBbra6IWHsWly
|
||||
# Database parameters
|
||||
@@ -64,6 +71,16 @@ PHRASEANET_SMTP_SECURE_MODE=tls
|
||||
PHRASEANET_SMTP_USER=
|
||||
PHRASEANET_SMTP_PASSWORD=
|
||||
|
||||
# Locale setting
|
||||
|
||||
LC_MESSAGES=C.UTF-8
|
||||
LC_COLLATE=C.UTF-8
|
||||
LC_IDENTIFICATION=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
LC_MEASUREMENT=C.UTF-8
|
||||
LC_CTYPE=C.UTF-8
|
||||
LC_TIME=C.UTF-8
|
||||
LC_NAME=C.UTF-8
|
||||
|
||||
# --- DEV purpose ---
|
||||
|
||||
@@ -86,6 +103,7 @@ PHRASEANET_DB_DIR=./volumes/db
|
||||
PHRASEANET_ELASTICSEARCH_DIR=./volumes/elasticsearch
|
||||
PHRASEANET_THUMBNAILS_DIR=./www/thumbnails
|
||||
PHRASEANET_CUSTOM_DIR=./www/custom
|
||||
PHRASEANET_PLUGINS_DIR=./www/plugins
|
||||
PHRASEANET_TMP_DIR=./tmp
|
||||
PHRASEANET_CACHE_DIR=./cache
|
||||
PHRASEANET_DOWNLOAD_DIR=./datas/download
|
||||
|
160
CHANGELOG.md
@@ -1,5 +1,155 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 4.1.1
|
||||
|
||||
### Change summary
|
||||
|
||||
- Phraseanet now using Docker. Retrieve all official images on DockerHub
|
||||
- Worker manager, a new way for all operations on assets. In the near future, this will replace the current task manager.
|
||||
- Geolocation based on Mapbox (requires an account on Mapbox https://www.mapbox.com).
|
||||
- Video chaptering and subtitling support.
|
||||
- GUI redesign for Push, Feedback, List manager, Lightbox on mobile.
|
||||
|
||||
|
||||
this version is finale version of 4.1.0 published in preview at start of year, a lot of improvement, bugfixes on several elements see summary here
|
||||
|
||||
### New Feature summary
|
||||
|
||||
* [PHRAS-2023] - Refacto Lightbox mobile in 4.1
|
||||
* [PHRAS-2219] - Refacto design Push screen
|
||||
* [PHRAS-2220] - Refacto design Feedback screen
|
||||
* [PHRAS-2221] - Refacto design List manager general screen
|
||||
* [PHRAS-2222] - Refacto design ListManager Advance Mode screen
|
||||
* [PHRAS-2223] - Refacto dev list manager Advance Mode screen
|
||||
* [PHRAS-2541] - Dev-Design-Prod/Publish Screen
|
||||
* [PHRAS-2548] - Phraseanet Docker and Docker Compose
|
||||
* [PHRAS-1226] - Geolocalisation In Phraseanet
|
||||
* [PHRAS-1626] - bin/console databox:mount mount an existing databox
|
||||
* [PHRAS-1628] - bin/console collection:publish
|
||||
* [PHRAS-1630] - bin/console database:unmout
|
||||
* [PHRAS-1631] - bin/console collection:unpublish
|
||||
* [PHRAS-1648] - bin/console user:password
|
||||
* [PHRAS-1659] - bin/console user:create
|
||||
* [PHRAS-1771] - bin/console collection:unpublish
|
||||
* [PHRAS-1773] - bin/console collection:publish
|
||||
* [PHRAS-2518] - Phraseanet worker Read/Write metadata
|
||||
* [PHRAS-2520] - Phraseanet worker send webhook
|
||||
* [PHRAS-2738] - Phraseanet worker populate database
|
||||
* [PHRAS-2435] - Phraseanet Worker Build subdefinition
|
||||
* [PHRAS-2436] - Phraseanet Worker build zip export and send mail
|
||||
* [PHRAS-2636] - Phraseanet Worker fetch assets from external uploader (pull mode)
|
||||
* [PHRAS-2904] - Fullfill field define in geoloc - position field with information return by Geonames
|
||||
* [PHRAS-161] - PROD Add a maps for geolocalisation of media in detailed view
|
||||
* [PHRAS-1935] - View prod/ Video chapter editor
|
||||
* [PHRAS-2997] - Matomo analytic service in Phraseanet
|
||||
* [PHRAS-1890] - Add GS1 databases model to Phraseanet
|
||||
|
||||
|
||||
### Improvement and fix summary
|
||||
|
||||
* [PHRAS-1561] - Prod | Print - Use the label of field when print, use the GUI user language
|
||||
* [PHRAS-2067] - Prod : Introduce thumbnail & preview generic images for Fonts records
|
||||
* [PHRAS-2473] - Populate Optimisation, sometime populate databox (database) is very long
|
||||
* [PHRAS-2524] - Put worker log in ELK
|
||||
* [PHRAS-2739] - incorporate Phraseanet-plugin-SubdefWebhook into Phraseanet
|
||||
* [PHRAS-2157] - Prod / Share : Iframe sizes are set to 0 for audio documents
|
||||
* [PHRAS-2538] - Some MP4 file is not correctly detected by Phraseanet.
|
||||
* [PHRAS-2825] - Prod : Add a reset button to initialize searches filters
|
||||
* [PHRAS-1872] - prod/export by email / subject are NOK
|
||||
* [PHRAS-2342] - Report : collections not selected
|
||||
* [PHRAS-2343] - report : all fields of all databases
|
||||
* [PHRAS-2350] - Report : url is too long
|
||||
* [PHRAS-2476] - Bad header in generated video preview file
|
||||
* [PHRAS-2196] - API - Stories records pagination on search answer and Stories fetch info
|
||||
* [PHRAS-2880] - extend admin GUI for define facets ordering.
|
||||
* [PHRAS-2967] - Lightbox - dev of send email report - warn windows
|
||||
* [PHRAS-1752] - update facebook sdk dependency
|
||||
* [PHRAS-2678] - add `webhook monitor`
|
||||
* [PHRAS-2915] - Lightbox (desktop version) Change sort order for basket and Feedback in landing page ( most recent in first)
|
||||
* [PHRAS-2082] - Bump design of windows create user , create template user, create new subdef
|
||||
* [PHRAS-2676] - Weaked download behaviour for large amount of data
|
||||
* [PHRAS-2671] - Change behavior of preview display in audio file case
|
||||
* [PHRAS-2879] - Define facets order in GUI and query result
|
||||
|
||||
## 4.0.12
|
||||
|
||||
Release notes - Phraseanet - Version 4.0.12
|
||||
|
||||
### Improvement
|
||||
* [PHRAS-2955] - Cache doctrine entity metadata for performance
|
||||
* [PHRAS-2964] - Application-box - set host colon of table sbas set to char 255
|
||||
* [PHRAS-3012] - [PHRAS-2977] - Docker compose optimisation, refacto volumes, build image
|
||||
optimisation, add Phraseanet plugin in build image, bump ffmpeg version in worker,
|
||||
fix error un redis configuration.
|
||||
more option for define volumes during installation process.
|
||||
* [PHRAS-3027] - Backport To 4.0 - Populate - Slow query - due to LIMIT in sql query.
|
||||
* [PHRAS-3027] - Translation improvement in EN and DE.
|
||||
|
||||
### Bugfix
|
||||
* [PHRAS-2979] - The content of a story is not displayed even for users with appropriate on the collection
|
||||
|
||||
|
||||
## 4.1.0
|
||||
|
||||
Pre release of 4.1
|
||||
|
||||
|
||||
## 4.0.11
|
||||
|
||||
Release notes - Phraseanet - Version 4.0.11
|
||||
|
||||
### New Feature and Improvement
|
||||
* [PHRAS-2878] - Print feedback report in PDF
|
||||
* [PHRAS-2757] - Exclude some collections from quarantine checkers sha256, UUID, filename (AKA exclude Trash from quarantine)
|
||||
* [PHRAS-2766] - Add status change capabilities to quarantine lazaret in substitute and add action
|
||||
* [PHRAS-2674] - Prod grey skin Improvement
|
||||
* [PHRAS-2775] - Prod - plugin - Publish item in diapo local menu - plugin skeleton improvement.
|
||||
* [PHRAS-925] - Search Engine improvement for word with dot and hyphen characters
|
||||
* [PHRAS-2496] - Pre-build vagrant image for Phraseanet and implement it in Phraseanet vagrant file.
|
||||
* [PHRAS-2637] - Sub definition Task init : select all databases when databases property is not set
|
||||
* [PHRAS-2670] - Fix notifications slow sql and basket select
|
||||
* [PHRAS-2672] - Bump videojs version to 7.5
|
||||
* [PHRAS-2691] - Prod - delete from trash , send deletion by bulk of 3 records
|
||||
* [PHRAS-2700] - Prod - number of results - Formating the results number
|
||||
* [PHRAS-2742] - Enhance plugin-skeleton in 4.0
|
||||
* [PHRAS-2750] - PHPExiftool to handle DJI XMP Tags, Bump exiftool version and switch to original exiftool/exiftool github repository
|
||||
* [PHRAS-835] - ES - date format timestamp unix, store and search datetime
|
||||
* [PHRAS-2791] - Embed-bundle - Videojs player serve poster-image property with sub definition permalink
|
||||
* [PHRAS-2842] - Databases Models - now default audio encodeur is mp3lame
|
||||
* [PHRAS-2857] - Exclude some collections from quarantine checkers sha256, UUID, filename (AKA exclude Trash)
|
||||
* [PHRAS-2899] - Quarantine: allow to substitute without selecting target record, (when match only one record).
|
||||
* [PHRAS-2765] - Translation in Plugin menu locale is now available
|
||||
* [PHRAS-2929] - bump sinonjs dependency to 1.7.1
|
||||
* [PHRAS-2728] - Landing page take browser language in account
|
||||
* [PHRAS-2693] - Collection Sort Sorter is now presented by column
|
||||
* [PHRAS-2817] - Deploy and Dev with docker is OK
|
||||
|
||||
|
||||
### Bugfix
|
||||
* [PHRAS-1069] - Dates seems not extracted from iptc
|
||||
* [PHRAS-1428] - Phraseanet Binaries in configuration not used in some alchemy-fr libraries (AKA text extraction of pdf is NOK)
|
||||
* [PHRAS-2567] - Registration Form - Term of use link is broken
|
||||
* [PHRAS-2644] - Searching for stories after applying a document filtering choice gives no results
|
||||
* [PHRAS-2652] - Fields "Phraseanet::no-source" are pushed to exiftool
|
||||
* [PHRAS-2682] - Prod - facets display is NOK when switch from basket or thesaurus Tab.
|
||||
* [PHRAS-2695] - Prod - Grey and White Skins - Browse Baskets: Unable to read the titles
|
||||
* [PHRAS-2702] - Lightbox - scroller thumbnail Nok
|
||||
* [PHRAS-2714] - Adding record from the API leaves a copy of the file into the system temporary directory
|
||||
* [PHRAS-2715] - Embed bundle, border issue on firefox.
|
||||
* [PHRAS-2716] - Records SetStatus HTTP API malfunction
|
||||
* [PHRAS-2723] - None information (name, last name etc...) is keep from the Push or a FeedBack user creation form
|
||||
* [PHRAS-2748] - Some characters into cterms (candidats) leeds to 500 error
|
||||
* [PHRAS-2754] - Permalink is not (re) activated when record is move from _TRASH_ collection
|
||||
* [PHRAS-2860] - Generated Subdefs for video Portait are not correctly Oriented
|
||||
* [PHRAS-2877] - User manipulator does not allow to set a null email
|
||||
* [PHRAS-2912] - When updating a user informations the wrong field are populated (job and activity inverted)
|
||||
* [PHRAS-2811] - Cleanning of bad chars in candidats terms
|
||||
|
||||
|
||||
## 4.0.10
|
||||
|
||||
Not publish
|
||||
|
||||
## 4.0.9
|
||||
|
||||
### Adds
|
||||
@@ -13,11 +163,11 @@
|
||||
|
||||
### Fixes
|
||||
|
||||
* PHRAS-2491 - Front - Click on facets title (expand/collapse) launched a bad query, due to jquery error.
|
||||
* PHRAS-2510 - Front - Facets values appear Truncated after 15th character.
|
||||
* PHRAS-2153 - Front - No user search possible with the field "Company" and field "Country".
|
||||
* PHRAS-2154 - Front - Bug on Chrome only - selected 1 document instead of all for the feedback.
|
||||
* PHRAS-2538 - Back - Some MP4 files were not correctly detected by Phraseanet.
|
||||
- PHRAS-2491 - Front - Click on facets title (expand/collapse) launched a bad query, due to jquery error.
|
||||
- PHRAS-2510 - Front - Facets values appear Truncated after 15th character.
|
||||
- PHRAS-2153 - Front - No user search possible with the field "Company" and field "Country".
|
||||
- PHRAS-2154 - Front - Bug on Chrome only - selected 1 document instead of all for the feedback.
|
||||
- PHRAS-2538 - Back - Some MP4 files were not correctly detected by Phraseanet.
|
||||
|
||||
## 4.0.8
|
||||
|
||||
|
@@ -37,7 +37,7 @@ RUN echo "deb http://deb.debian.org/debian stretch main non-free" > /etc/apt/sou
|
||||
swftools \
|
||||
unoconv \
|
||||
unzip \
|
||||
xpdf \
|
||||
poppler-utils \
|
||||
libreoffice-base-core \
|
||||
libreoffice-impress \
|
||||
libreoffice-calc \
|
||||
@@ -67,6 +67,7 @@ RUN echo "deb http://deb.debian.org/debian stretch main non-free" > /etc/apt/sou
|
||||
libgsm1-dev \
|
||||
libfreetype6-dev \
|
||||
# End FFmpeg
|
||||
nano \
|
||||
&& update-locale "LANG=fr_FR.UTF-8 UTF-8" \
|
||||
&& dpkg-reconfigure --frontend noninteractive locales \
|
||||
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
|
||||
|
41
README.md
@@ -32,9 +32,13 @@ And follow the install steps described at https://docs.phraseanet.com/4.0/en/Adm
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- docker-compose
|
||||
- docker-compose >=v1.25.4
|
||||
- docker >=v18.01-ce
|
||||
|
||||
Note about elasticsearch container
|
||||
Check this link
|
||||
https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-prod-prerequisites
|
||||
|
||||
## Get started
|
||||
|
||||
You should review the default env variables defined in `.env` file.
|
||||
@@ -84,8 +88,9 @@ docker-compose -f docker-compose.yml run --rm worker <command>
|
||||
```
|
||||
|
||||
Where `<command>` can be:
|
||||
- `bin/console task-manager:scheduler:run` (default)
|
||||
- `bin/console worker:execute -m 2`
|
||||
|
||||
- `bin/console worker:execute -m 2` (default)
|
||||
- `bin/console task-manager:scheduler:run`
|
||||
- ...
|
||||
|
||||
The default parameters allow you to reach the app with : `http://localhost:8082`
|
||||
@@ -100,6 +105,12 @@ https://hub.docker.com/r/alchemyfr/phraseanet-worker
|
||||
|
||||
https://hub.docker.com/r/alchemyfr/phraseanet-nginx
|
||||
|
||||
https://hub.docker.com/repository/docker/alchemyfr/phraseanet-db
|
||||
|
||||
https://hub.docker.com/repository/docker/alchemyfr/phraseanet-elasticsearch
|
||||
|
||||
|
||||
|
||||
To use them and not build the images locally, we advise to override the properties in file: env.local
|
||||
|
||||
```bash
|
||||
@@ -108,6 +119,21 @@ PHRASEANET_DOCKER_REGISTRY=alchemyfr
|
||||
# Tag of the Docker images
|
||||
PHRASEANET_DOCKER_TAG=
|
||||
```
|
||||
or
|
||||
|
||||
Pull images before launch docker-compose
|
||||
|
||||
#### Tag organisation on docker hub
|
||||
|
||||
|
||||
```latest``` : latest stable version
|
||||
|
||||
```4.0``` : latest stable version in 4.0
|
||||
|
||||
```4.1``` : latest stable version in 4.1
|
||||
|
||||
```4.1.1``` : Phraseanet version 4.1.1
|
||||
|
||||
|
||||
## Development mode
|
||||
|
||||
@@ -172,17 +198,20 @@ XDEBUG_REMOTE_HOST=host.docker.internal
|
||||
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"
|
||||
PHRASEANET_PLUGINS="https://github.com/alchemy-fr/Phraseanet-plugin-expose.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"
|
||||
# Plugins are separated by semicolons
|
||||
PHRASEANET_PLUGINS="git@github.com:foo/bar.git(branch-1);git@github.com:baz/42.git"
|
||||
```
|
||||
|
||||
> Prefer the HTTPS URL for public repositories, you will not be required to provide your SSH key.
|
||||
|
||||
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:
|
||||
Also ensure you're using the SSH URL form (i.e: `git@github.com:alchemy-fr/repo.git`).
|
||||
```bash
|
||||
export PHRASEANET_SSH_PRIVATE_KEY=$(cat ~/.ssh/id_rsa)
|
||||
# or if your private key is protected by a passphrase:
|
||||
|
@@ -328,6 +328,14 @@ workers:
|
||||
password: guest
|
||||
vhost: /
|
||||
|
||||
externalservice:
|
||||
ginger:
|
||||
AutoSubtitling:
|
||||
service_base_url: https://base.uri
|
||||
token: 39c6011d
|
||||
transcript_format: text/vtt
|
||||
subdef_source: preview
|
||||
|
||||
user_account:
|
||||
deleting_policies:
|
||||
email_confirmation: true
|
||||
|
@@ -13,10 +13,6 @@ services:
|
||||
- ../:/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
|
||||
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
|
||||
|
||||
builder:
|
||||
build:
|
||||
@@ -50,25 +46,12 @@ services:
|
||||
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
|
||||
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
|
||||
- ${PHRASEANET_CACHE_DIR}:/var/alchemy/Phraseanet/cache:rw
|
||||
- ${PHRASEANET_TMP_DIR}:/var/alchemy/Phraseanet/tmp:rw
|
||||
|
||||
worker:
|
||||
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
|
||||
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
|
||||
- ${PHRASEANET_CACHE_DIR}:/var/alchemy/Phraseanet/cache:rw
|
||||
- ${PHRASEANET_TMP_DIR}:/var/alchemy/Phraseanet/tmp:rw
|
||||
|
||||
|
||||
rabbitmq:
|
||||
ports:
|
||||
|
@@ -14,10 +14,12 @@ services:
|
||||
- ${PHRASEANET_DATA_DIR}:/var/alchemy/Phraseanet/datas:rw
|
||||
- ${PHRASEANET_THUMBNAILS_DIR}:/var/alchemy/Phraseanet/www/thumbnails:rw
|
||||
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
|
||||
- ${PHRASEANET_PLUGINS_DIR}:/var/alchemy/Phraseanet/www/plugins:rw
|
||||
depends_on:
|
||||
- phraseanet
|
||||
environment:
|
||||
- MAX_BODY_SIZE
|
||||
- GATEWAY_SEND_TIMEOUT
|
||||
ports:
|
||||
- ${PHRASEANET_APP_PORT}:80
|
||||
|
||||
@@ -39,9 +41,12 @@ services:
|
||||
- PHRASEANET_PROJECT_NAME
|
||||
- MAX_BODY_SIZE
|
||||
- MAX_INPUT_VARS
|
||||
- MAX_EXECUTION_TIME
|
||||
- MAX_INPUT_TIME
|
||||
- OPCACHE_ENABLED
|
||||
- SESSION_CACHE_LIMITER
|
||||
- PHP_LOG_LEVEL
|
||||
- PHRASEANET_ADMIN_ACCOUNT_ID
|
||||
- PHRASEANET_ADMIN_ACCOUNT_EMAIL
|
||||
- PHRASEANET_ADMIN_ACCOUNT_PASSWORD
|
||||
- PHRASEANET_DB_HOST
|
||||
@@ -63,14 +68,28 @@ services:
|
||||
- PHRASEANET_SMTP_SECURE_MODE
|
||||
- PHRASEANET_SMTP_USER
|
||||
- PHRASEANET_SMTP_PASSWORD
|
||||
- PHRASEANET_DOWNLOAD_DIR
|
||||
- PHRASEANET_LAZARET_DIR
|
||||
- PHRASEANET_CAPTION_DIR
|
||||
- PHRASEANET_WORKER_TMP
|
||||
- LC_MESSAGES=C.UTF-8
|
||||
- LC_COLLATE=C.UTF-8
|
||||
- LC_IDENTIFICATION=C.UTF-8
|
||||
- LANG=C.UTF-8
|
||||
- LC_MEASUREMENT=C.UTF-8
|
||||
- LC_CTYPE=C.UTF-8
|
||||
- LC_TIME=C.UTF-8
|
||||
- LC_NAME=C.UTF-8
|
||||
|
||||
volumes:
|
||||
- config_vol:/var/alchemy/Phraseanet/config:rw
|
||||
- data_vol:/var/alchemy/Phraseanet/datas:rw
|
||||
- tmp_vol:/var/alchemy/Phraseanet/tmp:rw
|
||||
- logs_vol:/var/alchemy/Phraseanet/logs:rw
|
||||
- thumbnails_vol:/var/alchemy/Phraseanet/www/thumbnails:rw
|
||||
- custom_vol:/var/alchemy/Phraseanet/www/custom:rw
|
||||
- cache_vol:/var/alchemy/Phraseanet/cache:rw
|
||||
- ${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
|
||||
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
|
||||
- ${PHRASEANET_PLUGINS_DIR}:/var/alchemy/Phraseanet/www/plugins:rw
|
||||
- ${PHRASEANET_CACHE_DIR}:/var/alchemy/Phraseanet/cache:rw
|
||||
- ${PHRASEANET_TMP_DIR}:/var/alchemy/Phraseanet/tmp:rw
|
||||
|
||||
worker:
|
||||
build:
|
||||
@@ -93,14 +112,23 @@ services:
|
||||
- OPCACHE_ENABLED
|
||||
- SESSION_CACHE_LIMITER
|
||||
- PHP_LOG_LEVEL
|
||||
- LC_MESSAGES=C.UTF-8
|
||||
- LC_COLLATE=C.UTF-8
|
||||
- LC_IDENTIFICATION=C.UTF-8
|
||||
- LANG=C.UTF-8
|
||||
- LC_MEASUREMENT=C.UTF-8
|
||||
- LC_CTYPE=C.UTF-8
|
||||
- LC_TIME=C.UTF-8
|
||||
- LC_NAME=C.UTF-8
|
||||
|
||||
volumes:
|
||||
- config_vol:/var/alchemy/Phraseanet/config:rw
|
||||
- data_vol:/var/alchemy/Phraseanet/datas:rw
|
||||
- tmp_vol:/var/alchemy/Phraseanet/tmp:rw
|
||||
- logs_vol:/var/alchemy/Phraseanet/logs:rw
|
||||
- thumbnails_vol:/var/alchemy/Phraseanet/www/thumbnails:rw
|
||||
- custom_vol:/var/alchemy/Phraseanet/www/custom:rw
|
||||
- cache_vol:/var/alchemy/Phraseanet/cache:rw
|
||||
- ${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
|
||||
- ${PHRASEANET_CUSTOM_DIR}:/var/alchemy/Phraseanet/www/custom:rw
|
||||
- ${PHRASEANET_CACHE_DIR}:/var/alchemy/Phraseanet/cache:rw
|
||||
- ${PHRASEANET_TMP_DIR}:/var/alchemy/Phraseanet/tmp:rw
|
||||
|
||||
db:
|
||||
image: $PHRASEANET_DOCKER_REGISTRY/phraseanet-db:$PHRASEANET_DOCKER_TAG
|
||||
@@ -151,10 +179,12 @@ volumes:
|
||||
driver: local
|
||||
custom_vol:
|
||||
driver: local
|
||||
plugins_dir:
|
||||
driver: local
|
||||
cache_vol:
|
||||
driver: local
|
||||
# to be replacer by stdout/stderr
|
||||
logs_vol:
|
||||
driver: local
|
||||
dev_vol:
|
||||
driver: local
|
||||
driver: local
|
||||
|
@@ -2,6 +2,6 @@
|
||||
|
||||
set -xe
|
||||
|
||||
cat /nginx.conf.sample | sed "s/\$MAX_BODY_SIZE/$MAX_BODY_SIZE/g" > /etc/nginx/conf.d/default.conf
|
||||
cat /nginx.conf.sample | sed "s/\$MAX_BODY_SIZE/$MAX_BODY_SIZE/g" | sed "s/\$GATEWAY_SEND_TIMEOUT/$GATEWAY_SEND_TIMEOUT/g" > /etc/nginx/conf.d/default.conf
|
||||
|
||||
exec "$@"
|
||||
|
@@ -1,3 +1,4 @@
|
||||
send_timeout $GATEWAY_SEND_TIMEOUT;
|
||||
upstream backend {
|
||||
server phraseanet:9000;
|
||||
}
|
||||
|
@@ -12,26 +12,33 @@ chown -R app:app \
|
||||
datas \
|
||||
tmp \
|
||||
logs \
|
||||
www/thumbnails \
|
||||
www/custom
|
||||
www
|
||||
|
||||
FILE=config/configuration.yml
|
||||
|
||||
if [ -f "$FILE" ]; then
|
||||
echo "$FILE exists, skip setup."
|
||||
bin/setup system:config set registry.general.title $PHRASEANET_PROJECT_NAME
|
||||
if [[ $PHRASEANET_SMTP_ENABLED=true ]]; then
|
||||
if [[ $PHRASEANET_PROJECT_NAME ]]; then
|
||||
bin/setup system:config set registry.general.title $PHRASEANET_PROJECT_NAME
|
||||
fi
|
||||
if [[ $PHRASEANET_SMTP_ENABLED && $PHRASEANET_SMTP_ENABLED=true ]]; then
|
||||
bin/setup system:config set registry.email.smtp-enabled $PHRASEANET_SMTP_ENABLED
|
||||
bin/setup system:config set registry.email.smtp-auth-enabled $PHRASEANET_SMTP_AUTH_ENABLED
|
||||
bin/setup system:config set registry.email.smtp-auth-secure-mode $PHRASEANET_SMTP_SECURE_MODE
|
||||
bin/setup system:config set registry.email.smtp-auth-host $PHRASEANET_SMTP_HOST
|
||||
bin/setup system:config set registry.email.smtp-auth-port $PHRASEANET_SMTP_PORT
|
||||
bin/setup system:config set registry.email.smtp-host $PHRASEANET_SMTP_HOST
|
||||
bin/setup system:config set registry.email.smtp-port $PHRASEANET_SMTP_PORT
|
||||
bin/setup system:config set registry.email.smtp-user $PHRASEANET_SMTP_USER
|
||||
bin/setup system:config set registry.email.smtp-password $PHRASEANET_SMTP_PASSWORD
|
||||
bin/setup system:config set registry.email.emitter-email $PHRASEANET_EMITTER_EMAIL
|
||||
bin/setup system:config set registry.email.prefix $PHRASEANET_MAIL_OBJECT_PREFIX
|
||||
if [[ -n $PHRASEANET_TRUSTED_PROXY ]]; then
|
||||
bin/setup system:config add trusted-proxies $PHRASEANET_TRUSTED_PROXY
|
||||
fi
|
||||
fi
|
||||
bin/console user:password --user_id=1 --password $PHRASEANET_ADMIN_ACCOUNT_PASSWORD -y
|
||||
if [[ -n ${PHRASEANET_ADMIN_ACCOUNT_ID} && $PHRASEANET_ADMIN_ACCOUNT_ID =~ ^[0-9]+$ ]]; then
|
||||
bin/console user:password --user_id=$PHRASEANET_ADMIN_ACCOUNT_ID --password $PHRASEANET_ADMIN_ACCOUNT_PASSWORD -y
|
||||
fi
|
||||
|
||||
else
|
||||
echo "$FILE doesn't exist, entering setup..."
|
||||
runuser app -c docker/phraseanet/auto-install.sh
|
||||
@@ -43,5 +50,18 @@ if [ ${XDEBUG_ENABLED} == "1" ]; then
|
||||
fi
|
||||
|
||||
./docker/phraseanet/plugins/console init
|
||||
#rm -Rf cache/
|
||||
|
||||
chown -R app:app \
|
||||
cache \
|
||||
config \
|
||||
datas \
|
||||
tmp \
|
||||
logs \
|
||||
www
|
||||
|
||||
if [ -d "plugins/" ];then
|
||||
chown -R app:app plugins;
|
||||
fi
|
||||
|
||||
bash -e docker-php-entrypoint $@
|
||||
|
@@ -380,7 +380,7 @@ expose_php = On
|
||||
; Maximum execution time of each script, in seconds
|
||||
; http://php.net/max-execution-time
|
||||
; Note: This directive is hardcoded to 0 for the CLI SAPI
|
||||
max_execution_time = 9999
|
||||
max_execution_time = $MAX_EXECUTION_TIME
|
||||
|
||||
; Maximum amount of time each script may spend parsing request data. It's a good
|
||||
; idea to limit this time on productions servers in order to eliminate unexpectedly
|
||||
@@ -390,7 +390,7 @@ max_execution_time = 9999
|
||||
; Development Value: 60 (60 seconds)
|
||||
; Production Value: 60 (60 seconds)
|
||||
; http://php.net/max-input-time
|
||||
max_input_time = 60
|
||||
max_input_time = $MAX_INPUT_TIME
|
||||
|
||||
; Maximum input variable nesting level
|
||||
; http://php.net/max-input-nesting-level
|
||||
|
@@ -29,7 +29,7 @@ class InstallCommand extends Command
|
||||
mkdir($pluginsDir);
|
||||
}
|
||||
|
||||
foreach (explode(' ', $plugins) as $key => $plugin) {
|
||||
foreach (explode(';', $plugins) as $key => $plugin) {
|
||||
$plugin = trim($plugin);
|
||||
$repo = $plugin;
|
||||
$branch = 'master';
|
||||
|
@@ -91,7 +91,6 @@ use Alchemy\Phrasea\WorkerManager\Provider\AlchemyWorkerServiceProvider;
|
||||
use Alchemy\Phrasea\WorkerManager\Provider\QueueWorkerServiceProvider;
|
||||
use Alchemy\QueueProvider\QueueServiceProvider;
|
||||
use Alchemy\WorkerProvider\WorkerServiceProvider;
|
||||
use Doctrine\DBAL\Event\ConnectionEventArgs;
|
||||
use MediaVorus\Media\MediaInterface;
|
||||
use MediaVorus\MediaVorus;
|
||||
use Monolog\Handler\ErrorLogHandler;
|
||||
@@ -618,7 +617,7 @@ class Application extends SilexApplication
|
||||
);
|
||||
|
||||
$this['tmp.lazaret.path'] = $factory->createDefinition(
|
||||
['main', 'storage', 'quarantine'],
|
||||
['main', 'storage', 'lazaret'],
|
||||
function (Application $app) {
|
||||
return $app['tmp.path'].'/lazaret';
|
||||
}
|
||||
|
@@ -2093,7 +2093,7 @@ class V1Controller extends Controller
|
||||
|
||||
try {
|
||||
$collection = \collection::getByBaseId($this->app, $request->get('base_id'));
|
||||
$record->move_to_collection($collection, $this->getApplicationBox());
|
||||
$record->move_to_collection($collection);
|
||||
|
||||
return Result::create($request, ["record" => $this->listRecord($request, $record)])->createResponse();
|
||||
} catch (\Exception $e) {
|
||||
|
393
lib/Alchemy/Phrasea/Controller/Api/V3/V3RecordController.php
Normal file
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Controller\Api\V3;
|
||||
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\DispatcherAware;
|
||||
use Alchemy\Phrasea\Application\Helper\JsonBodyAware;
|
||||
use Alchemy\Phrasea\Controller\Api\Result;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\Core\Event\RecordEdit;
|
||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
use caption_field;
|
||||
use databox_field;
|
||||
use Exception;
|
||||
use record_adapter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
||||
class V3RecordController extends Controller
|
||||
{
|
||||
use JsonBodyAware;
|
||||
use DispatcherAware;
|
||||
|
||||
|
||||
/**
|
||||
* Return detailed information about one story
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $databox_id
|
||||
* @param int $record_id
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function indexAction_patch(Request $request, $databox_id, $record_id)
|
||||
{
|
||||
$struct = $this->findDataboxById($databox_id)->get_meta_structure();
|
||||
$record = $this->findDataboxById($databox_id)->get_record($record_id);
|
||||
|
||||
//$record->set_metadatas()
|
||||
|
||||
//setRecordStatusAction
|
||||
|
||||
try {
|
||||
$b = $this->decodeJsonBody($request);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return $this->app['controller.api.v1']->getBadRequestAction($request, 'Bad JSON');
|
||||
}
|
||||
|
||||
$debug = [
|
||||
'metadatas_ops' => null,
|
||||
'sb_ops' => null,
|
||||
];
|
||||
try {
|
||||
// do metadatas ops
|
||||
if (is_array($b->metadatas)) {
|
||||
$debug['metadatas_ops'] = $this->do_metadatas($struct, $record, $b->metadatas);
|
||||
}
|
||||
// do sb ops
|
||||
if (is_array($b->status)) {
|
||||
$debug['sb_ops'] = $this->do_status($record, $b->status);
|
||||
}
|
||||
if(!is_null($b->base_id)) {
|
||||
$debug['coll_ops'] = $this->do_collection($record, $b->base_id);
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return $this->app['controller.api.v1']->getBadRequestAction(
|
||||
$request,
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
// @todo Move event dispatch inside record_adapter class (keeps things encapsulated)
|
||||
$this->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($record));
|
||||
|
||||
$ret = $this->getResultHelpers()->listRecord($request, $record, $this->getAclForUser());
|
||||
|
||||
return Result::create($request, $ret)->createResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param record_adapter $record
|
||||
* @param $base_id
|
||||
*/
|
||||
private function do_collection(record_adapter $record, $base_id)
|
||||
{
|
||||
$record->move_to_collection($this->getApplicationBox()->get_collection($base_id));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
/// TODO : keep multi-values uniques !
|
||||
/// it should be done in record_adapter
|
||||
//////////////////////////////////
|
||||
|
||||
/**
|
||||
* @param databox_field[] $struct
|
||||
* @param record_adapter $record
|
||||
* @param $metadatas
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function do_metadatas($struct, record_adapter $record, $metadatas)
|
||||
{
|
||||
$structByKey = [];
|
||||
$allStructFields = [];
|
||||
foreach ($struct as $f) {
|
||||
$allStructFields[$f->get_id()] = $f;
|
||||
$structByKey[$f->get_id()] = &$allStructFields[$f->get_id()];
|
||||
$structByKey[$f->get_name()] = &$allStructFields[$f->get_id()];
|
||||
}
|
||||
|
||||
$metadatas_ops = [];
|
||||
foreach ($metadatas as $_m) {
|
||||
// sanity
|
||||
if($_m->meta_struct_id && $_m->field_name) {
|
||||
throw new Exception("define meta_struct_id OR field_name, not both.");
|
||||
}
|
||||
// select fields that match meta_struct_id or field_name (can be arrays)
|
||||
$fields_list = null; // to filter caption_fields from record, default all
|
||||
$struct_fields = []; // struct fields that match meta_struct_id or field_name
|
||||
$field_keys = $_m->meta_struct_id ? $_m->meta_struct_id : $_m->field_name; // can be null if none defined (=match all)
|
||||
if($field_keys !== null) {
|
||||
if (!is_array($field_keys)) {
|
||||
$field_keys = [$field_keys];
|
||||
}
|
||||
$fields_list = [];
|
||||
foreach ($field_keys as $k) {
|
||||
if(array_key_exists($k, $structByKey)) {
|
||||
$fields_list[] = $structByKey[$k]->get_name();
|
||||
$struct_fields[$structByKey[$k]->get_id()] = $structByKey[$k];
|
||||
}
|
||||
else {
|
||||
throw new Exception(sprintf("unknown field (%s).", $k));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no meta_struct_id, no field_name --> match all struct fields !
|
||||
$struct_fields = $allStructFields;
|
||||
}
|
||||
$caption_fields = $record->get_caption()->get_fields($fields_list, true);
|
||||
|
||||
$meta_id = is_null($_m->meta_id) ? null : (int)($_m->meta_id);
|
||||
|
||||
if(!($match_method = (string)($_m->match_method))) {
|
||||
$match_method = 'ignore_case';
|
||||
}
|
||||
if(!in_array($match_method, ['strict', 'ignore_case', 'regexp'])) {
|
||||
throw new Exception(sprintf("bad match_method (%s).", $match_method));
|
||||
}
|
||||
|
||||
$values = [];
|
||||
if(is_array($_m->value)) {
|
||||
foreach ($_m->value as $v) {
|
||||
if(($v = trim((string)$v)) !== '') {
|
||||
$values[] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(($v = trim((string)($_m->value))) !== '') {
|
||||
$values[] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if(!($action = (string)($_m->action))) {
|
||||
$action = 'set';
|
||||
}
|
||||
|
||||
switch ($_m->action) {
|
||||
case 'set':
|
||||
$ops = $this->metadata_set($struct_fields, $caption_fields, $meta_id, $values);
|
||||
break;
|
||||
case 'add':
|
||||
$ops = $this->metadata_add($struct_fields, $values);
|
||||
break;
|
||||
case 'delete':
|
||||
$ops = $this->metadata_replace($caption_fields, $meta_id, $match_method, $values, null);
|
||||
break;
|
||||
case 'replace':
|
||||
if (!is_string($_m->replace_with) && !is_null($_m->replace_with)) {
|
||||
throw new Exception("bad \"replace_with\" for action \"replace\".");
|
||||
}
|
||||
$ops = $this->metadata_replace($caption_fields, $meta_id, $match_method, $values, $_m->replace_with);
|
||||
break;
|
||||
default:
|
||||
throw new Exception(sprintf("bad action (%s).", $action));
|
||||
}
|
||||
|
||||
$metadatas_ops = array_merge($metadatas_ops, $ops);
|
||||
}
|
||||
|
||||
$record->set_metadatas($metadatas_ops, true);
|
||||
|
||||
return $metadatas_ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $record
|
||||
* @param $statuses
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function do_status(record_adapter $record, $statuses)
|
||||
{
|
||||
$datas = strrev($record->getStatus());
|
||||
|
||||
foreach ($statuses as $status) {
|
||||
$n = (int)($status->bit);
|
||||
$value = (int)($status->state);
|
||||
if ($n > 31 || $n < 4) {
|
||||
throw new Exception(sprintf("Invalid status bit number (%s).", $n));
|
||||
}
|
||||
if ($value < 0 || $value > 1) {
|
||||
throw new Exception(sprintf("Invalid status bit state (%s) for bit (%s).", $value, $n));
|
||||
}
|
||||
|
||||
$datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 1));
|
||||
}
|
||||
|
||||
$record->setStatus(strrev($datas));
|
||||
|
||||
return ["status" => $this->getResultHelpers()->listRecordStatus($record)];
|
||||
}
|
||||
|
||||
private function match($pattern, $method, $value)
|
||||
{
|
||||
switch ($method) {
|
||||
case 'strict':
|
||||
return $value === $pattern;
|
||||
case 'ignore_case':
|
||||
return strtolower($value) === strtolower($pattern);
|
||||
case 'regexp':
|
||||
return preg_match($pattern, $value) == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param databox_field[] $struct_fields struct-fields (from struct) matching meta_struct_id or field_name
|
||||
* @param caption_field[] $caption_fields caption-fields (from record) matching meta_struct_id or field_name (or all if not set)
|
||||
* @param int|null $meta_id
|
||||
* @param string[] $values
|
||||
*
|
||||
* @return array ops to execute
|
||||
* @throws Exception
|
||||
*/
|
||||
private function metadata_set($struct_fields, $caption_fields, $meta_id, $values)
|
||||
{
|
||||
$ops = [];
|
||||
|
||||
// if one field was multi-valued and no meta_id was set, we must delete all values
|
||||
foreach ($caption_fields as $cf) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
if (is_null($meta_id) || $field_value->getId() === (int)$meta_id) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => ''
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// now set values to matching struct_fields
|
||||
foreach ($struct_fields as $sf) {
|
||||
if($sf->is_multi()) {
|
||||
// add the non-null value(s)
|
||||
foreach ($values as $value) {
|
||||
if ($value) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $sf->get_id(),
|
||||
'meta_id' => $meta_id, // can be null
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// mono-valued
|
||||
if(count($values) > 1) {
|
||||
throw new Exception(sprintf("setting mono-valued (%s) requires only one value.", $sf->get_name()));
|
||||
}
|
||||
if( ($value = $values[0]) ) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $sf->get_id(),
|
||||
'meta_id' => $meta_id, // probably null,
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param databox_field[] $struct_fields struct-fields (from struct) matching meta_struct_id or field_name
|
||||
* @param string[] $values
|
||||
*
|
||||
* @return array ops to execute
|
||||
* @throws Exception
|
||||
*/
|
||||
private function metadata_add($struct_fields, $values)
|
||||
{
|
||||
$ops = [];
|
||||
|
||||
// now set values to matching struct_fields
|
||||
foreach ($struct_fields as $sf) {
|
||||
if(!$sf->is_multi()) {
|
||||
throw new Exception(sprintf("can't \"add\" to mono-valued (%s).", $sf->get_name()));
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $sf->get_id(),
|
||||
'meta_id' => null,
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param caption_field[] $caption_fields caption-fields (from record) matching meta_struct_id or field_name (or all if not set)
|
||||
* @param int|null $meta_id
|
||||
* @param string $match_method "strict" | "ignore_case" | "regexp"
|
||||
* @param string[] $values
|
||||
* @param string|null $replace_with
|
||||
*
|
||||
* @return array ops to execute
|
||||
*/
|
||||
private function metadata_replace($caption_fields, $meta_id, $match_method, $values, $replace_with)
|
||||
{
|
||||
$ops = [];
|
||||
|
||||
$replace_with = trim((string)$replace_with);
|
||||
|
||||
foreach ($caption_fields as $cf) {
|
||||
// match all ?
|
||||
if(is_null($meta_id) && count($values) == 0) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => $replace_with
|
||||
];
|
||||
}
|
||||
}
|
||||
// match by meta-id ?
|
||||
if (!is_null($meta_id)) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
if ($field_value->getId() === $meta_id) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => $replace_with
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// match by value(s) ?
|
||||
foreach ($values as $value) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
$rw = $replace_with;
|
||||
if($match_method=='regexp' && $rw != '') {
|
||||
$rw = preg_replace($value, $rw, $field_value->getValue());
|
||||
}
|
||||
if ($this->match($value, $match_method, $field_value->getValue())) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => $rw
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return V3ResultHelpers
|
||||
*/
|
||||
private function getResultHelpers()
|
||||
{
|
||||
return $this->app['controller.api.v3.resulthelpers'];
|
||||
}
|
||||
}
|
277
lib/Alchemy/Phrasea/Controller/Api/V3/V3ResultHelpers.php
Normal file
@@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Controller\Api\V3;
|
||||
|
||||
|
||||
use ACL;
|
||||
use Alchemy\Phrasea\Authentication\Authenticator;
|
||||
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||
use Alchemy\Phrasea\Media\MediaSubDefinitionUrlGenerator;
|
||||
use caption_field;
|
||||
use databox_status;
|
||||
use media_Permalink_Adapter;
|
||||
use media_subdef;
|
||||
use record_adapter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
|
||||
class V3ResultHelpers
|
||||
{
|
||||
/** @var PropertyAccess */
|
||||
private $conf;
|
||||
|
||||
/** @var MediaSubDefinitionUrlGenerator */
|
||||
private $urlgenerator;
|
||||
|
||||
/** @var Authenticator */
|
||||
private $authenticator;
|
||||
|
||||
|
||||
public function __construct($conf, $urlgenerator, Authenticator $authenticator)
|
||||
{
|
||||
$this->urlgenerator = $urlgenerator;
|
||||
$this->conf = $conf;
|
||||
$this->authenticator = $authenticator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve detailed information about one status
|
||||
*
|
||||
* @param record_adapter $record
|
||||
* @return array
|
||||
*/
|
||||
public function listRecordStatus(record_adapter $record)
|
||||
{
|
||||
$ret = [];
|
||||
foreach ($record->getStatusStructure() as $bit => $status) {
|
||||
$ret[] = [
|
||||
'bit' => $bit,
|
||||
'state' => databox_status::bitIsSet($record->getStatusBitField(), $bit),
|
||||
];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function listEmbeddableMedia(Request $request, record_adapter $record, media_subdef $media, ACL $acl)
|
||||
{
|
||||
if (!$media->is_physically_present()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->getAuthenticator()->isAuthenticated()) {
|
||||
if ($media->get_name() !== 'document'
|
||||
&& false === $acl->has_access_to_subdef($record, $media->get_name())
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if ($media->get_name() === 'document'
|
||||
&& !$acl->has_right_on_base($record->getBaseId(), ACL::CANDWNLDHD)
|
||||
&& !$acl->has_hd_grant($record)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($media->get_permalink() instanceof media_Permalink_Adapter) {
|
||||
$permalink = $this->listPermalink($media->get_permalink());
|
||||
} else {
|
||||
$permalink = null;
|
||||
}
|
||||
|
||||
$urlTTL = (int) $request->get(
|
||||
'subdef_url_ttl',
|
||||
$this->getConf()->get(['registry', 'general', 'default-subdef-url-ttl'])
|
||||
);
|
||||
if ($urlTTL < 0) {
|
||||
$urlTTL = -1;
|
||||
}
|
||||
$issuer = $this->getAuthenticator()->getUser();
|
||||
|
||||
return [
|
||||
'name' => $media->get_name(),
|
||||
'permalink' => $permalink,
|
||||
'height' => $media->get_height(),
|
||||
'width' => $media->get_width(),
|
||||
'filesize' => $media->get_size(),
|
||||
'devices' => $media->getDevices(),
|
||||
'player_type' => $media->get_type(),
|
||||
'mime_type' => $media->get_mime(),
|
||||
'substituted' => $media->is_substituted(),
|
||||
'created_on' => $media->get_creation_date()->format(DATE_ATOM),
|
||||
'updated_on' => $media->get_modification_date()->format(DATE_ATOM),
|
||||
'url' => $this->urlgenerator->generate($issuer, $media, $urlTTL),
|
||||
'url_ttl' => $urlTTL,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param media_Permalink_Adapter $permalink
|
||||
* @return array
|
||||
*
|
||||
* @todo fix duplicated code
|
||||
* @noinspection DuplicatedCode
|
||||
*/
|
||||
public function listPermalink(media_Permalink_Adapter $permalink)
|
||||
{
|
||||
$downloadUrl = $permalink->get_url();
|
||||
$downloadUrl->getQuery()->set('download', '1');
|
||||
|
||||
return [
|
||||
'created_on' => $permalink->get_created_on()->format(DATE_ATOM),
|
||||
'id' => $permalink->get_id(),
|
||||
'is_activated' => $permalink->get_is_activated(),
|
||||
'label' => $permalink->get_label(),
|
||||
'updated_on' => $permalink->get_last_modified()->format(DATE_ATOM),
|
||||
'page_url' => $permalink->get_page(),
|
||||
'download_url' => (string)$downloadUrl,
|
||||
'url' => (string)$permalink->get_url(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve detailed information about one record
|
||||
*
|
||||
* @param Request $request
|
||||
* @param record_adapter $record
|
||||
* @param ACL $aclforuser
|
||||
* @return array
|
||||
*/
|
||||
public function listRecord(Request $request, record_adapter $record, ACL $aclforuser)
|
||||
{
|
||||
$technicalInformation = [];
|
||||
foreach ($record->get_technical_infos()->getValues() as $name => $value) {
|
||||
$technicalInformation[] = ['name' => $name, 'value' => $value];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'databox_id' => $record->getDataboxId(),
|
||||
'record_id' => $record->getRecordId(),
|
||||
'mime_type' => $record->getMimeType(),
|
||||
'title' => $record->get_title(),
|
||||
'original_name' => $record->get_original_name(),
|
||||
'updated_on' => $record->getUpdated()->format(DATE_ATOM),
|
||||
'created_on' => $record->getCreated()->format(DATE_ATOM),
|
||||
'collection_id' => $record->getCollectionId(),
|
||||
'base_id' => $record->getBaseId(),
|
||||
'sha256' => $record->getSha256(),
|
||||
'thumbnail' => $this->listEmbeddableMedia($request, $record, $record->get_thumbnail(), $aclforuser),
|
||||
'technical_informations' => $technicalInformation,
|
||||
'phrasea_type' => $record->getType(),
|
||||
'uuid' => $record->getUuid(),
|
||||
];
|
||||
|
||||
if ($request->attributes->get('_extended', false)) {
|
||||
$data = array_merge($data, [
|
||||
'subdefs' => $this->listRecordEmbeddableMedias($request, $record, $aclforuser),
|
||||
'metadata' => $this->listRecordMetadata($record, $aclforuser),
|
||||
'status' => $this->listRecordStatus($record),
|
||||
'caption' => $this->listRecordCaption($record, $aclforuser),
|
||||
]);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param record_adapter $record
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordEmbeddableMedias(Request $request, record_adapter $record, ACL $acl)
|
||||
{
|
||||
$subdefs = [];
|
||||
|
||||
foreach ($record->get_embedable_medias([], []) as $name => $media) {
|
||||
if (null !== $subdef = $this->listEmbeddableMedia($request, $record, $media, $acl)) {
|
||||
$subdefs[] = $subdef;
|
||||
}
|
||||
}
|
||||
|
||||
return $subdefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all fields of given record
|
||||
*
|
||||
* @param record_adapter $record
|
||||
* @param ACL $acl
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordMetadata(record_adapter $record, ACL $acl)
|
||||
{
|
||||
$includeBusiness = $acl->can_see_business_fields($record->getDatabox());
|
||||
|
||||
return $this->listRecordCaptionFields($record->get_caption()->get_fields(null, $includeBusiness));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param caption_field[] $fields
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordCaptionFields($fields)
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$databox_field = $field->get_databox_field();
|
||||
|
||||
$fieldData = [
|
||||
'meta_structure_id' => $field->get_meta_struct_id(),
|
||||
'name' => $field->get_name(),
|
||||
'labels' => [
|
||||
'fr' => $databox_field->get_label('fr'),
|
||||
'en' => $databox_field->get_label('en'),
|
||||
'de' => $databox_field->get_label('de'),
|
||||
'nl' => $databox_field->get_label('nl'),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($field->get_values() as $value) {
|
||||
$data = [
|
||||
'meta_id' => $value->getId(),
|
||||
'value' => $value->getValue(),
|
||||
];
|
||||
|
||||
$ret[] = $fieldData + $data;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param record_adapter $record
|
||||
* @param ACL $acl
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordCaption(record_adapter $record, ACL $acl)
|
||||
{
|
||||
$includeBusiness = $acl->can_see_business_fields($record->getDatabox());
|
||||
|
||||
$caption = [];
|
||||
|
||||
foreach ($record->get_caption()->get_fields(null, $includeBusiness) as $field) {
|
||||
$caption[] = [
|
||||
'meta_structure_id' => $field->get_meta_struct_id(),
|
||||
'name' => $field->get_name(),
|
||||
'value' => $field->get_serialized_values(';'),
|
||||
];
|
||||
}
|
||||
|
||||
return $caption;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////
|
||||
private function getAuthenticator()
|
||||
{
|
||||
return $this->authenticator;
|
||||
}
|
||||
|
||||
protected function getConf()
|
||||
{
|
||||
return $this->conf;
|
||||
}
|
||||
|
||||
}
|
@@ -1,8 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Controller\Api;
|
||||
namespace Alchemy\Phrasea\Controller\Api\V3;
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\DispatcherAware;
|
||||
use Alchemy\Phrasea\Application\Helper\JsonBodyAware;
|
||||
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
|
||||
use Alchemy\Phrasea\Controller\Api\Result;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\Databox\DataboxGroupable;
|
||||
use Alchemy\Phrasea\Fractal\CallbackTransformer;
|
||||
@@ -31,34 +34,19 @@ use Alchemy\Phrasea\SearchEngine\SearchEngineInterface;
|
||||
use Alchemy\Phrasea\SearchEngine\SearchEngineLogger;
|
||||
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
|
||||
use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
|
||||
use caption_record;
|
||||
use League\Fractal\Manager as FractalManager;
|
||||
use League\Fractal\Resource\Item;
|
||||
use media_Permalink_Adapter;
|
||||
use media_subdef;
|
||||
use record_adapter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class V3Controller extends Controller
|
||||
class V3SearchController extends Controller
|
||||
{
|
||||
/**
|
||||
* Return detailed information about one story
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $databox_id
|
||||
* @param int $record_id
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getStoryAction(Request $request, $databox_id, $record_id)
|
||||
{
|
||||
try {
|
||||
$story = $this->findDataboxById($databox_id)->get_record($record_id);
|
||||
|
||||
return Result::create($request, ['story' => $this->listStory($request, $story)])->createResponse();
|
||||
} catch (NotFoundHttpException $e) {
|
||||
return Result::createError($request, 404, $this->app->trans('Story Not Found'))->createResponse();
|
||||
} catch (\Exception $e) {
|
||||
return $this->app['controller.api.v1']->getBadRequestAction($request, $this->app->trans('An error occurred'));
|
||||
}
|
||||
}
|
||||
use JsonBodyAware;
|
||||
use DispatcherAware;
|
||||
|
||||
/**
|
||||
* Search for results
|
||||
@@ -101,7 +89,7 @@ class V3Controller extends Controller
|
||||
|
||||
$includeResolver = new IncludeResolver($transformerResolver);
|
||||
|
||||
$fractal = new \League\Fractal\Manager();
|
||||
$fractal = new FractalManager();
|
||||
$fractal->setSerializer(new TraceableArraySerializer($this->app['dispatcher']));
|
||||
$fractal->parseIncludes($this->resolveSearchIncludes($request));
|
||||
|
||||
@@ -125,314 +113,7 @@ class V3Controller extends Controller
|
||||
return Result::create($request, $ret)->createResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve detailed information about one story
|
||||
*
|
||||
* @param Request $request
|
||||
* @param \record_adapter $story
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function listStory(Request $request, \record_adapter $story)
|
||||
{
|
||||
if (!$story->isStory()) {
|
||||
return Result::createError($request, 404, 'Story not found')->createResponse();
|
||||
}
|
||||
|
||||
$per_page = (int)$request->get('per_page')?:10;
|
||||
$page = (int)$request->get('page')?:1;
|
||||
$offset = ($per_page * ($page - 1)) + 1;
|
||||
|
||||
$caption = $story->get_caption();
|
||||
|
||||
$format = function (\caption_record $caption, $dcField) {
|
||||
|
||||
$field = $caption->get_dc_field($dcField);
|
||||
|
||||
if (!$field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $field->get_serialized_values();
|
||||
};
|
||||
|
||||
return [
|
||||
'@entity@' => V1Controller::OBJECT_TYPE_STORY,
|
||||
'databox_id' => $story->getDataboxId(),
|
||||
'story_id' => $story->getRecordId(),
|
||||
'updated_on' => $story->getUpdated()->format(DATE_ATOM),
|
||||
'created_on' => $story->getCreated()->format(DATE_ATOM),
|
||||
'collection_id' => $story->getCollectionId(),
|
||||
'base_id' => $story->getBaseId(),
|
||||
'thumbnail' => $this->listEmbeddableMedia($request, $story, $story->get_thumbnail()),
|
||||
'uuid' => $story->getUuid(),
|
||||
'metadatas' => [
|
||||
'@entity@' => V1Controller::OBJECT_TYPE_STORY_METADATA_BAG,
|
||||
'dc:contributor' => $format($caption, \databox_Field_DCESAbstract::Contributor),
|
||||
'dc:coverage' => $format($caption, \databox_Field_DCESAbstract::Coverage),
|
||||
'dc:creator' => $format($caption, \databox_Field_DCESAbstract::Creator),
|
||||
'dc:date' => $format($caption, \databox_Field_DCESAbstract::Date),
|
||||
'dc:description' => $format($caption, \databox_Field_DCESAbstract::Description),
|
||||
'dc:format' => $format($caption, \databox_Field_DCESAbstract::Format),
|
||||
'dc:identifier' => $format($caption, \databox_Field_DCESAbstract::Identifier),
|
||||
'dc:language' => $format($caption, \databox_Field_DCESAbstract::Language),
|
||||
'dc:publisher' => $format($caption, \databox_Field_DCESAbstract::Publisher),
|
||||
'dc:relation' => $format($caption, \databox_Field_DCESAbstract::Relation),
|
||||
'dc:rights' => $format($caption, \databox_Field_DCESAbstract::Rights),
|
||||
'dc:source' => $format($caption, \databox_Field_DCESAbstract::Source),
|
||||
'dc:subject' => $format($caption, \databox_Field_DCESAbstract::Subject),
|
||||
'dc:title' => $format($caption, \databox_Field_DCESAbstract::Title),
|
||||
'dc:type' => $format($caption, \databox_Field_DCESAbstract::Type),
|
||||
],
|
||||
'records' => $this->listRecords($request, array_values($story->getChildren($offset, $per_page)->get_elements())),
|
||||
];
|
||||
}
|
||||
|
||||
private function listEmbeddableMedia(Request $request, \record_adapter $record, \media_subdef $media)
|
||||
{
|
||||
if (!$media->is_physically_present()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->getAuthenticator()->isAuthenticated()) {
|
||||
$acl = $this->getAclForUser();
|
||||
if ($media->get_name() !== 'document'
|
||||
&& false === $acl->has_access_to_subdef($record, $media->get_name())
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
if ($media->get_name() === 'document'
|
||||
&& !$acl->has_right_on_base($record->getBaseId(), \ACL::CANDWNLDHD)
|
||||
&& !$acl->has_hd_grant($record)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($media->get_permalink() instanceof \media_Permalink_Adapter) {
|
||||
$permalink = $this->listPermalink($media->get_permalink());
|
||||
} else {
|
||||
$permalink = null;
|
||||
}
|
||||
|
||||
$urlTTL = (int) $request->get(
|
||||
'subdef_url_ttl',
|
||||
$this->getConf()->get(['registry', 'general', 'default-subdef-url-ttl'])
|
||||
);
|
||||
if ($urlTTL < 0) {
|
||||
$urlTTL = -1;
|
||||
}
|
||||
$issuer = $this->getAuthenticatedUser();
|
||||
|
||||
return [
|
||||
'name' => $media->get_name(),
|
||||
'permalink' => $permalink,
|
||||
'height' => $media->get_height(),
|
||||
'width' => $media->get_width(),
|
||||
'filesize' => $media->get_size(),
|
||||
'devices' => $media->getDevices(),
|
||||
'player_type' => $media->get_type(),
|
||||
'mime_type' => $media->get_mime(),
|
||||
'substituted' => $media->is_substituted(),
|
||||
'created_on' => $media->get_creation_date()->format(DATE_ATOM),
|
||||
'updated_on' => $media->get_modification_date()->format(DATE_ATOM),
|
||||
'url' => $this->app['media_accessor.subdef_url_generator']->generate($issuer, $media, $urlTTL),
|
||||
'url_ttl' => $urlTTL,
|
||||
];
|
||||
}
|
||||
|
||||
private function listPermalink(\media_Permalink_Adapter $permalink)
|
||||
{
|
||||
$downloadUrl = $permalink->get_url();
|
||||
$downloadUrl->getQuery()->set('download', '1');
|
||||
|
||||
return [
|
||||
'created_on' => $permalink->get_created_on()->format(DATE_ATOM),
|
||||
'id' => $permalink->get_id(),
|
||||
'is_activated' => $permalink->get_is_activated(),
|
||||
/** @Ignore */
|
||||
'label' => $permalink->get_label(),
|
||||
'updated_on' => $permalink->get_last_modified()->format(DATE_ATOM),
|
||||
'page_url' => $permalink->get_page(),
|
||||
'download_url' => (string)$downloadUrl,
|
||||
'url' => (string)$permalink->get_url(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param RecordReferenceInterface[]|RecordReferenceCollection $records
|
||||
* @return array
|
||||
*/
|
||||
private function listRecords(Request $request, $records)
|
||||
{
|
||||
if (!$records instanceof RecordReferenceCollection) {
|
||||
$records = new RecordReferenceCollection($records);
|
||||
}
|
||||
|
||||
$technicalData = $this->app['service.technical_data']->fetchRecordsTechnicalData($records);
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($records->toRecords($this->getApplicationBox()) as $index => $record) {
|
||||
$record->setTechnicalDataSet($technicalData[$index]);
|
||||
|
||||
$data[$index] = $this->listRecord($request, $record);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve detailed information about one record
|
||||
*
|
||||
* @param Request $request
|
||||
* @param \record_adapter $record
|
||||
* @return array
|
||||
*/
|
||||
private function listRecord(Request $request, \record_adapter $record)
|
||||
{
|
||||
$technicalInformation = [];
|
||||
foreach ($record->get_technical_infos()->getValues() as $name => $value) {
|
||||
$technicalInformation[] = ['name' => $name, 'value' => $value];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'databox_id' => $record->getDataboxId(),
|
||||
'record_id' => $record->getRecordId(),
|
||||
'mime_type' => $record->getMimeType(),
|
||||
'title' => $record->get_title(),
|
||||
'original_name' => $record->get_original_name(),
|
||||
'updated_on' => $record->getUpdated()->format(DATE_ATOM),
|
||||
'created_on' => $record->getCreated()->format(DATE_ATOM),
|
||||
'collection_id' => $record->getCollectionId(),
|
||||
'base_id' => $record->getBaseId(),
|
||||
'sha256' => $record->getSha256(),
|
||||
'thumbnail' => $this->listEmbeddableMedia($request, $record, $record->get_thumbnail()),
|
||||
'technical_informations' => $technicalInformation,
|
||||
'phrasea_type' => $record->getType(),
|
||||
'uuid' => $record->getUuid(),
|
||||
];
|
||||
|
||||
if ($request->attributes->get('_extended', false)) {
|
||||
$data = array_merge($data, [
|
||||
'subdefs' => $this->listRecordEmbeddableMedias($request, $record),
|
||||
'metadata' => $this->listRecordMetadata($record),
|
||||
'status' => $this->listRecordStatus($record),
|
||||
'caption' => $this->listRecordCaption($record),
|
||||
]);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param \record_adapter $record
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordEmbeddableMedias(Request $request, \record_adapter $record)
|
||||
{
|
||||
$subdefs = [];
|
||||
|
||||
foreach ($record->get_embedable_medias([], []) as $name => $media) {
|
||||
if (null !== $subdef = $this->listEmbeddableMedia($request, $record, $media)) {
|
||||
$subdefs[] = $subdef;
|
||||
}
|
||||
}
|
||||
|
||||
return $subdefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all fields of given record
|
||||
*
|
||||
* @param \record_adapter $record
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordMetadata(\record_adapter $record)
|
||||
{
|
||||
$includeBusiness = $this->getAclForUser()->can_see_business_fields($record->getDatabox());
|
||||
|
||||
return $this->listRecordCaptionFields($record->get_caption()->get_fields(null, $includeBusiness));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \caption_field[] $fields
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordCaptionFields($fields)
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$databox_field = $field->get_databox_field();
|
||||
|
||||
$fieldData = [
|
||||
'meta_structure_id' => $field->get_meta_struct_id(),
|
||||
'name' => $field->get_name(),
|
||||
'labels' => [
|
||||
'fr' => $databox_field->get_label('fr'),
|
||||
'en' => $databox_field->get_label('en'),
|
||||
'de' => $databox_field->get_label('de'),
|
||||
'nl' => $databox_field->get_label('nl'),
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($field->get_values() as $value) {
|
||||
$data = [
|
||||
'meta_id' => $value->getId(),
|
||||
'value' => $value->getValue(),
|
||||
];
|
||||
|
||||
$ret[] = $fieldData + $data;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve detailed information about one status
|
||||
*
|
||||
* @param \record_adapter $record
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordStatus(\record_adapter $record)
|
||||
{
|
||||
$ret = [];
|
||||
foreach ($record->getStatusStructure() as $bit => $status) {
|
||||
$ret[] = [
|
||||
'bit' => $bit,
|
||||
'state' => \databox_status::bitIsSet($record->getStatusBitField(), $bit),
|
||||
];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \record_adapter $record
|
||||
* @return array
|
||||
*/
|
||||
private function listRecordCaption(\record_adapter $record)
|
||||
{
|
||||
$includeBusiness = $this->getAclForUser()->can_see_business_fields($record->getDatabox());
|
||||
|
||||
$caption = [];
|
||||
|
||||
foreach ($record->get_caption()->get_fields(null, $includeBusiness) as $field) {
|
||||
$caption[] = [
|
||||
'meta_structure_id' => $field->get_meta_struct_id(),
|
||||
'name' => $field->get_name(),
|
||||
'value' => $field->get_serialized_values(';'),
|
||||
];
|
||||
}
|
||||
|
||||
return $caption;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns requested includes
|
||||
*
|
||||
* @param Request $request
|
||||
@@ -660,7 +341,7 @@ class V3Controller extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RecordCollection|\record_adapter[] $references
|
||||
* @param RecordCollection|record_adapter[] $references
|
||||
* @return RecordView[]
|
||||
*/
|
||||
private function buildRecordViews($references)
|
||||
@@ -693,7 +374,7 @@ class V3Controller extends Controller
|
||||
|
||||
foreach ($subdefGroups as $index => $subdefGroup) {
|
||||
if (!isset($subdefGroup['thumbnail'])) {
|
||||
$fakeSubdef = new \media_subdef($this->app, $references[$index], 'thumbnail', true, []);
|
||||
$fakeSubdef = new media_subdef($this->app, $references[$index], 'thumbnail', true, []);
|
||||
$fakeSubdefs[spl_object_hash($fakeSubdef)] = $fakeSubdef;
|
||||
|
||||
$subdefGroups[$index]['thumbnail'] = $fakeSubdef;
|
||||
@@ -701,9 +382,9 @@ class V3Controller extends Controller
|
||||
}
|
||||
|
||||
$allSubdefs = $this->mergeGroupsIntoOneList($subdefGroups);
|
||||
$allPermalinks = \media_Permalink_Adapter::getMany(
|
||||
$allPermalinks = media_Permalink_Adapter::getMany(
|
||||
$this->app,
|
||||
array_filter($allSubdefs, function (\media_subdef $subdef) use ($fakeSubdefs) {
|
||||
array_filter($allSubdefs, function (media_subdef $subdef) use ($fakeSubdefs) {
|
||||
return !isset($fakeSubdefs[spl_object_hash($subdef)]);
|
||||
})
|
||||
);
|
||||
@@ -712,7 +393,7 @@ class V3Controller extends Controller
|
||||
|
||||
$subdefViews = [];
|
||||
|
||||
/** @var \media_subdef $subdef */
|
||||
/** @var media_subdef $subdef */
|
||||
foreach ($allSubdefs as $index => $subdef) {
|
||||
$subdefView = new SubdefView($subdef);
|
||||
|
||||
@@ -728,7 +409,7 @@ class V3Controller extends Controller
|
||||
|
||||
$reorderedGroups = [];
|
||||
|
||||
/** @var \media_subdef[] $subdefGroup */
|
||||
/** @var media_subdef[] $subdefGroup */
|
||||
foreach ($subdefGroups as $index => $subdefGroup) {
|
||||
$reordered = [];
|
||||
|
||||
@@ -789,7 +470,7 @@ class V3Controller extends Controller
|
||||
|
||||
/**
|
||||
* @param RecordView[] $recordViews
|
||||
* @param \caption_record[] $captions
|
||||
* @param caption_record[] $captions
|
||||
* @param bool[] $canSeeBusiness
|
||||
*/
|
||||
private function buildCaptionViews($recordViews, $captions, $canSeeBusiness)
|
146
lib/Alchemy/Phrasea/Controller/Api/V3/V3StoriesController.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Controller\Api\V3;
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\DispatcherAware;
|
||||
use Alchemy\Phrasea\Application\Helper\JsonBodyAware;
|
||||
use Alchemy\Phrasea\Controller\Api\Result;
|
||||
use Alchemy\Phrasea\Controller\Api\V1Controller;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\Model\RecordReferenceInterface;
|
||||
use Alchemy\Phrasea\Record\RecordReferenceCollection;
|
||||
use caption_record;
|
||||
use databox_Field_DCESAbstract;
|
||||
use Exception;
|
||||
use record_adapter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
|
||||
class V3StoriesController extends Controller
|
||||
{
|
||||
use JsonBodyAware;
|
||||
use DispatcherAware;
|
||||
|
||||
/**
|
||||
* Return detailed information about one story
|
||||
*
|
||||
* @param Request $request
|
||||
* @param int $databox_id
|
||||
* @param int $record_id
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getStoryAction(Request $request, $databox_id, $record_id)
|
||||
{
|
||||
try {
|
||||
$story = $this->findDataboxById($databox_id)->get_record($record_id);
|
||||
|
||||
return Result::create($request, ['story' => $this->listStory($request, $story)])->createResponse();
|
||||
}
|
||||
catch (NotFoundHttpException $e) {
|
||||
return Result::createError($request, 404, 'Story Not Found')->createResponse();
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return $this->app['controller.api.v1']->getBadRequestAction($request, 'An error occurred');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve detailed information about one story
|
||||
*
|
||||
* @param Request $request
|
||||
* @param record_adapter $story
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function listStory(Request $request, record_adapter $story)
|
||||
{
|
||||
if (!$story->isStory()) {
|
||||
return Result::createError($request, 404, 'Story not found')->createResponse();
|
||||
}
|
||||
|
||||
$per_page = (int)$request->get('per_page')?:10;
|
||||
$page = (int)$request->get('page')?:1;
|
||||
$offset = ($per_page * ($page - 1)) + 1;
|
||||
|
||||
$caption = $story->get_caption();
|
||||
|
||||
$format = function (caption_record $caption, $dcField) {
|
||||
|
||||
$field = $caption->get_dc_field($dcField);
|
||||
|
||||
if (!$field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $field->get_serialized_values();
|
||||
};
|
||||
|
||||
return [
|
||||
'@entity@' => V1Controller::OBJECT_TYPE_STORY,
|
||||
'databox_id' => $story->getDataboxId(),
|
||||
'story_id' => $story->getRecordId(),
|
||||
'updated_on' => $story->getUpdated()->format(DATE_ATOM),
|
||||
'created_on' => $story->getCreated()->format(DATE_ATOM),
|
||||
'collection_id' => $story->getCollectionId(),
|
||||
'base_id' => $story->getBaseId(),
|
||||
'thumbnail' => $this->getResultHelpers()->listEmbeddableMedia($request, $story, $story->get_thumbnail(), $this->getAclForUser()),
|
||||
'uuid' => $story->getUuid(),
|
||||
'metadatas' => [
|
||||
'@entity@' => V1Controller::OBJECT_TYPE_STORY_METADATA_BAG,
|
||||
'dc:contributor' => $format($caption, databox_Field_DCESAbstract::Contributor),
|
||||
'dc:coverage' => $format($caption, databox_Field_DCESAbstract::Coverage),
|
||||
'dc:creator' => $format($caption, databox_Field_DCESAbstract::Creator),
|
||||
'dc:date' => $format($caption, databox_Field_DCESAbstract::Date),
|
||||
'dc:description' => $format($caption, databox_Field_DCESAbstract::Description),
|
||||
'dc:format' => $format($caption, databox_Field_DCESAbstract::Format),
|
||||
'dc:identifier' => $format($caption, databox_Field_DCESAbstract::Identifier),
|
||||
'dc:language' => $format($caption, databox_Field_DCESAbstract::Language),
|
||||
'dc:publisher' => $format($caption, databox_Field_DCESAbstract::Publisher),
|
||||
'dc:relation' => $format($caption, databox_Field_DCESAbstract::Relation),
|
||||
'dc:rights' => $format($caption, databox_Field_DCESAbstract::Rights),
|
||||
'dc:source' => $format($caption, databox_Field_DCESAbstract::Source),
|
||||
'dc:subject' => $format($caption, databox_Field_DCESAbstract::Subject),
|
||||
'dc:title' => $format($caption, databox_Field_DCESAbstract::Title),
|
||||
'dc:type' => $format($caption, databox_Field_DCESAbstract::Type),
|
||||
],
|
||||
'records' => $this->listRecords($request, array_values($story->getChildren($offset, $per_page)->get_elements())),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param RecordReferenceInterface[]|RecordReferenceCollection $records
|
||||
* @return array
|
||||
*/
|
||||
private function listRecords(Request $request, $records)
|
||||
{
|
||||
if (!$records instanceof RecordReferenceCollection) {
|
||||
$records = new RecordReferenceCollection($records);
|
||||
}
|
||||
|
||||
$technicalData = $this->app['service.technical_data']->fetchRecordsTechnicalData($records);
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($records->toRecords($this->getApplicationBox()) as $index => $record) {
|
||||
$record->setTechnicalDataSet($technicalData[$index]);
|
||||
|
||||
$data[$index] = $this->getResultHelpers()->listRecord($request, $record, $this->getAclForUser());
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return V3ResultHelpers
|
||||
*/
|
||||
private function getResultHelpers()
|
||||
{
|
||||
return $this->app['controller.api.v3.resulthelpers'];
|
||||
}
|
||||
|
||||
}
|
@@ -155,6 +155,8 @@ class LanguageController
|
||||
'description notice' => $translator->trans('prod:mapboxgl: description notice'),
|
||||
'title-map-dialog' => $translator->trans('prod:mapboxgl: title map dialog'),
|
||||
'create new user' => $translator->trans('prod:push: create new user'),
|
||||
'prod:videoeditor:subtitletab:message:: error' => $translator->trans('prod:videoeditor:subtitletab:message:: error'),
|
||||
'prod:videoeditor:subtitletab:message:: success' => $translator->trans('prod:videoeditor:subtitletab:message:: success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -115,13 +115,13 @@ class MoveCollectionController extends Controller
|
||||
|
||||
foreach ($records as $record) {
|
||||
$oldCollectionId = $record->getCollection()->get_coll_id();
|
||||
$record->move_to_collection($collection, $this->getApplicationBox());
|
||||
$record->move_to_collection($collection);
|
||||
|
||||
if ($request->request->get("chg_coll_son") == "1") {
|
||||
/** @var \record_adapter $child */
|
||||
foreach ($record->getChildren() as $child) {
|
||||
if ($this->getAclForUser()->has_right_on_base($child->getBaseId(), \ACL::CANDELETERECORD)) {
|
||||
$child->move_to_collection($collection, $this->getApplicationBox());
|
||||
$child->move_to_collection($collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -242,7 +242,7 @@ class RecordController extends Controller
|
||||
$this->getEventDispatcher()->dispatch(RecordEvents::DELETE, new DeleteEvent($record));
|
||||
} else {
|
||||
// move to trash collection
|
||||
$record->move_to_collection($trashCollectionsBySbasId[$sbasId], $this->getApplicationBox());
|
||||
$record->move_to_collection($trashCollectionsBySbasId[$sbasId]);
|
||||
// disable permalinks
|
||||
foreach($record->get_subdefs() as $subdef) {
|
||||
if( ($pl = $subdef->get_permalink()) ) {
|
||||
|
@@ -15,8 +15,10 @@ use Alchemy\Phrasea\Application\Helper\FilesystemAware;
|
||||
use Alchemy\Phrasea\Application\Helper\SubDefinitionSubstituerAware;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\Controller\RecordsRequest;
|
||||
use Alchemy\Phrasea\Core\Event\Record\RecordAutoSubtitleEvent;
|
||||
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
|
||||
use Alchemy\Phrasea\Core\Event\Record\SubdefinitionCreateEvent;
|
||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Alchemy\Phrasea\Metadata\PhraseanetMetadataReader;
|
||||
use Alchemy\Phrasea\Metadata\PhraseanetMetadataSetter;
|
||||
@@ -24,7 +26,6 @@ use Alchemy\Phrasea\Record\RecordWasRotated;
|
||||
use DataURI\Parser;
|
||||
use MediaAlchemyst\Alchemyst;
|
||||
use MediaVorus\MediaVorus;
|
||||
use PHPExiftool\Reader;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ToolsController extends Controller
|
||||
@@ -45,7 +46,6 @@ class ToolsController extends Controller
|
||||
if (count($records) == 1) {
|
||||
/** @var \record_adapter $record */
|
||||
$record = $records->first();
|
||||
$databox = $record->getDatabox();
|
||||
|
||||
/**Array list of subdefs**/
|
||||
$listsubdef = array_keys($record-> get_subdefs());
|
||||
@@ -88,14 +88,13 @@ class ToolsController extends Controller
|
||||
$metadatas = true;
|
||||
}
|
||||
}
|
||||
$conf = $this->getConf();
|
||||
|
||||
return $this->render('prod/actions/Tools/index.html.twig', [
|
||||
'records' => $records,
|
||||
'record' => $record,
|
||||
'recordSubdefs' => $recordAccessibleSubdefs,
|
||||
'metadatas' => $metadatas,
|
||||
'listsubdef' => $listsubdef
|
||||
'listsubdef' => $listsubdef
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -118,6 +117,7 @@ class ToolsController extends Controller
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
/** @var \media_subdef $subdef */
|
||||
foreach ($record->get_subdefs() as $subdef) {
|
||||
if ($subdef->get_type() !== \media_subdef::TYPE_IMAGE) {
|
||||
continue;
|
||||
@@ -146,6 +146,7 @@ class ToolsController extends Controller
|
||||
|
||||
foreach ($selection as $record) {
|
||||
$substituted = false;
|
||||
/** @var \media_subdef $subdef */
|
||||
foreach ($record->get_subdefs() as $subdef) {
|
||||
if ($subdef->is_substituted()) {
|
||||
$substituted = true;
|
||||
@@ -362,14 +363,6 @@ class ToolsController extends Controller
|
||||
return $this->app->json($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Reader
|
||||
*/
|
||||
private function getExifToolReader()
|
||||
{
|
||||
return $this->app['exiftool.reader'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Alchemyst
|
||||
*/
|
||||
@@ -449,13 +442,45 @@ class ToolsController extends Controller
|
||||
try {
|
||||
$record->set_metadatas($metadatas);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
catch (\Exception $e) {
|
||||
return $this->app->json(['success' => false, 'errorMessage' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
return $this->app->json(['success' => true, 'errorMessage' => '']);
|
||||
}
|
||||
|
||||
public function autoSubtitleAction(Request $request)
|
||||
{
|
||||
$record = new \record_adapter($this->app,
|
||||
(int)$request->request->get("databox_id"),
|
||||
(int)$request->request->get("record_id")
|
||||
);
|
||||
|
||||
$permalinkUrl = '';
|
||||
$conf = $this->getConf();
|
||||
|
||||
// if subdef_source not set, by default use the preview permalink
|
||||
$subdefSource = $conf->get(['externalservice', 'ginger', 'AutoSubtitling', 'subdef_source']) ?: 'preview';
|
||||
|
||||
if ($this->isPhysicallyPresent($record, $subdefSource) && ($previewLink = $record->get_subdef($subdefSource)->get_permalink()) != null) {
|
||||
$permalinkUrl = $previewLink->get_url()->__toString();
|
||||
}
|
||||
|
||||
$this->dispatch(
|
||||
PhraseaEvents::RECORD_AUTO_SUBTITLE,
|
||||
new RecordAutoSubtitleEvent(
|
||||
$record,
|
||||
$permalinkUrl,
|
||||
$request->request->get("subtitle_language_source"),
|
||||
$request->request->get("meta_struct_id_source"),
|
||||
$request->request->get("subtitle_language_destination"),
|
||||
$request->request->get("meta_struct_id_destination")
|
||||
)
|
||||
);
|
||||
|
||||
return $this->app->json(["status" => "dispatch"]);
|
||||
}
|
||||
|
||||
public function videoEditorAction(Request $request)
|
||||
{
|
||||
$records = RecordsRequest::fromRequest($this->app, $request, false);
|
||||
@@ -463,6 +488,7 @@ class ToolsController extends Controller
|
||||
$metadatas = false;
|
||||
$record = null;
|
||||
$JSFields = [];
|
||||
$videoTextTrackFields = [];
|
||||
|
||||
if (count($records) == 1) {
|
||||
/** @var \record_adapter $record */
|
||||
@@ -480,6 +506,19 @@ class ToolsController extends Controller
|
||||
'name' => $meta->get_name(),
|
||||
'_value' => $record->getCaption([$meta->get_name()]),
|
||||
];
|
||||
|
||||
if (preg_match('/^VideoTextTrack(.*)$/iu', $meta->get_name(), $matches) && !empty($matches[1]) && strlen($matches[1]) == 2 ) {
|
||||
$field['label'] = $matches[1];
|
||||
$field['meta_struct_id'] = $meta->get_id();
|
||||
$field['value'] = '';
|
||||
if ($record->get_caption()->has_field($meta->get_name())) {
|
||||
$fieldValues = $record->get_caption()->get_field($meta->get_name())->get_values();
|
||||
$fieldValue = array_pop($fieldValues);
|
||||
$field['value'] = $fieldValue->getValue();
|
||||
}
|
||||
$videoTextTrackFields[$meta->get_id()] = $field;
|
||||
unset($field);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$record->isStory()) {
|
||||
@@ -489,11 +528,23 @@ class ToolsController extends Controller
|
||||
$conf = $this->getConf();
|
||||
|
||||
return $this->render('prod/actions/Tools/videoEditor.html.twig', [
|
||||
'records' => $records,
|
||||
'record' => $record,
|
||||
'videoEditorConfig' => $conf->get(['video-editor']),
|
||||
'metadatas' => $metadatas,
|
||||
'JSonFields' => json_encode($JSFields),
|
||||
'records' => $records,
|
||||
'record' => $record,
|
||||
'videoEditorConfig' => $conf->get(['video-editor']),
|
||||
'metadatas' => $metadatas,
|
||||
'JSonFields' => json_encode($JSFields),
|
||||
'videoTextTrackFields' => $videoTextTrackFields
|
||||
]);
|
||||
}
|
||||
|
||||
private function isPhysicallyPresent(\record_adapter $record, $subdefName)
|
||||
{
|
||||
try {
|
||||
return $record->get_subdef($subdefName)->is_physically_present();
|
||||
} catch (\Exception $e) {
|
||||
unset($e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,9 @@ use Alchemy\Phrasea\Application\Helper\DispatcherAware;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\Core\Event\Thesaurus as ThesaurusEvent;
|
||||
use Alchemy\Phrasea\Core\Event\Thesaurus\ThesaurusEvents;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\PopulateIndexEvent;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
||||
use Doctrine\DBAL\Driver\Connection;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@@ -1222,6 +1225,26 @@ class ThesaurusController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order to populate databox
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
*/
|
||||
public function populate(Request $request)
|
||||
{
|
||||
$options = $this->getElasticsearchOptions();
|
||||
|
||||
$data['host'] = $options->getHost();
|
||||
$data['port'] = $options->getPort();
|
||||
$data['indexName'] = $options->getIndexName();
|
||||
$data['databoxIds'] = [$request->get('databox_id')];
|
||||
|
||||
$this->getDispatcher()->dispatch(WorkerEvents::POPULATE_INDEX, new PopulateIndexEvent($data));
|
||||
|
||||
return $this->app->json(["status" => "success"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
@@ -3031,4 +3054,12 @@ class ThesaurusController extends Controller
|
||||
{
|
||||
return $this->app['locales.available'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ElasticsearchOptions
|
||||
*/
|
||||
private function getElasticsearchOptions()
|
||||
{
|
||||
return $this->app['elasticsearch.options'];
|
||||
}
|
||||
}
|
||||
|
@@ -3,21 +3,41 @@
|
||||
namespace Alchemy\Phrasea\ControllerProvider\Api;
|
||||
|
||||
use Alchemy\Phrasea\Application as PhraseaApplication;
|
||||
use Alchemy\Phrasea\Controller\Api\V3Controller;
|
||||
use Alchemy\Phrasea\Controller\Api\V3\V3RecordController;
|
||||
use Alchemy\Phrasea\Controller\Api\V3\V3ResultHelpers;
|
||||
use Alchemy\Phrasea\Controller\Api\V3\V3SearchController;
|
||||
use Alchemy\Phrasea\Controller\Api\V3\V3StoriesController;
|
||||
use Alchemy\Phrasea\Core\Event\Listener\OAuthListener;
|
||||
use Silex\Application;
|
||||
use Silex\ControllerCollection;
|
||||
use Silex\ControllerProviderInterface;
|
||||
use Silex\ServiceProviderInterface;
|
||||
|
||||
|
||||
class V3 extends Api implements ControllerProviderInterface, ServiceProviderInterface
|
||||
{
|
||||
const VERSION = '3.0.0';
|
||||
|
||||
public function register(Application $app)
|
||||
{
|
||||
$app['controller.api.v3'] = $app->share(function (PhraseaApplication $app) {
|
||||
return (new V3Controller($app));
|
||||
$app['controller.api.v3.resulthelpers'] = $app->share(function (PhraseaApplication $app) {
|
||||
return (new V3ResultHelpers(
|
||||
$app['conf'],
|
||||
$app['media_accessor.subdef_url_generator'],
|
||||
$app['authentication']
|
||||
));
|
||||
});
|
||||
$app['controller.api.v3.metadatas'] = $app->share(function (PhraseaApplication $app) {
|
||||
return (new V3RecordController($app))
|
||||
->setJsonBodyHelper($app['json.body_helper'])
|
||||
->setDispatcher($app['dispatcher'])
|
||||
;
|
||||
});
|
||||
$app['controller.api.v3.search'] = $app->share(function (PhraseaApplication $app) {
|
||||
return (new V3SearchController($app));
|
||||
});
|
||||
$app['controller.api.v3.stories'] = $app->share(function (PhraseaApplication $app) {
|
||||
return (new V3StoriesController($app));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,12 +56,32 @@ class V3 extends Api implements ControllerProviderInterface, ServiceProviderInte
|
||||
|
||||
$controllers->before(new OAuthListener());
|
||||
|
||||
$controllers->get('/stories/{databox_id}/{record_id}/', 'controller.api.v3:getStoryAction')
|
||||
/**
|
||||
* @uses V3StoriesController::getStoryAction()
|
||||
*/
|
||||
$controllers->get('/stories/{databox_id}/{record_id}/', 'controller.api.v3.stories:getStoryAction')
|
||||
->before('controller.api.v1:ensureCanAccessToRecord')
|
||||
->assert('databox_id', '\d+')
|
||||
->assert('record_id', '\d+');
|
||||
|
||||
$controllers->match('/search/', 'controller.api.v3:searchAction');
|
||||
/**
|
||||
* @uses V3SearchController::searchAction()
|
||||
*/
|
||||
$controllers->match('/search/', 'controller.api.v3.search:searchAction');
|
||||
|
||||
/**
|
||||
* @uses V3RecordController::indexAction_patch()
|
||||
*/
|
||||
$controllers->patch('/records/{databox_id}/{record_id}/', 'controller.api.v3.metadatas:indexAction_patch')
|
||||
->before('controller.api.v1:ensureCanAccessToRecord')
|
||||
->before('controller.api.v1:ensureCanModifyRecord')
|
||||
->assert('databox_id', '\d+')
|
||||
->assert('record_id', '\d+');
|
||||
|
||||
/**
|
||||
* @uses \Alchemy\Phrasea\Controller\Api\V1Controller::getBadRequestAction()
|
||||
*/
|
||||
$controllers->match('/records/{any_id}/{anyother_id}/setmetadatas/', 'controller.api.v1:getBadRequestAction');
|
||||
|
||||
return $controllers;
|
||||
}
|
||||
|
@@ -72,6 +72,9 @@ class Tools implements ControllerProviderInterface, ServiceProviderInterface
|
||||
$controllers->post('/metadata/save/', 'controller.prod.tools:saveMetasAction')
|
||||
->bind('prod_tools_metadata_save');
|
||||
|
||||
$controllers->post('/auto-subtitle/', 'controller.prod.tools:autoSubtitleAction')
|
||||
->bind('prod_tools_auto_subtitle');
|
||||
|
||||
$controllers->get('/videoEditor', 'controller.prod.tools:videoEditorAction');
|
||||
|
||||
return $controllers;
|
||||
|
@@ -60,6 +60,7 @@ class Thesaurus implements ControllerProviderInterface, ServiceProviderInterface
|
||||
$controllers->match('newterm.php', 'controller.thesaurus:newTerm');
|
||||
$controllers->match('properties.php', 'controller.thesaurus:properties');
|
||||
$controllers->match('thesaurus.php', 'controller.thesaurus:thesaurus')->bind('thesaurus_thesaurus');
|
||||
$controllers->match('populate', 'controller.thesaurus:populate')->bind('thesaurus_populate');
|
||||
|
||||
$controllers->match('xmlhttp/accept.x.php', 'controller.thesaurus:acceptXml');
|
||||
$controllers->match('xmlhttp/acceptcandidates.x.php', 'controller.thesaurus:acceptCandidatesXml');
|
||||
|
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Core\Event\Record;
|
||||
|
||||
use Alchemy\Phrasea\Model\RecordInterface;
|
||||
|
||||
class RecordAutoSubtitleEvent extends RecordEvent
|
||||
{
|
||||
private $languageSource;
|
||||
private $metaStructureIdSource;
|
||||
private $languageDestination;
|
||||
private $metaStructureIdDestination;
|
||||
private $permalinkUrl;
|
||||
|
||||
public function __construct(
|
||||
RecordInterface $record,
|
||||
$permalinkUrl,
|
||||
$languageSource,
|
||||
$metaStructureIdSource,
|
||||
$languageDestination,
|
||||
$metaStructureIdDestination
|
||||
)
|
||||
{
|
||||
parent::__construct($record);
|
||||
|
||||
$this->languageSource = $languageSource;
|
||||
$this->metaStructureIdSource = $metaStructureIdSource;
|
||||
$this->languageDestination = $languageDestination;
|
||||
$this->metaStructureIdDestination = $metaStructureIdDestination;
|
||||
$this->permalinkUrl = $permalinkUrl;
|
||||
}
|
||||
|
||||
public function getLanguageSource()
|
||||
{
|
||||
return $this->languageSource;
|
||||
}
|
||||
|
||||
public function getMetaStructureIdSource()
|
||||
{
|
||||
return $this->metaStructureIdSource;
|
||||
}
|
||||
|
||||
public function getLanguageDestination()
|
||||
{
|
||||
return $this->languageDestination;
|
||||
}
|
||||
|
||||
public function getMetaStructureIdDestination()
|
||||
{
|
||||
return $this->metaStructureIdDestination;
|
||||
}
|
||||
|
||||
public function getPermalinkUrl()
|
||||
{
|
||||
return $this->permalinkUrl;
|
||||
}
|
||||
}
|
@@ -5,7 +5,6 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Record\RecordEvents;
|
||||
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreatedEvent;
|
||||
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationFailedEvent;
|
||||
use Alchemy\Phrasea\Core\Event\Record\SubDefinitionsCreatedEvent;
|
||||
use Alchemy\Phrasea\Model\Entities\WebhookEvent;
|
||||
use Silex\Application;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
@@ -30,7 +29,8 @@ class WebhookSubdefEventSubscriber implements EventSubscriberInterface
|
||||
$this->app['manipulator.webhook-event']->create(
|
||||
WebhookEvent::RECORD_SUBDEF_CREATED,
|
||||
WebhookEvent::RECORD_SUBDEF_TYPE,
|
||||
$eventData
|
||||
$eventData,
|
||||
[$event->getRecord()->getBaseId()]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,22 +45,8 @@ class WebhookSubdefEventSubscriber implements EventSubscriberInterface
|
||||
$this->app['manipulator.webhook-event']->create(
|
||||
WebhookEvent::RECORD_SUBDEF_FAILED,
|
||||
WebhookEvent::RECORD_SUBDEF_TYPE,
|
||||
$eventData
|
||||
);
|
||||
}
|
||||
|
||||
public function onSubdefsCreated(SubDefinitionsCreatedEvent $event)
|
||||
{
|
||||
$eventData = [
|
||||
'databox_id' => $event->getRecord()->getDataboxId(),
|
||||
'record_id' => $event->getRecord()->getRecordId(),
|
||||
'subdef_count' => count($event->getMedia())
|
||||
];
|
||||
|
||||
$this->app['manipulator.webhook-event']->create(
|
||||
WebhookEvent::RECORD_SUBDEFS_CREATED,
|
||||
WebhookEvent::RECORD_SUBDEF_TYPE,
|
||||
$eventData
|
||||
$eventData,
|
||||
[$event->getRecord()->getBaseId()]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,7 +54,6 @@ class WebhookSubdefEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
return [
|
||||
RecordEvents::SUB_DEFINITION_CREATED => 'onSubdefCreated',
|
||||
RecordEvents::SUB_DEFINITIONS_CREATED => 'onSubdefsCreated',
|
||||
RecordEvents::SUB_DEFINITION_CREATION_FAILED => 'onSubdefCreationFailed'
|
||||
];
|
||||
}
|
||||
|
@@ -54,6 +54,8 @@ final class PhraseaEvents
|
||||
const RECORD_EDIT = 'record.edit';
|
||||
const RECORD_UPLOAD = 'record.upload';
|
||||
|
||||
const RECORD_AUTO_SUBTITLE = 'record.auto-subtitle';
|
||||
|
||||
const THESAURUS_IMPORTED = 'thesaurus.imported';
|
||||
const THESAURUS_FIELD_LINKED = 'thesaurus.field-linked';
|
||||
const THESAURUS_CANDIDATE_ACCEPTED_AS_CONCEPT = 'thesaurus.candidate-accepted-as-concept';
|
||||
|
@@ -150,6 +150,9 @@ class RepositoriesServiceProvider implements ServiceProviderInterface
|
||||
$app['repo.worker-running-job'] = $app->share(function (PhraseaApplication $app) {
|
||||
return $app['orm.em']->getRepository('Phraseanet:WorkerRunningJob');
|
||||
});
|
||||
$app['repo.worker-job'] = $app->share(function (PhraseaApplication $app) {
|
||||
return $app['orm.em']->getRepository('Phraseanet:WorkerJob');
|
||||
});
|
||||
$app['repo.worker-running-populate'] = $app->share(function (PhraseaApplication $app) {
|
||||
return $app['orm.em']->getRepository('Phraseanet:WorkerRunningPopulate');
|
||||
});
|
||||
|
@@ -16,8 +16,7 @@ class Version
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
|
||||
private $number = '4.1.0-alpha.29a';
|
||||
private $number = '4.1.1';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
150
lib/Alchemy/Phrasea/Model/Entities/WorkerJob.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Model\Entities;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Gedmo\Mapping\Annotation as Gedmo;
|
||||
|
||||
/**
|
||||
* @ORM\Table(name="WorkerJob", indexes={@ORM\Index(name="worker_job_type", columns={"type"})})
|
||||
* @ORM\Entity(repositoryClass="Alchemy\Phrasea\Model\Repositories\WorkerJobRepository")
|
||||
*/
|
||||
class WorkerJob
|
||||
{
|
||||
const WAITING = "waiting";
|
||||
const RUNNING = "running";
|
||||
const FINISHED = "finished";
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", name="type")
|
||||
*/
|
||||
private $type;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json_array", name="data", nullable=false)
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", name="status")
|
||||
*/
|
||||
private $status;
|
||||
|
||||
/**
|
||||
* @Gedmo\Timestampable(on="create")
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
private $created;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $started;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $finished;
|
||||
|
||||
/**
|
||||
* @return integer
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return WorkerJob
|
||||
*/
|
||||
public function setData(array $data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStatus()
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getCreated()
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime $finished
|
||||
* @return $this
|
||||
*/
|
||||
public function setFinished(\DateTime $finished)
|
||||
{
|
||||
$this->finished = $finished;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFinished()
|
||||
{
|
||||
return $this->finished;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime $started
|
||||
* @return $this
|
||||
*/
|
||||
public function setStarted(\DateTime $started)
|
||||
{
|
||||
$this->started = $started;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getStarted()
|
||||
{
|
||||
return $this->started;
|
||||
}
|
||||
}
|
@@ -20,6 +20,8 @@ class WorkerRunningJob
|
||||
const FINISHED = 'finished';
|
||||
const RUNNING = 'running';
|
||||
|
||||
const MAX_RESULT = 500;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
|
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Model\Repositories;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
|
||||
class WorkerJobRepository extends EntityRepository
|
||||
{
|
||||
public function getEntityManager()
|
||||
{
|
||||
return parent::getEntityManager();
|
||||
}
|
||||
|
||||
public function reconnect()
|
||||
{
|
||||
if($this->_em->getConnection()->ping() === false) {
|
||||
$this->_em->getConnection()->close();
|
||||
$this->_em->getConnection()->connect();
|
||||
}
|
||||
}
|
||||
}
|
@@ -25,7 +25,6 @@ class PermalinkTransformer extends TransformerAbstract
|
||||
'created_on' => $permalink->get_created_on()->format(DATE_ATOM),
|
||||
'id' => $permalink->get_id(),
|
||||
'is_activated' => $permalink->get_is_activated(),
|
||||
/** @Ignore */
|
||||
'label' => $permalink->get_label(),
|
||||
'updated_on' => $permalink->get_last_modified()->format(DATE_ATOM),
|
||||
'page_url' => $permalink->get_page(),
|
||||
|
@@ -11,13 +11,10 @@
|
||||
|
||||
namespace Alchemy\Phrasea\SearchEngine\Elastic;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\MergeException;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Flag;
|
||||
use appbox;
|
||||
use DateTime;
|
||||
use igorw;
|
||||
use Exception;
|
||||
|
||||
|
||||
class RecordHelper
|
||||
{
|
||||
@@ -100,31 +97,31 @@ class RecordHelper
|
||||
$a = explode(';', preg_replace('/\D+/', ';', trim($value)));
|
||||
switch (count($a)) {
|
||||
case 1: // yyyy
|
||||
$date = new \DateTime($a[0] . '-01-01'); // will throw if date is not valid
|
||||
$date = new DateTime($a[0] . '-01-01'); // will throw if date is not valid
|
||||
$v_fix = $date->format('Y');
|
||||
break;
|
||||
case 2: // yyyy;mm
|
||||
$date = new \DateTime( $a[0] . '-' . $a[1] . '-01');
|
||||
$date = new DateTime( $a[0] . '-' . $a[1] . '-01');
|
||||
$v_fix = $date->format('Y-m');
|
||||
break;
|
||||
case 3: // yyyy;mm;dd
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2]);
|
||||
$date = new DateTime($a[0] . '-' . $a[1] . '-' . $a[2]);
|
||||
$v_fix = $date->format('Y-m-d');
|
||||
break;
|
||||
case 4:
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':00:00');
|
||||
$date = new DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':00:00');
|
||||
$v_fix = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
case 5:
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':00');
|
||||
$date = new DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':00');
|
||||
$v_fix = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
case 6:
|
||||
$date = new \DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':' . $a[5]);
|
||||
$date = new DateTime($a[0] . '-' . $a[1] . '-' . $a[2] . ' ' . $a[3] . ':' . $a[4] . ':' . $a[5]);
|
||||
$v_fix = $date->format('Y-m-d H:i:s');
|
||||
break;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
// no-op, v_fix = null
|
||||
}
|
||||
|
||||
@@ -151,8 +148,16 @@ class RecordHelper
|
||||
return (bool) $value;
|
||||
|
||||
case FieldMapping::TYPE_STRING:
|
||||
$value = substr($value, 0, 32766); // for lucene limit, before a better solution
|
||||
return str_replace("\0", '', $value);
|
||||
$value = str_replace("\0", '', $value); // no null char for lucene !
|
||||
if( strlen($value) > 32766) { // for lucene limit, before a better solution
|
||||
for($l=32766; $l > 0; $l--) {
|
||||
if(ord(substr($value, $l-1, 1)) < 128) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$value = substr($value, 0, $l);
|
||||
}
|
||||
return $value;
|
||||
|
||||
default:
|
||||
return $value;
|
||||
|
@@ -74,7 +74,6 @@ class RecordMoverJob extends AbstractJob
|
||||
|
||||
private function processData(Application $app, $row, $logsql)
|
||||
{
|
||||
/** @var databox $databox */
|
||||
$databox = $app->findDataboxById($row['sbas_id']);
|
||||
$rec = $databox->get_record($row['record_id']);
|
||||
|
||||
@@ -83,7 +82,7 @@ class RecordMoverJob extends AbstractJob
|
||||
// change collection ?
|
||||
if (array_key_exists('coll', $row)) {
|
||||
$coll = \collection::getByCollectionId($app, $databox, $row['coll']);
|
||||
$rec->move_to_collection($coll, $app['phraseanet.appbox']);
|
||||
$rec->move_to_collection($coll);
|
||||
if ($logsql) {
|
||||
$this->log('debug', sprintf("on sbas %s move rid %s to coll %s \n", $row['sbas_id'], $row['record_id'], $coll->get_coll_id()));
|
||||
}
|
||||
|
@@ -23,9 +23,9 @@ class WorkerExecuteCommand extends Command
|
||||
$this->setDescription('Listen queues define on configuration, launch corresponding service for execution')
|
||||
->addOption('preserve-payload', 'p', InputOption::VALUE_NONE, 'Preserve temporary payload file')
|
||||
->addOption('queue-name', '', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'The name of queues to be consuming')
|
||||
->addOption('max-processes', 'm', InputOption::VALUE_REQUIRED, 'The max number of process allow to run (default 4) ')
|
||||
->addOption('MWG', '', InputOption::VALUE_NONE, 'Enable MWG metadata compatibility (use only for write metadata service)')
|
||||
->addOption('clear-metadatas', '', InputOption::VALUE_NONE, 'Delete metadatas from documents if not compliant with Database structure (use only for write metadata service)')
|
||||
->addOption('max-processes', 'm', InputOption::VALUE_REQUIRED, 'The max number of process allow to run (default 1) ')
|
||||
// ->addOption('MWG', '', InputOption::VALUE_NONE, 'Enable MWG metadata compatibility (use only for write metadata service)')
|
||||
// ->addOption('clear-metadatas', '', InputOption::VALUE_NONE, 'Remove metadatas from documents if not compliant with Database structure (use only for write metadata service)')
|
||||
->setHelp('');
|
||||
|
||||
return $this;
|
||||
@@ -33,9 +33,6 @@ class WorkerExecuteCommand extends Command
|
||||
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$MWG = false;
|
||||
$clearMetadatas = false;
|
||||
|
||||
$argQueueName = $input->getOption('queue-name');
|
||||
$maxProcesses = intval($input->getOption('max-processes'));
|
||||
|
||||
@@ -64,14 +61,6 @@ class WorkerExecuteCommand extends Command
|
||||
$workerInvoker->setMaxProcessPoolValue($maxProcesses);
|
||||
}
|
||||
|
||||
if ($input->getOption('MWG')) {
|
||||
$MWG = true;
|
||||
}
|
||||
|
||||
if ($input->getOption('clear-metadatas')) {
|
||||
$clearMetadatas = true;
|
||||
}
|
||||
|
||||
if ($input->getOption('preserve-payload')) {
|
||||
$workerInvoker->preservePayloads();
|
||||
}
|
||||
|
@@ -79,11 +79,11 @@ class AdminConfigurationController extends Controller
|
||||
$reload = ($request->query->get('reload')) == 1 ? true : false ;
|
||||
|
||||
if ($request->query->get('running') == 1 && $request->query->get('finished') == 1) {
|
||||
$workerRunningJob = $repoWorker->findAll();
|
||||
$workerRunningJob = $repoWorker->findBy([], ['id' => 'DESC'], WorkerRunningJob::MAX_RESULT);
|
||||
} elseif ($request->query->get('running') == 1) {
|
||||
$workerRunningJob = $repoWorker->findBy(['status' => WorkerRunningJob::RUNNING]);
|
||||
$workerRunningJob = $repoWorker->findBy(['status' => WorkerRunningJob::RUNNING], ['id' => 'DESC'], WorkerRunningJob::MAX_RESULT);
|
||||
} elseif ($request->query->get('finished') == 1) {
|
||||
$workerRunningJob = $repoWorker->findBy(['status' => WorkerRunningJob::FINISHED]);
|
||||
$workerRunningJob = $repoWorker->findBy(['status' => WorkerRunningJob::FINISHED], ['id' => 'DESC'], WorkerRunningJob::MAX_RESULT);
|
||||
}
|
||||
|
||||
return $this->render('admin/worker-manager/worker_info.html.twig', [
|
||||
@@ -92,6 +92,22 @@ class AdminConfigurationController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function queueMonitorAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
$reload = ($request->query->get('reload')) == 1 ? true : false ;
|
||||
|
||||
/** @var AMQPConnection $serverConnection */
|
||||
$serverConnection = $app['alchemy_worker.amqp.connection'];
|
||||
$serverConnection->getChannel();
|
||||
$serverConnection->declareExchange();
|
||||
$queuesStatus = $serverConnection->getQueuesStatus();
|
||||
|
||||
return $this->render('admin/worker-manager/worker_queue_monitor.html.twig', [
|
||||
'queuesStatus' => $queuesStatus,
|
||||
'reload' => $reload
|
||||
]);
|
||||
}
|
||||
|
||||
public function truncateTableAction(PhraseaApplication $app, Request $request)
|
||||
{
|
||||
/** @var WorkerRunningJobRepository $repoWorker */
|
||||
|
@@ -11,11 +11,13 @@ use Alchemy\Phrasea\WorkerManager\Worker\CreateRecordWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\DeleteRecordWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\ExportMailWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\Factory\CallableWorkerFactory;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\MainQueueWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\PopulateIndexWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\ProcessPool;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\PullAssetsWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\Resolver\TypeBasedWorkerResolver;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\SubdefCreationWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\SubtitleWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\WebhookWorker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\WorkerInvoker;
|
||||
use Alchemy\Phrasea\WorkerManager\Worker\WriteMetadatasWorker;
|
||||
@@ -128,6 +130,16 @@ class AlchemyWorkerServiceProvider implements PluginProviderInterface
|
||||
return (new DeleteRecordWorker())
|
||||
->setApplicationBox($app['phraseanet.appbox']);
|
||||
}));
|
||||
|
||||
$app['alchemy_worker.type_based_worker_resolver']->addFactory(MessagePublisher::SUBTITLE_TYPE, new CallableWorkerFactory(function () use ($app) {
|
||||
return (new SubtitleWorker($app['repo.worker-job'], $app['conf'], new LazyLocator($app, 'phraseanet.appbox'), $app['alchemy_worker.logger']))
|
||||
->setFileSystemLocator(new LazyLocator($app, 'filesystem'))
|
||||
->setTemporaryFileSystemLocator(new LazyLocator($app, 'temporary-filesystem'));
|
||||
}));
|
||||
|
||||
$app['alchemy_worker.type_based_worker_resolver']->addFactory(MessagePublisher::MAIN_QUEUE_TYPE, new CallableWorkerFactory(function () use ($app) {
|
||||
return new MainQueueWorker($app['alchemy_worker.message.publisher'], $app['repo.worker-job']);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -84,6 +84,10 @@ class ControllerServiceProvider implements ControllerProviderInterface, ServiceP
|
||||
->method('GET|POST')
|
||||
->bind('worker_admin_pullAssets');
|
||||
|
||||
$controllers->match('/queue-monitor', 'controller.worker.admin.configuration:queueMonitorAction')
|
||||
->method('GET')
|
||||
->bind('worker_admin_queue_monitor');
|
||||
|
||||
return $controllers;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@ use Alchemy\Phrasea\WorkerManager\Subscriber\AssetsIngestSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\ExportSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\RecordSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\SearchengineSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\SubtitleSubscriber;
|
||||
use Alchemy\Phrasea\WorkerManager\Subscriber\WebhookSubscriber;
|
||||
use Silex\Application;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
@@ -68,6 +69,7 @@ class QueueWorkerServiceProvider implements PluginProviderInterface
|
||||
$dispatcher->addSubscriber(new AssetsIngestSubscriber($app['alchemy_worker.message.publisher']));
|
||||
$dispatcher->addSubscriber(new SearchengineSubscriber($app['alchemy_worker.message.publisher']));
|
||||
$dispatcher->addSubscriber(new WebhookSubscriber($app['alchemy_worker.message.publisher']));
|
||||
$dispatcher->addSubscriber(new SubtitleSubscriber(new LazyLocator($app, 'repo.worker-job'), $app['alchemy_worker.message.publisher']));
|
||||
|
||||
return $dispatcher;
|
||||
})
|
||||
|
@@ -29,7 +29,9 @@ class AMQPConnection
|
||||
MessagePublisher::CREATE_RECORD_TYPE => MessagePublisher::CREATE_RECORD_QUEUE,
|
||||
MessagePublisher::PULL_QUEUE => MessagePublisher::PULL_QUEUE,
|
||||
MessagePublisher::POPULATE_INDEX_TYPE => MessagePublisher::POPULATE_INDEX_QUEUE,
|
||||
MessagePublisher::DELETE_RECORD_TYPE => MessagePublisher::DELETE_RECORD_QUEUE
|
||||
MessagePublisher::DELETE_RECORD_TYPE => MessagePublisher::DELETE_RECORD_QUEUE,
|
||||
MessagePublisher::MAIN_QUEUE_TYPE => MessagePublisher::MAIN_QUEUE,
|
||||
MessagePublisher::SUBTITLE_TYPE => MessagePublisher::SUBTITLE_QUEUE
|
||||
];
|
||||
|
||||
// the corresponding worker queues and retry queues, loop queue
|
||||
@@ -44,7 +46,6 @@ class AMQPConnection
|
||||
MessagePublisher::PULL_QUEUE => MessagePublisher::LOOP_PULL_QUEUE
|
||||
];
|
||||
|
||||
// default message TTL in retry queue in millisecond
|
||||
public static $defaultFailedQueues = [
|
||||
MessagePublisher::WRITE_METADATAS_TYPE => MessagePublisher::FAILED_METADATAS_QUEUE,
|
||||
MessagePublisher::SUBDEF_CREATION_TYPE => MessagePublisher::FAILED_SUBDEF_QUEUE,
|
||||
@@ -213,6 +214,37 @@ class AMQPConnection
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get queueName, messageCount, consumerCount of queues
|
||||
* @return array
|
||||
*/
|
||||
public function getQueuesStatus()
|
||||
{
|
||||
$queuesList = array_merge(
|
||||
array_values(self::$defaultQueues),
|
||||
array_values(self::$defaultDelayedQueues),
|
||||
array_values(self::$defaultRetryQueues),
|
||||
array_values(self::$defaultFailedQueues)
|
||||
);
|
||||
|
||||
$this->getChannel();
|
||||
$queuesStatus = [];
|
||||
|
||||
foreach ($queuesList as $queue) {
|
||||
$this->setQueue($queue);
|
||||
list($queueName, $messageCount, $consumerCount) = $this->channel->queue_declare($queue, true);
|
||||
|
||||
$status['queueName'] = $queueName;
|
||||
$status['messageCount'] = $messageCount;
|
||||
$status['consumerCount'] = $consumerCount;
|
||||
|
||||
$queuesStatus[] = $status;
|
||||
unset($status);
|
||||
}
|
||||
|
||||
return $queuesStatus;
|
||||
}
|
||||
|
||||
public function connectionClose()
|
||||
{
|
||||
$this->channel->close();
|
||||
|
@@ -18,6 +18,12 @@ class MessagePublisher
|
||||
const WEBHOOK_TYPE = 'webhook';
|
||||
const POPULATE_INDEX_TYPE = 'populateIndex';
|
||||
const PULL_ASSETS_TYPE = 'pullAssets';
|
||||
const SUBTITLE_TYPE = 'subtitle';
|
||||
const MAIN_QUEUE_TYPE = 'mainQueue';
|
||||
|
||||
|
||||
const MAIN_QUEUE = 'main-queue';
|
||||
const SUBTITLE_QUEUE = 'subtitle-queue';
|
||||
|
||||
// worker queue to be consumed, when no ack , it is requeued to the retry queue
|
||||
const EXPORT_QUEUE = 'export-queue';
|
||||
|
@@ -54,18 +54,20 @@ class RecordSubscriber implements EventSubscriberInterface
|
||||
if (!$record->isStory()) {
|
||||
$subdefs = $record->getDatabox()->get_subdef_structure()->getSubdefGroup($record->getType());
|
||||
|
||||
foreach ($subdefs as $subdef) {
|
||||
$payload = [
|
||||
'message_type' => MessagePublisher::SUBDEF_CREATION_TYPE,
|
||||
'payload' => [
|
||||
'recordId' => $event->getRecord()->getRecordId(),
|
||||
'databoxId' => $event->getRecord()->getDataboxId(),
|
||||
'subdefName' => $subdef->get_name(),
|
||||
'status' => $event->isNewRecord() ? MessagePublisher::NEW_RECORD_MESSAGE : ''
|
||||
]
|
||||
];
|
||||
if ($subdefs !== null) {
|
||||
foreach ($subdefs as $subdef) {
|
||||
$payload = [
|
||||
'message_type' => MessagePublisher::SUBDEF_CREATION_TYPE,
|
||||
'payload' => [
|
||||
'recordId' => $event->getRecord()->getRecordId(),
|
||||
'databoxId' => $event->getRecord()->getDataboxId(),
|
||||
'subdefName' => $subdef->get_name(),
|
||||
'status' => $event->isNewRecord() ? MessagePublisher::NEW_RECORD_MESSAGE : ''
|
||||
]
|
||||
];
|
||||
|
||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::SUBDEF_QUEUE);
|
||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::SUBDEF_QUEUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\WorkerManager\Subscriber;
|
||||
|
||||
use Alchemy\Phrasea\Core\Event\Record\RecordAutoSubtitleEvent;
|
||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
use Alchemy\Phrasea\Model\Entities\WorkerJob;
|
||||
use Alchemy\Phrasea\Model\Repositories\WorkerJobRepository;
|
||||
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class SubtitleSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
private $messagePublisher;
|
||||
|
||||
/** @var WorkerJobRepository $repoWorkerJob*/
|
||||
private $repoWorkerJob;
|
||||
|
||||
/** @var callable */
|
||||
private $repoWorkerJobLocator;
|
||||
|
||||
public function __construct(callable $repoWorkerJobLocator, MessagePublisher $messagePublisher)
|
||||
{
|
||||
$this->repoWorkerJobLocator = $repoWorkerJobLocator;
|
||||
$this->messagePublisher = $messagePublisher;
|
||||
}
|
||||
|
||||
public function onRecordAutoSubtitle(RecordAutoSubtitleEvent $event)
|
||||
{
|
||||
$this->repoWorkerJob = $this->getRepoWorkerJob();
|
||||
|
||||
$em = $this->repoWorkerJob->getEntityManager();
|
||||
|
||||
$data = [
|
||||
"databoxId" => $event->getRecord()->getDataboxId(),
|
||||
"recordId" => $event->getRecord()->getRecordId(),
|
||||
"permalinkUrl" => $event->getPermalinkUrl(),
|
||||
"languageSource" => $event->getLanguageSource(),
|
||||
"metaStructureIdSource" => $event->getMetaStructureIdSource(),
|
||||
"languageDestination" => $event->getLanguageDestination(),
|
||||
"metaStructureIdDestination" => $event->getMetaStructureIdDestination()
|
||||
];
|
||||
|
||||
$this->repoWorkerJob->reconnect();
|
||||
$em->beginTransaction();
|
||||
|
||||
try {
|
||||
$workerJob = new WorkerJob();
|
||||
$workerJob
|
||||
->setType(MessagePublisher::SUBTITLE_TYPE)
|
||||
->setData($data)
|
||||
->setStatus(WorkerJob::WAITING)
|
||||
;
|
||||
|
||||
$em->persist($workerJob);
|
||||
$em->flush();
|
||||
|
||||
$em->commit();
|
||||
|
||||
$data['workerId'] = $workerJob->getId();
|
||||
$data['type'] = MessagePublisher::SUBTITLE_TYPE;
|
||||
|
||||
$payload = [
|
||||
'message_type' => MessagePublisher::MAIN_QUEUE_TYPE,
|
||||
'payload' => $data
|
||||
];
|
||||
|
||||
$this->messagePublisher->publishMessage($payload, MessagePublisher::MAIN_QUEUE);
|
||||
} catch (\Exception $e) {
|
||||
$em->rollback();
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
PhraseaEvents::RECORD_AUTO_SUBTITLE => 'onRecordAutoSubtitle',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WorkerJobRepository
|
||||
*/
|
||||
private function getRepoWorkerJob()
|
||||
{
|
||||
$callable = $this->repoWorkerJobLocator;
|
||||
|
||||
return $callable();
|
||||
}
|
||||
}
|
49
lib/Alchemy/Phrasea/WorkerManager/Worker/MainQueueWorker.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\WorkerManager\Worker;
|
||||
|
||||
use Alchemy\Phrasea\Model\Repositories\WorkerJobRepository;
|
||||
use Alchemy\Phrasea\WorkerManager\Queue\MessagePublisher;
|
||||
|
||||
class MainQueueWorker implements WorkerInterface
|
||||
{
|
||||
private $messagePublisher;
|
||||
|
||||
private $repoWorkerJob;
|
||||
|
||||
public function __construct(
|
||||
MessagePublisher $messagePublisher,
|
||||
WorkerJobRepository $repoWorkerJob
|
||||
)
|
||||
{
|
||||
$this->messagePublisher = $messagePublisher;
|
||||
$this->repoWorkerJob = $repoWorkerJob;
|
||||
}
|
||||
|
||||
public function process(array $payload)
|
||||
{
|
||||
|
||||
// if needed do treatement here depending on the type
|
||||
$queue = null;
|
||||
$messageType = '';
|
||||
|
||||
switch ($payload['type']) {
|
||||
case MessagePublisher::SUBTITLE_TYPE:
|
||||
$queue = MessagePublisher::SUBTITLE_QUEUE;
|
||||
$messageType = $payload['type'];
|
||||
unset($payload['type']);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$data = [
|
||||
'message_type' => $messageType,
|
||||
'payload' => $payload
|
||||
];
|
||||
|
||||
if ($queue != null) {
|
||||
$this->messagePublisher->publishMessage($data, $queue);
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,7 +10,7 @@ use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
class ProcessPool implements LoggerAwareInterface
|
||||
{
|
||||
const MAX_PROCESSES = 4;
|
||||
const MAX_PROCESSES = 1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
@@ -41,7 +41,7 @@ class ProcessPool implements LoggerAwareInterface
|
||||
* Sets a logger instance on the object
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
* @return null
|
||||
* @return void
|
||||
*/
|
||||
public function setLogger(LoggerInterface $logger)
|
||||
{
|
||||
|
310
lib/Alchemy/Phrasea/WorkerManager/Worker/SubtitleWorker.php
Normal file
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\WorkerManager\Worker;
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\FilesystemAware;
|
||||
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||
use Alchemy\Phrasea\Model\Entities\WorkerJob;
|
||||
use Alchemy\Phrasea\Model\Repositories\WorkerJobRepository;
|
||||
use GuzzleHttp\Client;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class SubtitleWorker implements WorkerInterface
|
||||
{
|
||||
use FilesystemAware;
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $appboxLocator;
|
||||
|
||||
private $logger;
|
||||
private $conf;
|
||||
|
||||
/** @var WorkerJobRepository $repoWorkerJob*/
|
||||
private $repoWorkerJob;
|
||||
|
||||
public function __construct(WorkerJobRepository $repoWorkerJob, PropertyAccess $conf, callable $appboxLocator, LoggerInterface $logger)
|
||||
{
|
||||
$this->repoWorkerJob = $repoWorkerJob;
|
||||
$this->conf = $conf;
|
||||
$this->appboxLocator = $appboxLocator;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function process(array $payload)
|
||||
{
|
||||
$gingaBaseurl = $this->conf->get(['externalservice', 'ginger', 'AutoSubtitling', 'service_base_url']);
|
||||
$gingaToken = $this->conf->get(['externalservice', 'ginger', 'AutoSubtitling', 'token']);
|
||||
$gingaTranscriptFormat = $this->conf->get(['externalservice', 'ginger', 'AutoSubtitling', 'transcript_format']);
|
||||
|
||||
if (!$gingaBaseurl || !$gingaToken || !$gingaTranscriptFormat) {
|
||||
$this->logger->error("External service Ginga not set correctly in configuration.yml");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @var WorkerJob $workerJob */
|
||||
$workerJob = $this->repoWorkerJob->find($payload['workerId']);
|
||||
if ($workerJob == null) {
|
||||
$this->logger->error("WorkerId not found");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$workerJob->setStatus(WorkerJob::RUNNING)
|
||||
->setStarted(new \DateTime('now'));
|
||||
|
||||
$em = $this->repoWorkerJob->getEntityManager();
|
||||
$this->repoWorkerJob->reconnect();
|
||||
$em->persist($workerJob);
|
||||
$em->flush();
|
||||
|
||||
switch ($gingaTranscriptFormat) {
|
||||
case 'text/srt,':
|
||||
$extension = 'srt';
|
||||
break;
|
||||
case 'text/plain':
|
||||
$extension = 'txt';
|
||||
break;
|
||||
case 'application/json':
|
||||
$extension = 'json';
|
||||
break;
|
||||
case 'text/vtt':
|
||||
default:
|
||||
$extension = 'vtt';
|
||||
break;
|
||||
}
|
||||
|
||||
$languageSource = $this->getLanguageFormat($payload['languageSource']);
|
||||
$languageDestination = $this->getLanguageFormat($payload['languageDestination']);
|
||||
|
||||
$record = $this->getApplicationBox()->get_databox($payload['databoxId'])->get_record($payload['recordId']);
|
||||
$languageSourceFieldName = $record->getDatabox()->get_meta_structure()->get_element($payload['metaStructureIdSource'])->get_name();
|
||||
|
||||
$subtitleSourceTemporaryFile = $this->getTemporaryFilesystem()->createTemporaryFile("subtitle", null, $extension);
|
||||
$gingerClient = new Client();
|
||||
|
||||
// if the languageSourceFieldName do not yet exist, first generate subtitle for it
|
||||
if ($payload['permalinkUrl'] != '' && !$record->get_caption()->has_field($languageSourceFieldName)) {
|
||||
try {
|
||||
$response = $gingerClient->post($gingaBaseurl.'/media/', [
|
||||
'headers' => [
|
||||
'Authorization' => 'token '.$gingaToken
|
||||
],
|
||||
'json' => [
|
||||
'url' => $payload['permalinkUrl'],
|
||||
'language' => $languageSource
|
||||
]
|
||||
]);
|
||||
} catch(\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 201) {
|
||||
$this->logger->error("response status /media/ : ". $response->getStatusCode());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$responseMediaBody = $response->getBody()->getContents();
|
||||
$responseMediaBody = json_decode($responseMediaBody,true);
|
||||
|
||||
$checkStatus = true;
|
||||
do {
|
||||
// first wait 5 second before check subtitling status
|
||||
sleep(5);
|
||||
$this->logger->info("bigin to check status");
|
||||
try {
|
||||
$response = $gingerClient->get($gingaBaseurl.'/task/'.$responseMediaBody['task_id'].'/', [
|
||||
'headers' => [
|
||||
'Authorization' => 'token '.$gingaToken
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$checkStatus = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
$checkStatus = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$responseTaskBody = $response->getBody()->getContents();
|
||||
$responseTaskBody = json_decode($responseTaskBody,true);
|
||||
|
||||
} while($responseTaskBody['status'] != 'SUCCESS');
|
||||
|
||||
if (!$checkStatus) {
|
||||
$this->logger->error("can't check status");
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $gingerClient->get($gingaBaseurl.'/media/'.$responseMediaBody['media']['uuid'].'/', [
|
||||
'headers' => [
|
||||
'Authorization' => 'token '.$gingaToken,
|
||||
'ACCEPT' => $gingaTranscriptFormat
|
||||
],
|
||||
'query' => [
|
||||
'language' => $languageSource
|
||||
]
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
$this->logger->error("response status /media/uuid : ". $response->getStatusCode());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$transcriptContent = $response->getBody()->getContents();
|
||||
|
||||
$transcriptContent = preg_replace('/WEBVTT/', 'WEBVTT - with cue identifier', $transcriptContent, 1);
|
||||
|
||||
// save subtitle on temporary file to use to translate if needed
|
||||
file_put_contents($subtitleSourceTemporaryFile, $transcriptContent);
|
||||
|
||||
$metadatas[0] = [
|
||||
'meta_struct_id' => (int)$payload['metaStructureIdSource'],
|
||||
'meta_id' => '',
|
||||
'value' => $transcriptContent
|
||||
];
|
||||
|
||||
try {
|
||||
$record->set_metadatas($metadatas);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->logger->info("Generate subtitle on language source SUCCESS");
|
||||
} elseif ($record->get_caption()->has_field($languageSourceFieldName)) {
|
||||
// get the source subtitle and save it to a temporary file
|
||||
$fieldValues = $record->get_caption()->get_field($languageSourceFieldName)->get_values();
|
||||
$fieldValue = array_pop($fieldValues);
|
||||
|
||||
file_put_contents($subtitleSourceTemporaryFile, $fieldValue->getValue());
|
||||
}
|
||||
|
||||
if ($payload['metaStructureIdSource'] !== $payload['metaStructureIdDestination']) {
|
||||
try {
|
||||
$response = $gingerClient->post($gingaBaseurl.'/translate/', [
|
||||
'headers' => [
|
||||
'Authorization' => 'token '.$gingaToken,
|
||||
'ACCEPT' => $gingaTranscriptFormat
|
||||
],
|
||||
'multipart' => [
|
||||
[
|
||||
'name' => 'transcript',
|
||||
'contents' => fopen($subtitleSourceTemporaryFile, 'r')
|
||||
],
|
||||
[
|
||||
'name' => 'transcript_format',
|
||||
'contents' => $gingaTranscriptFormat,
|
||||
|
||||
],
|
||||
[
|
||||
'name' => 'language_in',
|
||||
'contents' => $languageSource,
|
||||
|
||||
],
|
||||
[
|
||||
'name' => 'language_out',
|
||||
'contents' => $languageDestination,
|
||||
|
||||
]
|
||||
]
|
||||
]);
|
||||
} catch(\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
$this->logger->error("response status /translate/ : ". $response->getStatusCode());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$transcriptContent = $response->getBody()->getContents();
|
||||
$transcriptContent = preg_replace('/WEBVTT/', 'WEBVTT - with cue identifier', $transcriptContent, 1);
|
||||
|
||||
$metadatas[0] = [
|
||||
'meta_struct_id' => (int)$payload['metaStructureIdDestination'],
|
||||
'meta_id' => '',
|
||||
'value' => $transcriptContent
|
||||
];
|
||||
|
||||
try {
|
||||
$record->set_metadatas($metadatas);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$this->logger->info("Translate subtitle on language destination SUCCESS");
|
||||
}
|
||||
|
||||
$this->jobFinished($workerJob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \appbox
|
||||
*/
|
||||
private function getApplicationBox()
|
||||
{
|
||||
$callable = $this->appboxLocator;
|
||||
|
||||
return $callable();
|
||||
}
|
||||
|
||||
private function jobFinished(WorkerJob $workerJob)
|
||||
{
|
||||
$workerJob->setStatus(WorkerJob::FINISHED)
|
||||
->setFinished(new \DateTime('now'));
|
||||
|
||||
$em = $this->repoWorkerJob->getEntityManager();
|
||||
$this->repoWorkerJob->reconnect();
|
||||
|
||||
$em->persist($workerJob);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
private function getLanguageFormat($language)
|
||||
{
|
||||
switch ($language) {
|
||||
case 'En':
|
||||
return 'en-GB';
|
||||
case 'De':
|
||||
return 'de-DE';
|
||||
case 'Fr':
|
||||
default:
|
||||
return 'fr-FR';
|
||||
}
|
||||
}
|
||||
}
|
@@ -522,10 +522,11 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
|
||||
/**
|
||||
*
|
||||
* @param collection $collection
|
||||
* @param appbox $appbox
|
||||
* @param appbox $appbox WTF this parm is useless
|
||||
* @return record_adapter
|
||||
*
|
||||
*/
|
||||
public function move_to_collection(collection $collection, appbox $appbox)
|
||||
public function move_to_collection(collection $collection, appbox $appbox = null)
|
||||
{
|
||||
if ($this->getCollection()->get_base_id() === $collection->get_base_id()) {
|
||||
return $this;
|
||||
@@ -1054,10 +1055,13 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
|
||||
}
|
||||
}
|
||||
|
||||
if (trim($params['meta_id']) !== '') {
|
||||
$tmp_val = trim($params['value']);
|
||||
$tmp_val = trim($params['value']);
|
||||
|
||||
$caption_field_value = $caption_field->get_value($params['meta_id']);
|
||||
if (trim($params['meta_id']) !== '') {
|
||||
|
||||
if(is_null($caption_field_value = $caption_field->get_value($params['meta_id']))) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($tmp_val === '') {
|
||||
$caption_field_value->delete();
|
||||
@@ -1068,8 +1072,11 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
|
||||
$caption_field_value->setVocab($vocab, $vocab_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$caption_field_value = caption_Field_Value::create($this->app, $databox_field, $this, $params['value'], $vocab, $vocab_id);
|
||||
}
|
||||
else {
|
||||
if($tmp_val !== '') {
|
||||
caption_Field_Value::create($this->app, $databox_field, $this, $params['value'], $vocab, $vocab_id);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@@ -319,5 +319,15 @@ workers:
|
||||
user: ''
|
||||
password: ''
|
||||
vhost: /
|
||||
|
||||
externalservice:
|
||||
ginger:
|
||||
AutoSubtitling:
|
||||
service_base_url: https://base.uri
|
||||
token: 39c6011d
|
||||
transcript_format: text/vtt
|
||||
subdef_source: preview
|
||||
|
||||
|
||||
Console_logger_enabled_environments: [test]
|
||||
|
||||
|
@@ -119,7 +119,7 @@
|
||||
<vcodec>libvpx</vcodec>
|
||||
</subdef>
|
||||
<subdef class="preview" name="audiovideowav" downloadable="true" orderable="true" presets="Wave Mono 8 kHz">
|
||||
<path>{{datapathnoweb}}{{basename}}/subview</path>
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<meta>no</meta>
|
||||
<mediatype>audio</mediatype>
|
||||
<audiobitrate>128</audiobitrate>
|
||||
@@ -131,7 +131,7 @@
|
||||
<label lang="en">Audio WAVE 8 kHz</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="audiovideomp3" downloadable="true" orderable="true" presets="Normal MP3 128 kbit/s">
|
||||
<path>{{datapathnoweb}}{{basename}}/subview</path>
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<meta>no</meta>
|
||||
<mediatype>audio</mediatype>
|
||||
<audiobitrate>180</audiobitrate>
|
||||
|
234
lib/conf.d/data_templates/gs1.xml
Normal file
@@ -0,0 +1,234 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<record>
|
||||
<path>{{datapathnoweb}}{{basename}}/documents</path>
|
||||
<subdefs>
|
||||
<subdefgroup name="image">
|
||||
<subdef class="preview" name="preview" downloadable="true">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<size>1024</size>
|
||||
<method>resample</method>
|
||||
<dpi>72</dpi>
|
||||
<strip>no</strip>
|
||||
<quality>75</quality>
|
||||
<meta>yes</meta>
|
||||
<devices>screen</devices>
|
||||
<mediatype>image</mediatype>
|
||||
<label lang="fr">Prévisualisation</label>
|
||||
<label lang="en">Preview</label>
|
||||
</subdef>
|
||||
<subdef class="thumbnail" name="thumbnail" downloadable="true">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<size>240</size>
|
||||
<method>resample</method>
|
||||
<dpi>72</dpi>
|
||||
<strip>yes</strip>
|
||||
<quality>75</quality>
|
||||
<meta>no</meta>
|
||||
<devices>screen</devices>
|
||||
<mediatype>image</mediatype>
|
||||
<label lang="fr">Vignette</label>
|
||||
<label lang="en">Thumbnail</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="preview_mobile" downloadable="false">
|
||||
<size>480</size>
|
||||
<resolution>72</resolution>
|
||||
<strip>yes</strip>
|
||||
<quality>75</quality>
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>image</mediatype>
|
||||
<meta>no</meta>
|
||||
<devices>handheld</devices>
|
||||
<label lang="fr">Prévisualisation Mobile</label>
|
||||
<label lang="en">Mobile Preview</label>
|
||||
</subdef>
|
||||
<subdef class="thumbnail" name="thumbnail_mobile" downloadable="false">
|
||||
<size>150</size>
|
||||
<resolution>72</resolution>
|
||||
<strip>yes</strip>
|
||||
<quality>75</quality>
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>image</mediatype>
|
||||
<meta>no</meta>
|
||||
<devices>handheld</devices>
|
||||
<label lang="fr">Vignette mobile</label>
|
||||
<label lang="en">Mobile Thumbnail</label>
|
||||
</subdef>
|
||||
</subdefgroup>
|
||||
<subdefgroup name="video">
|
||||
<subdef class="thumbnail" name="thumbnail" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<size>240</size>
|
||||
<devices>screen</devices>
|
||||
<mediatype>image</mediatype>
|
||||
<writeDatas>no</writeDatas>
|
||||
<label lang="fr">Vignette</label>
|
||||
<label lang="en">Thumbnail</label>
|
||||
</subdef>
|
||||
<subdef class="thumbnail" name="thumbnailgif" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<size>240</size>
|
||||
<mediatype>gif</mediatype>
|
||||
<delay>150</delay>
|
||||
<devices>screen</devices>
|
||||
<writeDatas>no</writeDatas>
|
||||
<label lang="fr">Animation GIF</label>
|
||||
<label lang="en">GIF Animation</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="preview" downloadable="true">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<size>748</size>
|
||||
<mediatype>video</mediatype>
|
||||
<writeDatas>yes</writeDatas>
|
||||
<acodec>libfdk_aac</acodec>
|
||||
<vcodec>libx264</vcodec>
|
||||
<devices>screen</devices>
|
||||
<bitrate>1000</bitrate>
|
||||
<audiobitrate>128</audiobitrate>
|
||||
<audiosamplerate>48000</audiosamplerate>
|
||||
<fps>25</fps>
|
||||
<GOPsize>25</GOPsize>
|
||||
<label lang="fr">Prévisualisation</label>
|
||||
<label lang="en">Preview</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="preview_webm" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<size>748</size>
|
||||
<mediatype>video</mediatype>
|
||||
<devices>screen</devices>
|
||||
<bitrate>1000</bitrate>
|
||||
<audiobitrate>128</audiobitrate>
|
||||
<audiosamplerate>48000</audiosamplerate>
|
||||
<acodec>libvorbis</acodec>
|
||||
<fps>25</fps>
|
||||
<GOPsize>25</GOPsize>
|
||||
<vcodec>libvpx</vcodec>
|
||||
<label lang="fr">Prévisualisation WebM</label>
|
||||
<label lang="en">WebM Preview</label>
|
||||
</subdef>
|
||||
</subdefgroup>
|
||||
<subdefgroup name="audio">
|
||||
<subdef class="thumbnail" name="thumbnail" downloadable="true">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>image</mediatype>
|
||||
<size>240</size>
|
||||
<devices>screen</devices>
|
||||
<writeDatas>no</writeDatas>
|
||||
<label lang="fr">Vignette</label>
|
||||
<label lang="en">Thumbnail</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="preview" downloadable="true">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>audio</mediatype>
|
||||
<writeDatas>yes</writeDatas>
|
||||
<audiobitrate>128</audiobitrate>
|
||||
<audiosamplerate>48000</audiosamplerate>
|
||||
<devices>screen</devices>
|
||||
<label lang="fr">Prévisualisation</label>
|
||||
<label lang="en">Preview</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="preview_mobile" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>audio</mediatype>
|
||||
<devices>handheld</devices>
|
||||
<label lang="fr">Prévisualisation Mobile</label>
|
||||
<label lang="en">Mobile Preview</label>
|
||||
</subdef>
|
||||
</subdefgroup>
|
||||
<subdefgroup name="document">
|
||||
<subdef class="thumbnail" name="thumbnail" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>image</mediatype>
|
||||
<method>resample</method>
|
||||
<dpi>72</dpi>
|
||||
<size>240</size>
|
||||
<writeDatas>no</writeDatas>
|
||||
<devices>screen</devices>
|
||||
<label lang="fr">Vignette</label>
|
||||
<label lang="en">Thumbnail</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="preview" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>flexpaper</mediatype>
|
||||
<writeDatas>no</writeDatas>
|
||||
<devices>screen</devices>
|
||||
<label lang="fr">Prévisualisation</label>
|
||||
<label lang="en">Preview</label>
|
||||
</subdef>
|
||||
</subdefgroup>
|
||||
<subdefgroup name="flash">
|
||||
<subdef class="thumbnail" name="thumbnail" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>image</mediatype>
|
||||
<size>240</size>
|
||||
<writeDatas>no</writeDatas>
|
||||
<method>resample</method>
|
||||
<dpi>72</dpi>
|
||||
<devices>screen</devices>
|
||||
<label lang="fr">Vignette</label>
|
||||
<label lang="en">Thumbnail</label>
|
||||
</subdef>
|
||||
<subdef class="preview" name="preview" downloadable="false">
|
||||
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
|
||||
<mediatype>image</mediatype>
|
||||
<size>800</size>
|
||||
<writeDatas>no</writeDatas>
|
||||
<method>resample</method>
|
||||
<dpi>72</dpi>
|
||||
<devices>screen</devices>
|
||||
<label lang="fr">Prévisualisation</label>
|
||||
<label lang="en">Preview</label>
|
||||
</subdef>
|
||||
</subdefgroup>
|
||||
</subdefs>
|
||||
|
||||
<description>
|
||||
<GDTI src="" index="1" />
|
||||
<BrandName src="" index="1" />
|
||||
<ProductName src="XMP-dc:Title" index="1" />
|
||||
<ValidFromDate src="" index="1" type="date" />
|
||||
<GTIN14 src="" index="1" />
|
||||
<AngleIndicator src="" index="1" />
|
||||
<ArticleVariant src="" index="1" />
|
||||
<ClippingPathName src="" index="1" />
|
||||
<ColorMode src="" index="1" readonly="1" />
|
||||
<Copyright src="" index="1" />
|
||||
<CreateDate src="" index="1" readonly="1" type="date" />
|
||||
<Description src="XMP-dc:Description" index="1" />
|
||||
<ExpirationDate src="XMP-plus:LicenseEndDate" index="1" type="date" />
|
||||
<FacingIndicator src="" index="1" />
|
||||
<FileType src="" index="1" />
|
||||
<Filename src="Phraseanet:tf-basename" index="1" readonly="1" thumbtitle="1"/>
|
||||
<ImageQADate src="" index="1" readonly="1" type="date" />
|
||||
<ClippingPathPresent src="" index="1" />
|
||||
<LegalOwner src="XMP-plus:CopyrightOwnerName" index="1" />
|
||||
<LegalOwnerContactInfo src="" index="1" />
|
||||
<MaxAvailHeight src="Phraseanet:tf-height" index="1" readonly="1" type="number" />
|
||||
<MaxAvailWidth src="Phraseanet:tf-width" index="1" readonly="1" type="number" />
|
||||
<NumberOfTheImage src="" index="1" />
|
||||
<PackagingType src="" index="1" />
|
||||
<ProductNetContent src="" index="1" />
|
||||
<ProductSupplier src="" index="1" />
|
||||
<ProductURL src="" index="1" readonly="1" />
|
||||
<RightOfUse src="XMP-xmpRights:UsageTerms" index="1" multi="1" separator=";" />
|
||||
<SpecialRights src="" index="1" multi="1" separator=";" />
|
||||
<VersionNumber src="" index="1" />
|
||||
<InOutPackaging src="" index="1" />
|
||||
<ArchiveDate src="Phraseanet:tf-archivedate" readonly="1" type="date" />
|
||||
<LastEditDate src="Phraseanet:tf-editdate" readonly="1" type="date" />
|
||||
</description>
|
||||
|
||||
<statbits>
|
||||
<bit n="4" labelOn="Caption_filled" searchable="0" printable="0" labelOff="Unspecified_caption">
|
||||
<label switch="off" code="en">Caption not filled</label>
|
||||
<label switch="off" code="fr">Media non renseigne</label>
|
||||
<label switch="on" code="en">Caption filled</label>
|
||||
<label switch="on" code="fr">Média renseigné</label>
|
||||
</bit>
|
||||
<bit n="5" labelOn="Clipping_Path_Present" searchable="1" printable="0" labelOff="No_Clipping_Path">
|
||||
<label switch="off" code="en">No Clipping Path</label>
|
||||
<label switch="off" code="fr">Sans masque de détourage</label>
|
||||
<label switch="on" code="en">Clipping Path Present</label>
|
||||
<label switch="on" code="fr">Avec masque de détourage</label>
|
||||
</bit>
|
||||
</statbits>
|
||||
</record>
|
@@ -65,7 +65,7 @@
|
||||
"normalize-css": "^2.1.0",
|
||||
"npm": "^6.0.0",
|
||||
"npm-modernizr": "^2.8.3",
|
||||
"phraseanet-production-client": "0.34.214-d",
|
||||
"phraseanet-production-client": "0.34.256-d",
|
||||
"requirejs": "^2.3.5",
|
||||
"tinymce": "^4.0.28",
|
||||
"underscore": "^1.8.3",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-05-29T13:54:14Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<file date="2020-07-08T13:05:50Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>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.</note>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-05-29T13:54:38Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<file date="2020-07-08T13:06:14Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>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.</note>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-05-29T13:55:04Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<file date="2020-07-08T13:06:42Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>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.</note>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-05-29T13:55:35Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<file date="2020-07-08T13:07:11Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>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.</note>
|
||||
|
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Model\Proxies\__CG__\Alchemy\Phrasea\Model\Entities;
|
||||
|
||||
/**
|
||||
* DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR
|
||||
*/
|
||||
class WorkerRunningJob extends \Alchemy\Phrasea\Model\Entities\WorkerRunningJob implements \Doctrine\ORM\Proxy\Proxy
|
||||
{
|
||||
/**
|
||||
* @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with
|
||||
* three parameters, being respectively the proxy object to be initialized, the method that triggered the
|
||||
* initialization process and an array of ordered parameters that were passed to that method.
|
||||
*
|
||||
* @see \Doctrine\Common\Persistence\Proxy::__setInitializer
|
||||
*/
|
||||
public $__initializer__;
|
||||
|
||||
/**
|
||||
* @var \Closure the callback responsible of loading properties that need to be copied in the cloned object
|
||||
*
|
||||
* @see \Doctrine\Common\Persistence\Proxy::__setCloner
|
||||
*/
|
||||
public $__cloner__;
|
||||
|
||||
/**
|
||||
* @var boolean flag indicating if this object was already initialized
|
||||
*
|
||||
* @see \Doctrine\Common\Persistence\Proxy::__isInitialized
|
||||
*/
|
||||
public $__isInitialized__ = false;
|
||||
|
||||
/**
|
||||
* @var array properties to be lazy loaded, with keys being the property
|
||||
* names and values being their default values
|
||||
*
|
||||
* @see \Doctrine\Common\Persistence\Proxy::__getLazyProperties
|
||||
*/
|
||||
public static $lazyPropertiesDefaults = [];
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param \Closure $initializer
|
||||
* @param \Closure $cloner
|
||||
*/
|
||||
public function __construct($initializer = null, $cloner = null)
|
||||
{
|
||||
|
||||
$this->__initializer__ = $initializer;
|
||||
$this->__cloner__ = $cloner;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
if ($this->__isInitialized__) {
|
||||
return ['__isInitialized__', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'id', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'databoxId', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'recordId', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'work', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'workOn', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'created', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'published', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'status'];
|
||||
}
|
||||
|
||||
return ['__isInitialized__', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'id', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'databoxId', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'recordId', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'work', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'workOn', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'created', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'published', '' . "\0" . 'Alchemy\\Phrasea\\Model\\Entities\\WorkerRunningJob' . "\0" . 'status'];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
if ( ! $this->__isInitialized__) {
|
||||
$this->__initializer__ = function (WorkerRunningJob $proxy) {
|
||||
$proxy->__setInitializer(null);
|
||||
$proxy->__setCloner(null);
|
||||
|
||||
$existingProperties = get_object_vars($proxy);
|
||||
|
||||
foreach ($proxy->__getLazyProperties() as $property => $defaultValue) {
|
||||
if ( ! array_key_exists($property, $existingProperties)) {
|
||||
$proxy->$property = $defaultValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->__cloner__ && $this->__cloner__->__invoke($this, '__clone', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces initialization of the proxy
|
||||
*/
|
||||
public function __load()
|
||||
{
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, '__load', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @internal generated method: use only when explicitly handling proxy specific loading logic
|
||||
*/
|
||||
public function __isInitialized()
|
||||
{
|
||||
return $this->__isInitialized__;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @internal generated method: use only when explicitly handling proxy specific loading logic
|
||||
*/
|
||||
public function __setInitialized($initialized)
|
||||
{
|
||||
$this->__isInitialized__ = $initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @internal generated method: use only when explicitly handling proxy specific loading logic
|
||||
*/
|
||||
public function __setInitializer(\Closure $initializer = null)
|
||||
{
|
||||
$this->__initializer__ = $initializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @internal generated method: use only when explicitly handling proxy specific loading logic
|
||||
*/
|
||||
public function __getInitializer()
|
||||
{
|
||||
return $this->__initializer__;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @internal generated method: use only when explicitly handling proxy specific loading logic
|
||||
*/
|
||||
public function __setCloner(\Closure $cloner = null)
|
||||
{
|
||||
$this->__cloner__ = $cloner;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @internal generated method: use only when explicitly handling proxy specific cloning logic
|
||||
*/
|
||||
public function __getCloner()
|
||||
{
|
||||
return $this->__cloner__;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @internal generated method: use only when explicitly handling proxy specific loading logic
|
||||
* @static
|
||||
*/
|
||||
public function __getLazyProperties()
|
||||
{
|
||||
return self::$lazyPropertiesDefaults;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
if ($this->__isInitialized__ === false) {
|
||||
return (int) parent::getId();
|
||||
}
|
||||
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []);
|
||||
|
||||
return parent::getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setDataboxId($databoxId)
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setDataboxId', [$databoxId]);
|
||||
|
||||
return parent::setDataboxId($databoxId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getDataboxId()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getDataboxId', []);
|
||||
|
||||
return parent::getDataboxId();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setRecordId($recordId)
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setRecordId', [$recordId]);
|
||||
|
||||
return parent::setRecordId($recordId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getRecordId()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getRecordId', []);
|
||||
|
||||
return parent::getRecordId();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setWork($work)
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setWork', [$work]);
|
||||
|
||||
return parent::setWork($work);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWork()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getWork', []);
|
||||
|
||||
return parent::getWork();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setWorkOn($workOn)
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setWorkOn', [$workOn]);
|
||||
|
||||
return parent::setWorkOn($workOn);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWorkOn()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getWorkOn', []);
|
||||
|
||||
return parent::getWorkOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getCreated()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getCreated', []);
|
||||
|
||||
return parent::getCreated();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setPublished(\DateTime $published)
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setPublished', [$published]);
|
||||
|
||||
return parent::setPublished($published);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getPublished()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getPublished', []);
|
||||
|
||||
return parent::getPublished();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setStatus($status)
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setStatus', [$status]);
|
||||
|
||||
return parent::setStatus($status);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getStatus()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getStatus', []);
|
||||
|
||||
return parent::getStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getWorkName()
|
||||
{
|
||||
|
||||
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getWorkName', []);
|
||||
|
||||
return parent::getWorkName();
|
||||
}
|
||||
|
||||
}
|
@@ -164,3 +164,20 @@ $mainMenuLinkBackgroundHoverColor: transparent;
|
||||
|
||||
}
|
||||
|
||||
.acceptDl-info {
|
||||
background-color: #d9edf7;
|
||||
border: 1px solid #bce8f1;
|
||||
border-radius: 3px;
|
||||
color: #3a87ad;
|
||||
display: inline-block;
|
||||
padding: 9px 24px 5px 9px;
|
||||
margin-bottom: 20px;
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,.5);
|
||||
a, label {
|
||||
color: #3a87ad!important;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
|
1
resources/www/lightbox/images/chevron-left-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-left" class="svg-inline--fa fa-chevron-left fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M34.52 239.03L228.87 44.69c9.37-9.37 24.57-9.37 33.94 0l22.67 22.67c9.36 9.36 9.37 24.52.04 33.9L131.49 256l154.02 154.75c9.34 9.38 9.32 24.54-.04 33.9l-22.67 22.67c-9.37 9.37-24.57 9.37-33.94 0L34.52 272.97c-9.37-9.37-9.37-24.57 0-33.94z"></path></svg>
|
After Width: | Height: | Size: 482 B |
1
resources/www/lightbox/images/chevron-right-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-right" class="svg-inline--fa fa-chevron-right fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>
|
After Width: | Height: | Size: 527 B |
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-download" class="svg-inline--fa fa-file-download fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="#2196f3" d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm76.45 211.36l-96.42 95.7c-6.65 6.61-17.39 6.61-24.04 0l-96.42-95.7C73.42 337.29 80.54 320 94.82 320H160v-80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v80h65.18c14.28 0 21.4 17.29 11.27 27.36zM377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z"></path></svg>
|
After Width: | Height: | Size: 625 B |
1
resources/www/lightbox/images/file-download-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="file-download" class="svg-inline--fa fa-file-download fa-w-12" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="#ffffff" d="M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm76.45 211.36l-96.42 95.7c-6.65 6.61-17.39 6.61-24.04 0l-96.42-95.7C73.42 337.29 80.54 320 94.82 320H160v-80c0-8.84 7.16-16 16-16h32c8.84 0 16 7.16 16 16v80h65.18c14.28 0 21.4 17.29 11.27 27.36zM377 105L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z"></path></svg>
|
After Width: | Height: | Size: 625 B |
1
resources/www/lightbox/images/home-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="home" class="svg-inline--fa fa-home fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="#ffffff" d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z"></path></svg>
|
After Width: | Height: | Size: 708 B |
1
resources/www/lightbox/images/pause-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="pause" class="svg-inline--fa fa-pause fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M144 479H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h96c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm304-48V79c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h96c26.5 0 48-21.5 48-48z"></path></svg>
|
After Width: | Height: | Size: 444 B |
1
resources/www/lightbox/images/play-solid.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="play" class="svg-inline--fa fa-play fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"></path></svg>
|
After Width: | Height: | Size: 339 B |
@@ -99,7 +99,7 @@ img {
|
||||
overflow: scroll;
|
||||
}
|
||||
.display_id {
|
||||
top: 5px;
|
||||
top: 0;
|
||||
margin: 0 0 0 5px;
|
||||
}
|
||||
}
|
||||
@@ -134,8 +134,8 @@ img {
|
||||
background-color: #212121;
|
||||
}
|
||||
.display_id {
|
||||
top: 4px;
|
||||
left: 8px;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
}
|
||||
.agreement {
|
||||
position: absolute;
|
||||
@@ -173,7 +173,9 @@ img {
|
||||
|
||||
.display_id {
|
||||
background-color: #FFFFFF;
|
||||
padding: 3px 6px;
|
||||
padding: 3.5px 6px;
|
||||
min-width: 15px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
z-index: 99;
|
||||
color: #212121;
|
||||
@@ -214,6 +216,28 @@ img {
|
||||
overflow: hidden;
|
||||
background-color: #1F1E1B;
|
||||
color: #BFBFBF;
|
||||
.PNB.choices {
|
||||
position: relative;
|
||||
}
|
||||
.comment_button {
|
||||
text-align: center;
|
||||
background: #353430;
|
||||
margin: 0;
|
||||
width: 118px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 7px;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
border: 0;
|
||||
bottom: -30px;
|
||||
.fa-comment.icon-white {
|
||||
font-size: 15px;
|
||||
line-height: 18px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#basket_options {
|
||||
@@ -230,6 +254,11 @@ img {
|
||||
#basket_infos .user_infos {
|
||||
height: 120px;
|
||||
top: auto;
|
||||
bottom: 43px;
|
||||
}
|
||||
.lightbox-icon {
|
||||
width: 10px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
#basket_infos {
|
||||
@@ -284,7 +313,7 @@ img {
|
||||
}
|
||||
|
||||
#right_column .right_column_wrapper {
|
||||
//top: 30px;
|
||||
top: 30px;
|
||||
bottom: 45px;
|
||||
}
|
||||
|
||||
@@ -296,6 +325,7 @@ img {
|
||||
#record_infos {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
|
||||
#record_compare {
|
||||
@@ -303,7 +333,10 @@ img {
|
||||
top: auto;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.download-feed{
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
}
|
||||
#record_compare .header, #record_compare .lightbox_container {
|
||||
left: 5px;
|
||||
}
|
||||
@@ -546,10 +579,14 @@ table th i {
|
||||
}
|
||||
|
||||
.basket_downloader {
|
||||
background-color: #1F1E1B;
|
||||
background-color: #ffffff;
|
||||
margin: 0 10px;
|
||||
padding: 2px;
|
||||
padding: 4px 0;
|
||||
border: 0;
|
||||
transition: 0.3s all;
|
||||
&:hover {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
@@ -562,6 +599,13 @@ hr {
|
||||
.report {
|
||||
margin: 0 10px;
|
||||
vertical-align: bottom;
|
||||
}.back-home {
|
||||
margin: 0 10px;
|
||||
vertical-align: bottom;
|
||||
width: 20px;
|
||||
background: #1F1E1B;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -669,3 +713,25 @@ a.btn-info {
|
||||
}
|
||||
|
||||
/** End Lightbox summary modal**/
|
||||
|
||||
.humane{
|
||||
position: fixed;
|
||||
z-index: 100000;
|
||||
font-family: Ubuntu, Arial, sans-serif;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
top: 100px;
|
||||
right: 70px;
|
||||
width: 400px;
|
||||
background: #2d2d72;
|
||||
color: rgb(255, 255, 255);
|
||||
box-shadow: rgb(0, 0, 0) 0px 4px 4px -4px;
|
||||
transform: translateY(-40px);
|
||||
transition: all 0.3s ease-out 0s;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text {
|
||||
padding: 0!important;
|
||||
}
|
@@ -1,3 +1,40 @@
|
||||
$blue-tsr: #2196f3;
|
||||
$grey-tsr: #aaa;
|
||||
$iconsPath: '../../../assets/thesaurus/images/';
|
||||
@mixin blue-btn {
|
||||
color: #fff;
|
||||
background: $blue-tsr;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border-color: darken($blue-tsr, 20%);
|
||||
min-width: 120px;
|
||||
margin: 0 10px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
&:hover {
|
||||
background: darken($blue-tsr, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin grey-btn {
|
||||
color: #000;
|
||||
background: $grey-tsr;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border-color: darken($grey-tsr, 20%);
|
||||
min-width: 120px;
|
||||
margin: 0 10px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
&:hover {
|
||||
background: darken($grey-tsr, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
BODY, TD, INPUT {
|
||||
FONT-FAMILY: Verdana, Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
@@ -8,11 +45,11 @@ FORM {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
BODY.dialog {
|
||||
.dialog {
|
||||
background-color: ButtonFace;
|
||||
}
|
||||
|
||||
BODY.dialog .x3Dbox {
|
||||
.x3Dbox {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
@@ -24,7 +61,7 @@ BODY.dialog .x3Dbox {
|
||||
border-right: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
BODY.dialog .x3Dbox .title {
|
||||
.x3Dbox .title {
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
left: 20px;
|
||||
@@ -58,7 +95,7 @@ H3, H4 {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
DIV.thbox {
|
||||
.thbox {
|
||||
BACKGROUND-COLOR: #ffffff;
|
||||
border-top: 1px solid #d0d0d0;
|
||||
border-left: 1px solid #d0d0d0;
|
||||
@@ -69,7 +106,7 @@ DIV.thbox {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
DIV.thbox .onglet {
|
||||
.thbox .onglet {
|
||||
position: absolute;
|
||||
top: -22px;
|
||||
left: 5px;
|
||||
@@ -87,20 +124,20 @@ DIV.thbox .onglet {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
DIV.thbox HR {
|
||||
.thbox HR {
|
||||
COLOR: #d0d0d0;
|
||||
height: 1px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
DIV.glossaire {
|
||||
.glossaire {
|
||||
position: relative;
|
||||
left: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
DIV.glossaire U {
|
||||
.glossaire U {
|
||||
position: relative;
|
||||
left: 1px;
|
||||
TEXT-DECORATION: none;
|
||||
@@ -116,30 +153,30 @@ DIV.glossaire U {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
DIV.glossaire U.nots {
|
||||
.glossaire U.nots {
|
||||
border: 1px solid #F0F0F0;
|
||||
BACKGROUND-COLOR: #F0F0F0;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.S_ {
|
||||
.glossaire .S_ {
|
||||
cursor: pointer;
|
||||
BACKGROUND-COLOR: #99a2d0;
|
||||
COLOR: #FFFFFF;
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.s_ {
|
||||
.glossaire .s_ {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.r0_ {
|
||||
.glossaire .r0_ {
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.r1_ {
|
||||
.glossaire .r1_ {
|
||||
COLOR: #FF4000;
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.OB {
|
||||
.glossaire .OB {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
padding-top: 0px;
|
||||
@@ -149,11 +186,11 @@ DIV.glossaire DIV.OB {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.ob {
|
||||
.glossaire .ob {
|
||||
display: none;
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.hb {
|
||||
.glossaire .hb {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
padding-top: 0px;
|
||||
@@ -163,46 +200,46 @@ DIV.glossaire DIV.hb {
|
||||
border-bottom: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
DIV.glossaire DIV.ctroot {
|
||||
.glossaire .ctroot {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
DIV.glossaire P.sy {
|
||||
.glossaire P.sy {
|
||||
}
|
||||
|
||||
DIV.glossaire P.ta {
|
||||
.glossaire P.ta {
|
||||
}
|
||||
|
||||
DIV.glossaire P.tc {
|
||||
.glossaire P.tc {
|
||||
}
|
||||
|
||||
DIV.glossaire P.tce {
|
||||
.glossaire P.tce {
|
||||
}
|
||||
|
||||
DIV.tableContainer {
|
||||
.tableContainer {
|
||||
margin: 2px;
|
||||
border: 1px solid #000000;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
DIV.tableContainerDragOver {
|
||||
.tableContainerDragOver {
|
||||
margin: 0px;
|
||||
border: 3px solid #99a2d0;
|
||||
}
|
||||
|
||||
DIV.tableContainer DIV.tbody {
|
||||
.tableContainer .tbody {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
DIV.tableContainer TABLE {
|
||||
.tableContainer TABLE {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
DIV.tableContainer THEAD TH {
|
||||
.tableContainer THEAD TH {
|
||||
background: #e0ece8;
|
||||
border-left: 1px solid #ffffff;
|
||||
border-right: 1px solid #c0ccc8;
|
||||
@@ -216,15 +253,15 @@ DIV.tableContainer THEAD TH {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
DIV.tableContainer TBODY TR.s_ {
|
||||
.tableContainer TBODY TR.s_ {
|
||||
}
|
||||
|
||||
DIV.tableContainer TBODY TR.S_ {
|
||||
.tableContainer TBODY TR.S_ {
|
||||
BACKGROUND-COLOR: #99a2d0;
|
||||
COLOR: #FFFFFF;
|
||||
}
|
||||
|
||||
DIV.tableContainer TBODY TD {
|
||||
.tableContainer TBODY TD {
|
||||
border-left: 1px solid #ffffff;
|
||||
border-right: 1px solid #cccccc;
|
||||
font-weight: normal;
|
||||
@@ -235,77 +272,68 @@ DIV.tableContainer TBODY TD {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
DIV.menu {
|
||||
.menu {
|
||||
FONT-FAMILY: Arial, helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
border-left: 1px solid #ffffff;
|
||||
border-top: 1px solid #ffffff;
|
||||
border-right: 2px solid #000000;
|
||||
border-bottom: 2px solid #000000;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
background-color: #d4d0c8;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #535353;
|
||||
}
|
||||
|
||||
DIV.menu IMG {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
.menu IMG {
|
||||
padding-right: 2px;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
left: -10px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
DIV.menu A {
|
||||
.menu p {
|
||||
padding: 2px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu a {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
color: #000000;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 13px;
|
||||
padding-right: 3px;
|
||||
overflow: hidden;
|
||||
border: none 0px #FFFFFF;
|
||||
white-space: nowrap;
|
||||
color: #fff;
|
||||
padding: 5px 6px;
|
||||
background-color: #535353;
|
||||
|
||||
}
|
||||
|
||||
DIV.menu A:hover {
|
||||
.menu A:hover {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
background-color: #000080;
|
||||
background-color: #884c92;
|
||||
}
|
||||
|
||||
DIV.menu A.disabled {
|
||||
.menu A.disabled {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
color: #A0A0A0;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 13px;
|
||||
padding-right: 3px;
|
||||
color: lighten(#535353, 10%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
DIV.menu A.disabled:hover {
|
||||
.menu A.disabled:hover {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
color: #A0A0A0;
|
||||
background-color: #d4d0c8;
|
||||
color: lighten(#535353, 5%);
|
||||
background-color: #535353;
|
||||
}
|
||||
|
||||
DIV.menu .line {
|
||||
.menu .line {
|
||||
display: block;
|
||||
position: relative;
|
||||
height: 0px;
|
||||
@@ -316,3 +344,90 @@ DIV.menu .line {
|
||||
border-top: 1px solid #555555;
|
||||
border-bottom: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
#delete_sy {
|
||||
background: orange;
|
||||
border: 1px solid darken(orange,20%);
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
padding: 1px 10px;
|
||||
margin-left: 12px;
|
||||
&.disabled {
|
||||
background: grey;
|
||||
}
|
||||
}
|
||||
|
||||
#DLG_PROPERTIES > #syMenu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.thesaurus_confirm_bottom_block {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
#ifrsample & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.thesaurus-page {
|
||||
.validate_btn {
|
||||
@include blue-btn;
|
||||
}
|
||||
.cancel_btn {
|
||||
@include grey-btn;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
||||
float: none;
|
||||
}
|
||||
.ui-dialog-buttonset {
|
||||
text-align: center;
|
||||
}
|
||||
.ui-button {
|
||||
&:nth-child(1) {
|
||||
@include grey-btn
|
||||
}
|
||||
&:nth-child(2) {
|
||||
@include blue-btn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.populate_btn {
|
||||
position: absolute;
|
||||
background: #884c92;
|
||||
z-index: 2;
|
||||
right: 50px;
|
||||
top: 50px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
padding: 7px 10px;
|
||||
font-weight: bold;
|
||||
border: 1px solid #d0d0d0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: darken(#884c92, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
.thesaurus-page {
|
||||
.ui-widget-header {
|
||||
border: 1px solid darken(#884c92, 20%);
|
||||
background: #884c92;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#flagsMenu p {
|
||||
color: #fff;
|
||||
padding: 0 10px;
|
||||
}
|
@@ -35,6 +35,11 @@
|
||||
{{ 'admin::workermanager:tab:metadata: title' |trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="worker-queue-monitor" role="presentation">
|
||||
<a href="#worker-queue-monitor" aria-controls="worker-queue-monitor" role="tab" data-toggle="tab" data-url="/admin/worker-manager/queue-monitor">
|
||||
{{ 'admin::workermanager:tab:queueMonitor: title' |trans }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
@@ -48,6 +53,7 @@
|
||||
<div role="tabpanel" class="tab-pane fade" id="worker-pull-assets"></div>
|
||||
<div role="tabpanel" class="tab-pane fade" id="worker-subview"></div>
|
||||
<div role="tabpanel" class="tab-pane fade" id="worker-metadata"></div>
|
||||
<div role="tabpanel" class="tab-pane fade" id="worker-queue-monitor"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@@ -42,7 +42,7 @@
|
||||
<table class="admintable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sortable">{{ 'admin::workermanager:tab:workerinfo: databox_id' | trans }}</th>
|
||||
<th class="sortable">{{ 'admin::workermanager:tab:workerinfo: databox_name' | trans }}</th>
|
||||
<th class="sortable">{{ 'admin::workermanager:tab:workerinfo: record_id' | trans }}</th>
|
||||
<th class="sortable">{{ 'admin::workermanager:tab:workerinfo: work' | trans }}</th>
|
||||
<th class="sortable">{{ 'admin::workermanager:tab:workerinfo: work_on' | trans }}</th>
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
{% for workerRow in workerRunningJob | sort | reverse %}
|
||||
<tr>
|
||||
<td>{{ workerRow.databoxId }}</td>
|
||||
<td>{{ workerRow.databoxId | sbas_labels(app) }}</td>
|
||||
<td>{{ workerRow.recordId }}</td>
|
||||
<td>{{ workerRow.getWorkName }}</td>
|
||||
<td>{{ workerRow.workOn }}</td>
|
||||
|
@@ -0,0 +1,42 @@
|
||||
{% if not reload %}
|
||||
<h1>{{ 'admin::workermanager:tab:queueMonitor: description' |trans }}</h1>
|
||||
|
||||
<button id="refresh-monitor" class="btn btn-success">
|
||||
{{ 'admin::workermanager:tab:queueMonitor: Refresh list' |trans }}
|
||||
</button>
|
||||
|
||||
<table class="admintable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{{ 'admin::workermanager:tab:queueMonitor: Message count' |trans }}</th>
|
||||
<th>{{ 'admin::workermanager:tab:queueMonitor: Consumer count' |trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="queue-list">
|
||||
|
||||
{% endif %}
|
||||
{% for queueStatus in queuesStatus %}
|
||||
<tr>
|
||||
<th>{{ queueStatus.queueName }}</th>
|
||||
<td>{{ queueStatus.messageCount }}</td>
|
||||
<td>{{ queueStatus.consumerCount }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% if not reload %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript">
|
||||
$("#refresh-monitor").on('click', function () {
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/admin/worker-manager/queue-monitor?reload=1",
|
||||
success: function (data) {
|
||||
$(".queue-list").empty().html(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
@@ -152,9 +152,8 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ _self.choose_title('download', choose_export_title, default_export_title) }}
|
||||
|
||||
{% if app['conf'].get(['registry', 'actions', 'tou-validation-required-for-export']) == true %}
|
||||
<div class="well-small">
|
||||
<div class="well-small acceptDl-info">
|
||||
<label for="TOU_acceptDL" class="checkbox">
|
||||
<input type="checkbox" name="TOU_accept" id="TOU_acceptDL" value="1" />
|
||||
{% set beginning_link = '<a href="' ~ path('get_tou') ~ '" class="TOUview">' %}
|
||||
@@ -177,21 +176,27 @@
|
||||
<input type="hidden" name="lst" value="{{lst}}"/>
|
||||
<input type="hidden" name="ssttid" value="{{ssttid}}"/>
|
||||
<div>
|
||||
{{ 'export::mail: destinataire' | trans }}
|
||||
<span style="min-width: 21px;display: inline-block; ">
|
||||
{{ 'export::mail: destinataire' | trans }}</span>
|
||||
<input type="text" value="" name="destmail" class="required span4">
|
||||
<div class="acceptDl-info" style="padding-top: 4px; margin-left: 25px;">
|
||||
<span style="font-style: italic">{{ 'Entrez plusieurs adresses email en les separant par des points-virgules' | trans }}</span>
|
||||
</div>
|
||||
{% set my_email = app.getAuthenticatedUser().getEmail() %}
|
||||
{% if my_email != '' %}
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="reading_confirm" value="1" />
|
||||
{% trans with {'%my_email%' : my_email} %}Recevoir un accuse de reception a %my_email%{% endtrans %}
|
||||
</label>
|
||||
{% else %}
|
||||
<label class="checkbox">
|
||||
{{ 'Accuse de reception indisponible, vous n\'avez pas declare d\'adresse email' | trans }}
|
||||
<input type="checkbox" name="reading_confirm" value="1" readonly />
|
||||
</label>
|
||||
{% endif %}
|
||||
<span style="font-style: italic; color: #999999;">{{ 'Entrez plusieurs adresses email en les separant par des points-virgules' | trans }}</span>
|
||||
<div class="acceptDl-info">
|
||||
{% if my_email != '' %}
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="reading_confirm" value="1" />
|
||||
{% trans with {'%my_email%' : my_email} %}Recevoir un accuse de reception a %my_email%{% endtrans %}
|
||||
</label>
|
||||
{% else %}
|
||||
<label class="checkbox">
|
||||
{{ 'Accuse de reception indisponible, vous n\'avez pas declare d\'adresse email' | trans }}
|
||||
<input type="checkbox" name="reading_confirm" value="1" readonly />
|
||||
</label>
|
||||
{% endif %}
|
||||
<span style="font-style: italic; color: #999999;">{{ 'export:email:: acknowledgement info' | trans }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>{{ 'export::mail: contenu du mail' | trans }}</p>
|
||||
@@ -235,7 +240,7 @@
|
||||
{{ _self.choose_title('sendmail', choose_export_title, default_export_title) }}
|
||||
|
||||
{% if app['conf'].get(['registry', 'actions', 'tou-validation-required-for-export']) == true %}
|
||||
<div class="well-small">
|
||||
<div class="well-small acceptDl-info">
|
||||
<label for="TOU_acceptMail" class="checkbox">
|
||||
<input type="checkbox" name="TOU_accept" id="TOU_acceptMail" value="1" />
|
||||
{% set beginning_link = '<a href="' ~ path('get_tou') ~ '" class="TOUview">' %}
|
||||
@@ -388,7 +393,7 @@
|
||||
</div>
|
||||
|
||||
{% if app['conf'].get(['registry', 'actions', 'tou-validation-required-for-export']) == true %}
|
||||
<div class="well-small">
|
||||
<div class="well-small acceptDl-info">
|
||||
<label for="TOU_acceptOrder" class="checkbox">
|
||||
<input type="checkbox" name="TOU_accept" id="TOU_acceptOrder" value="1" />
|
||||
{% set beginning_link = '<a href="' ~ path('get_tou') ~ '" class="TOUview">' %}
|
||||
@@ -469,7 +474,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if app['conf'].get(['registry', 'actions', 'tou-validation-required-for-export']) == true %}
|
||||
<div class="well-small">
|
||||
<div class="well-small acceptDl-info">
|
||||
<label for="TOU_acceptFTP" class="checkbox">
|
||||
<input type="checkbox" name="TOU_accept" id="TOU_acceptFTP" value="1" />
|
||||
{% set beginning_link = '<a href="' ~ path('get_tou') ~ '" class="TOUview">' %}
|
||||
|
@@ -232,7 +232,7 @@
|
||||
{% endif %}
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://docs.phraseanet.com/4.0/">
|
||||
<a target="_blank" href="{{ 'https://docs.phraseanet.com/4.1/' ~ app['locale'] }}">
|
||||
<span>
|
||||
{{ 'phraseanet:: aide' | trans }}
|
||||
</span>
|
||||
|
@@ -47,4 +47,16 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if basket_element.getBasket().getValidation() %}
|
||||
<button class="comment_button btn btn-mini btn-inverse">
|
||||
<i class="fa fa-comment icon-white" aria-hidden="true"></i>
|
||||
{% set n = 0 %}
|
||||
{% for validationData in basket_element.getValidationDatas() %}
|
||||
{% if validationData.getNote() %}
|
||||
{% set n = n+1 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ n }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@@ -92,11 +92,12 @@
|
||||
<div class="PNB" style="height:30px;bottom:auto;">
|
||||
<table border="0" cellspacing="0" cellpadding="0" style="width:100%;">
|
||||
<tr>
|
||||
<td style="width:20px;">
|
||||
<td style="width:50px;">
|
||||
<a href="/lightbox"><img title="{{ 'lightbox::recaptitulatif' | trans }}" class="back-home" src="/assets/lightbox/images/home-solid.svg"/></a>
|
||||
</td>
|
||||
<td style="width:40px;">
|
||||
<button class="ui-corner-all basket_downloader" title="{{ 'boutton::telecharger tous les documents' | trans }}">
|
||||
<img src="/assets/lightbox/images/save.png"/>
|
||||
<img width="15" src="/assets/lightbox/images/file-download-solid-blue.svg" >
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
|
@@ -1,25 +1,25 @@
|
||||
<span style="padding:10px 4px 7px;">
|
||||
{% if feed_element %}
|
||||
<button class="previous_button play btn btn-mini" title="{{ 'boutton::precedent' | trans }}">
|
||||
<i class="fa fa-chevron-left" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-left-solid.svg"/>
|
||||
</button>
|
||||
<button class="previous_button pause btn btn-mini btn-inverse" title="{{ 'boutton::precedent' | trans }}">
|
||||
<i class="fa fa-chevron-left icon-white" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-left-solid.svg"/>
|
||||
</button>
|
||||
<button class="play_button btn btn-mini" title="{{ 'boutton::demarrer' | trans }}">
|
||||
<i class="fa fa-play" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/play-solid.svg"/>
|
||||
</button>
|
||||
<button class="pause_button btn btn-mini" title="{{ 'boutton::pause' | trans }}">
|
||||
<i class="fa fa-pause" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/pause-solid.svg"/>
|
||||
</button>
|
||||
<button class="next_button play btn btn-mini" title="{{ 'boutton::suivant' | trans }}">
|
||||
<i class="fa fa-chevron-right" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-right-solid.svg"/>
|
||||
</button>
|
||||
<button class="next_button pause btn btn-mini btn-inverse" title="{{ 'boutton::suivant' | trans }}">
|
||||
<i class="fa fa-chevron-right icon-white" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-right-solid.svg"/>
|
||||
</button>
|
||||
<button class="download_button btn btn-mini btn-inverse" title="{{ 'boutton::telecharger' | trans }}">
|
||||
<i class="fa fa-arrow-circle-o-down icon-white" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/file-download-solid.svg"/>
|
||||
</button>
|
||||
<form name="download_form" style="display:none;">
|
||||
<input type="hidden" name="basrec" value="{{feed_element.getRecord(app).get_serialize_key()}}"/>
|
||||
|
@@ -11,10 +11,6 @@
|
||||
<link type="text/css" rel="stylesheet" href="/assets/lightbox/css/lightbox{% if not app.debug %}.min{% endif %}.css" media="screen"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block icon %}
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/assets/lightbox/images/favicon.ico">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="main_index" style="margin-top:50px;">
|
||||
<table id="main_wrapper" cellspacing="0" cellpadding="0">
|
||||
|
@@ -1,5 +1,8 @@
|
||||
{% extends "common/index_bootstrap.html.twig" %}
|
||||
|
||||
{% block icon %}
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/assets/lightbox/images/favicon.ico">
|
||||
{% endblock %}
|
||||
{% block extra_content %}
|
||||
<div id="DIALOG"></div>
|
||||
{% endblock %}
|
||||
|
@@ -1,42 +1,31 @@
|
||||
<span style="padding:10px 4px 7px;">
|
||||
{% if basket_element %}
|
||||
<button class="previous_button play btn btn-mini" title="{{ 'boutton::precedent' | trans }}">
|
||||
<i class="fa fa-chevron-left" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-left-solid.svg"/>
|
||||
</button>
|
||||
<button class="previous_button pause btn btn-mini btn-inverse" title="{{ 'boutton::precedent' | trans }}" style="display:none">
|
||||
<i class="fa fa-chevron-left icon-white" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-left-solid.svg"/>
|
||||
</button>
|
||||
<button class="play_button btn btn-mini" title="{{ 'boutton::demarrer' | trans }}">
|
||||
<i class="fa fa-play" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/play-solid.svg"/>
|
||||
</button>
|
||||
<button class="pause_button btn btn-mini" title="{{ 'boutton::pause' | trans }}" style="display:none">
|
||||
<i class="fa fa-pause" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/pause-solid.svg"/>
|
||||
</button>
|
||||
<button class="next_button play btn btn-mini" title="{{ 'boutton::suivant' | trans }}">
|
||||
<i class="fa fa-chevron-right" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-right-solid.svg"/>
|
||||
</button>
|
||||
<button class="next_button pause btn btn-mini btn-inverse" title="{{ 'boutton::suivant' | trans }}" style="display:none">
|
||||
<i class="fa fa-chevron-right icon-white" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/chevron-right-solid.svg"/>
|
||||
</button>
|
||||
<button class="download_button btn btn-mini btn-inverse" title="{{ 'boutton::telecharger' | trans }}">
|
||||
<i class="fa fa-arrow-circle-o-down icon-white" aria-hidden="true"></i>
|
||||
<img class="lightbox-icon" src="/assets/lightbox/images/file-download-solid.svg"/>
|
||||
</button>
|
||||
<form name="download_form" style="display:none;">
|
||||
<input type="hidden" name="basrec" value="{{basket_element.getRecord(app).get_serialize_key()}}"/>
|
||||
</form>
|
||||
|
|
||||
{% if basket_element.getBasket().getValidation() %}
|
||||
<button class="comment_button btn btn-mini btn-inverse">
|
||||
<i class="fa fa-pencil-square-o icon-white" aria-hidden="true"></i>
|
||||
{% set n = 0 %}
|
||||
{% for validationData in basket_element.getValidationDatas() %}
|
||||
{% if validationData.getNote() %}
|
||||
{% set n = n+1 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ n }}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
{% block content %}
|
||||
{% set basket_element = basket.getElements().first() %}
|
||||
<div class="PNB10">
|
||||
<input type="hidden" id="export-send-mail-notif" value="{{ 'prod::export: send mail notification' | trans }} ">
|
||||
<div class="PNB" id="top_container">
|
||||
<div id="record_wrapper" class="PNB single" style="right:250px;">
|
||||
<div id="record_main" class="PNB record_display_box" style="bottom:auto;right:auto;">
|
||||
@@ -155,11 +156,10 @@
|
||||
<tr>
|
||||
<td style="width:20px;">
|
||||
</td>
|
||||
{% if basket.getValidation() %}
|
||||
<td style="width:50px;">
|
||||
<img title="{{ 'lightbox::recaptitulatif' | trans }}" class="report" src="/assets/lightbox/images/retour.png"/>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
<td style="width:50px;">
|
||||
<a href="/lightbox"><img title="{{ 'lightbox::recaptitulatif' | trans }}" class="back-home" src="/assets/lightbox/images/home-solid.svg"/></a>
|
||||
</td>
|
||||
<td style="width:220px;">
|
||||
<select id="navigation" style='margin:0'>
|
||||
<optgroup label="{{ 'Validations' | trans }}">
|
||||
@@ -182,7 +182,7 @@
|
||||
</td>
|
||||
<td style="width:50px;">
|
||||
<button style='width:30px;margin:0;' class="ui-corner-all basket_downloader" title="{{ 'boutton::telecharger tous les documents' | trans }}">
|
||||
<img src="/assets/lightbox/images/save.png"/>
|
||||
<img width="15" src="/assets/lightbox/images/file-download-solid-blue.svg" >
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<div class="PNB">
|
||||
<div class="PNB header" style="height:40px;bottom:auto;">
|
||||
<table>
|
||||
<table class="detailed_basket_browser">
|
||||
<tr>
|
||||
<td style="width:230px;">
|
||||
<a href="#" class="back">
|
||||
@@ -23,9 +23,9 @@
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="basket_link" href="#">
|
||||
{{ Basket.getName() }}
|
||||
</a>
|
||||
<span class="basket_link" title="{{ Basket.getName() }}">
|
||||
{{ Basket.getName()|length > 55 ? Basket.getName()|slice(0, 52) ~ '...' : Basket.getName() }}
|
||||
</span>
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
|
@@ -40,8 +40,8 @@
|
||||
|
||||
</a>
|
||||
{% endif %}
|
||||
<a class="basket_link" href="{{ path('prod_workzone_basket', { basket : Basket.getId() }) }}">
|
||||
<span>{{ Basket.getName() }}</span>
|
||||
<a title="{{ Basket.getName()}}" class="basket_link" href="{{ path('prod_workzone_basket', { basket : Basket.getId() }) }}">
|
||||
<span> {{ Basket.getName()|length > 80 ? Basket.getName()|slice(0, 77) ~ '...' : Basket.getName() }}</span>
|
||||
<br><span class="basketCount">
|
||||
{{ Basket.getElements().count() }} {{ ' records' }}
|
||||
</span></a>
|
||||
|
@@ -29,6 +29,16 @@
|
||||
{{ "video range extractor" | trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#subtitleEditor" class="subtitleEditortoggle">
|
||||
{{ "prod:videoeditor:subtitleTab:: title" | trans }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#subtitleRequest" class="subtitleEditortoggle">
|
||||
{{ "prod:videoeditor:subtitleRequestTab:: title" | trans }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -82,7 +92,9 @@
|
||||
</video>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="videotools-spinner ui-widget-overlay ui-front hidden" id="videotools-spinner" style="opacity: 0.9">
|
||||
<img src="/assets/common/images/icons/loading.svg" alt="" id="gif-loader">
|
||||
</div>
|
||||
<div id="thumb_camera_button"></div>
|
||||
|
||||
<div class="vertical-divider"></div>
|
||||
@@ -158,6 +170,108 @@
|
||||
<div id="rangeExtractor" class="">
|
||||
<div class="video-range-editor-container"></div>
|
||||
</div>
|
||||
<div id="subtitleEditor" class="subtitleEditor video-subtitle-editor-container">
|
||||
<input type="hidden" id="defaultStartValue" value="00:00:00.000">
|
||||
<input type="hidden" id="defaultEndValue" value="00:00:02.000">
|
||||
<div id="default-item" class="default-item hide">
|
||||
<fieldset class='video-subtitle-item'><span class='number'>0</span>
|
||||
<div class='item-field start-time' ><label>{{ "prod:videoeditor:subtitletab:: Start time" | trans }}</label><input class='time startTime' type='text' name='startTime' size='12' value="00:00:00.000"/></div>
|
||||
<div class='item-field end-time'><label>{{ "prod:videoeditor:subtitletab:: End time" | trans }}</label><input class='time endTime' type='text' name='endTime' size='12'value="00:00:02.000" /></div>
|
||||
<div class='item-field show-for-time'><label>{{ "prod:videoeditor:subtitletab:: Show for" | trans }}</label><input class='showForTime' readonly type='text' size='12' value="00:00:02.000"/></div>
|
||||
<div class='item-field caption-text'><textarea class="captionText" name='captionText' placeholder='{{ "prod:videoeditor:subtitletab:: Caption placeholder" | trans }}' rows='2' ></textarea></div>
|
||||
<div class='remove-item'><i class='fa fa-times-circle'></i></div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<form name="video_subtitle_data" id="video-subtitle-data">
|
||||
<div class="video-subtitle-top">
|
||||
<label>{{ "prod:videoeditor:subtitletab:: work on" | trans }}</label>
|
||||
<select name="meta_struct_id" id="metaStructId">
|
||||
{% for videoTextTrackField in videoTextTrackFields %}
|
||||
<option value="{{ videoTextTrackField.meta_struct_id}}">{{ videoTextTrackField.label}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
{% for videoTextTrackField in videoTextTrackFields %}
|
||||
<input type="hidden" id="caption_{{ videoTextTrackField.meta_struct_id}}" value='{{ videoTextTrackField.value}}' name='databox_id'>
|
||||
{% endfor %}
|
||||
<input type="text" id="record-vtt">
|
||||
<input type="hidden" value='{{ record.get_sbas_id() }}' name='databox_id'>
|
||||
<input type="hidden" value='{{ record.get_record_id() }}' name='record_id'>
|
||||
<input type="hidden" id="no_caption" value='{{ "prod:videoeditor:subtitletab:: No caption message" | trans }}'>
|
||||
</div>
|
||||
</form>
|
||||
<form name="video_subtitle_list" id="video-subtitle-list">
|
||||
<div class="video-subtitle-bottom">
|
||||
<div class="video-subtitle-left">
|
||||
<div class="video-subtitle-left-inner">
|
||||
<div class="fields-wrapper">
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-subtitle-left-button">
|
||||
<button type="button" id="submit-subtitle" class="btn submit-subtitle btn-blue">{{ "prod:videoeditor:subtitletab:: save" | trans }}</button>
|
||||
<button type="button" id="copy-subtitle" class="btn copy-subtitle btn-blue">{{ "prod:videoeditor:subtitletab:: copy to clipboard" | trans }}</button>
|
||||
<button class="add-subtitle-vtt" tabindex="0" type="button" aria-label="Add VTT" title = {{ "prod:videoeditor:subtitletab:: add caption" | trans }}>
|
||||
<i class="fa fa-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-subtitle-right" style="overflow: hidden;">
|
||||
<div class="video-subtitle-wrapper">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div id ="subtitleRequest" class="subtitleRequest">
|
||||
<div class="video-subtitle-bottom">
|
||||
<div class="video-subtitle-left">
|
||||
<div class="video-request-left-inner">
|
||||
<form id="video-subtitle-request" class="video-subtitle-request">
|
||||
<p class="item">
|
||||
<label>{{ "prod:videoeditor:subtitleRequestTab:label:: Provider" | trans }}</label>
|
||||
<select name="subtitleProvider" id="subtitle_provider">
|
||||
<option value="Ginger">Ginger</option>
|
||||
</select>
|
||||
</p>
|
||||
<p class="item">
|
||||
<label>{{ "prod:videoeditor:subtitleRequestTab:label:: Kind" | trans }}</label>
|
||||
<select name="subtitle_kindr" id="subtitle_kindr">
|
||||
<option value="autosubtitling">{{ "prod:videoeditor:subtitleRequestTab:: Autosubtitling" | trans }}</option>
|
||||
</select>
|
||||
</p>
|
||||
<p class="item">
|
||||
<label>{{ "prod:videoeditor:subtitleRequestTab:label:: Source Audio language" | trans }}</label>
|
||||
<select name="subtitle_language_source" id="subtitle_language_source">
|
||||
{% for videoTextTrackField in videoTextTrackFields %}
|
||||
<option value="{{ videoTextTrackField.meta_struct_id}}">{{ videoTextTrackField.label}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</p>
|
||||
<p class="item">
|
||||
<label>{{ "prod:videoeditor:subtitleRequestTab:label:: Language destination" | trans }}</label>
|
||||
<select name="subtitle_language_destination" id="subtitle_language_destination">
|
||||
{% for videoTextTrackField in videoTextTrackFields %}
|
||||
<option value="{{ videoTextTrackField.meta_struct_id}}">{{ videoTextTrackField.label}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</p>
|
||||
<div class="video-subtitle-center-button">
|
||||
<button type="button" id="submit-subtitle-request" class="btn submit-subtitle btn-blue">{{ "prod:videoeditor:subtitleRequestTab:: submit" | trans }}</button>
|
||||
</div>
|
||||
<input type="hidden" value='{{ record.get_sbas_id() }}' name='record_sbas_id'>
|
||||
<input type="hidden" value='{{ record.get_record_id() }}' name='record_record_id'>
|
||||
<p class="text-center alert-wrapper hide" id="request-status">
|
||||
<span class="alert alert-info">{{ "prod:videoeditor:subtitleRequestTab:: Request in process" | trans }}</span>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-subtitle-right">
|
||||
<div class="video-subtitle-wrapper">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
@@ -173,7 +287,14 @@
|
||||
>
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.video-subtitle-editor-container .number {
|
||||
float: none;
|
||||
}
|
||||
.video-subtitle-editor-container .editing .number {
|
||||
float: left;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
var toolsConfig = {
|
||||
selectionLength: {{ selectionLength }},
|
||||
@@ -217,6 +338,8 @@
|
||||
{% for subdef in previewHtml5 %}
|
||||
{
|
||||
ratio: '{{ ratio }}',
|
||||
width: '{{ width }}',
|
||||
height: '{{ height }}',
|
||||
framerate: {{ record.exif[constant('media_subdef::TC_DATA_FRAMERATE')] | round(2) }},
|
||||
type: "{{ subdef.get_mime() }}",
|
||||
src: "{{ subdef.get_url() }}"
|
||||
@@ -231,6 +354,28 @@
|
||||
preferences: {
|
||||
overlapChapters: {% if overlapChapters != NULL %}{{ overlapChapters }}{% else %}1{% endif %},
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$('#submit-subtitle-request').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
console.log("auto-subtitle process");
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/prod/tools/auto-subtitle/',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
databox_id: {{ record.getDataboxId }},
|
||||
record_id: {{ record.getRecordId }},
|
||||
subtitle_language_source: $('#subtitle_language_source option:selected').text(),
|
||||
meta_struct_id_source: $('#subtitle_language_source').val(),
|
||||
subtitle_language_destination: $('#subtitle_language_destination option:selected').text(),
|
||||
meta_struct_id_destination: $('#subtitle_language_destination').val()
|
||||
},
|
||||
success: function success(data) {
|
||||
console.log(data);
|
||||
$('#request-status').removeClass('hide');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
@@ -45,7 +45,7 @@
|
||||
<label for="feed_add_title"><b>{{ 'publication : titre' | trans }}</b> <span>( {{ 'publication : title warning' | trans }} )</span></label>
|
||||
<input class="required_text input-block-level" style="max-width:500px" type="text" name="title" id="feed_add_title" value="{{title}}" />
|
||||
<label><span class="feed_title_warning feed_warning">{{ 'publication : title alert' | trans }}</span></label>
|
||||
<label for="feed_add_subtitle"><b>{{ 'publication : sous titre' | trans }}</b> <span class="feed_subtitle_warning feed_warning">{{ 'publication : subtitle warning' | trans }}</span></label>
|
||||
<label for="feed_add_subtitle"><b>{{ 'publication : sous titre' | trans }}</b> <span>( {{ 'publication : subtitle warning' | trans }} )</span></label>
|
||||
<textarea id="feed_add_subtitle" style="max-width:500px" class="input-block-level" name="subtitle" rows="5">{{desc}}</textarea>
|
||||
<label><span class="feed_subtitle_warning feed_warning">{{ 'publication : subtitle alert' | trans }}</span></label>
|
||||
<label for="feed_add_author_name"><b>{{ 'publication : autheur' | trans }}</b></label>
|
||||
|
@@ -1015,6 +1015,7 @@
|
||||
<input type="hidden" id="push-new-list-title" value="{{ 'prod::push: New list title' | trans }} ">
|
||||
<input type="hidden" id="push-list-name-empty" value="{{ 'prod::push: List name can not be empty' | trans }} ">
|
||||
<input type="hidden" id="btn-add" value="{{ 'prod::push: add' | trans }} ">
|
||||
<input type="hidden" id="export-send-mail-notif" value="{{ 'prod::export: send mail notification' | trans }} ">
|
||||
<script type="text/javascript" id="bitly_loader"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
|
@@ -22,25 +22,24 @@
|
||||
<script type="text/javascript" src="/assets/thesaurus/js/thesaurus{% if not app.debug %}.min{% endif %}.js"></script>
|
||||
{#<script type="text/javascript" src="{{ path('minifier', { 'f' : 'skins/thesaurus/xmlhttp.js' }) }}"></script>#}
|
||||
<script type="text/javascript">
|
||||
function loaded()
|
||||
{
|
||||
window.name="ACCEPT";
|
||||
self.focus();
|
||||
}
|
||||
//$('.close-dialog').trigger('click');
|
||||
function ok()
|
||||
{
|
||||
as = "";
|
||||
if((n=document.forms[0].as.length) > 0)
|
||||
if($(".as_1").length > 0)
|
||||
{
|
||||
for(i=0; i<n && as==""; i++)
|
||||
{
|
||||
if(document.forms[0].as[i].checked)
|
||||
as = document.forms[0].as[i].value;
|
||||
}
|
||||
if($(".as_1")[0].checked) {
|
||||
as = $(".as_1").val();
|
||||
}
|
||||
if($(".as_2").length > 0 && $(".as_2")[0].checked) {
|
||||
as = $(".as_2").val();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
as = document.forms[0].as.value;
|
||||
if($(".as_3").length > 0) {
|
||||
as = $(".as_3").val();
|
||||
}
|
||||
}
|
||||
if(as == "TS")
|
||||
{
|
||||
@@ -59,14 +58,13 @@
|
||||
switch(refresh.item(i).getAttribute("type"))
|
||||
{
|
||||
case "CT":
|
||||
{{ opener }}.reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
case "TH":
|
||||
{{ opener }}.reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.close();
|
||||
}
|
||||
else if(as == "SY")
|
||||
{
|
||||
@@ -85,19 +83,23 @@
|
||||
switch(refresh.item(i).getAttribute("type"))
|
||||
{
|
||||
case "CT":
|
||||
{{ opener }}.reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
case "TH":
|
||||
{{ opener }}.reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.close();
|
||||
}
|
||||
$('.close-dialog').trigger('click');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
$('.close-dialog').trigger('click');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body id="desktop" onload="loaded();" class="dialog">
|
||||
<body id="desktop" class="dialog">
|
||||
|
||||
{% if not cterm_found %}
|
||||
<center>
|
||||
@@ -109,11 +111,9 @@
|
||||
<br/>
|
||||
{{ 'thesaurus:: refresh' | trans }}
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<input style="position:relative; z-index:2; width:100px" type="button" id="cancel_button" value="{{ 'boutton::fermer' | trans }}" onclick="self.close();">
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" class="cancel_btn" id="cancel_button" value="{{ 'boutton::fermer' | trans }}" onclick="closeModal();">
|
||||
</div>
|
||||
{% else %}
|
||||
{% if not term_found %}
|
||||
<center>
|
||||
@@ -125,11 +125,9 @@
|
||||
<br/>
|
||||
{{ 'thesaurus:: refresh' | trans }}
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<input style="position:relative; z-index:2; width:100px" type="button" id="cancel_button" value="{{ 'boutton::fermer' | trans }}" onclick="self.close();">
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" class="cancel_btn" id="cancel_button" value="{{ 'boutton::fermer' | trans }}" onclick="closeModal();">
|
||||
</div>
|
||||
{% else %}
|
||||
{% if acceptable %}
|
||||
<center>
|
||||
@@ -144,9 +142,9 @@
|
||||
{{ 'thesaurus:: Accepter le terme comme' | trans }}
|
||||
<br/><br/><h4>{{ fullpath_src | raw }}</h4><br/><br/>
|
||||
<br/>
|
||||
<input type='radio' name='as' value='TS' checked>{{ 'thesaurus:: comme terme specifique' | trans }}
|
||||
<input type='radio' name='as' class="as_1" value='TS' checked>{{ 'thesaurus:: comme terme specifique' | trans }}
|
||||
<br/><br/>
|
||||
<input type='radio' name='as' value='SY'>
|
||||
<input type='radio' name='as' class="as_2" value='SY'>
|
||||
{% set fullpath_tgt_raw = fullpath_tgt | raw %}
|
||||
{% trans with {'%fullpath_tgt_raw%' : fullpath_tgt_raw} %}thesaurus:: comme synonyme de %fullpath_tgt_raw%{% endtrans %}
|
||||
<br/>
|
||||
@@ -155,13 +153,12 @@
|
||||
{{ 'thesaurus:: Accepter la branche comme' | trans }}
|
||||
{{ 'thesaurus:: comme terme specifique' | trans }}
|
||||
<br/><br/><h4>{{ fullpath_tgt | raw }}</h4><br/><br/>
|
||||
<input type='hidden' name='as' value='TS'>
|
||||
<input type='hidden' name='as' class="as_3" value='TS'>
|
||||
{% endif %}
|
||||
<br/>
|
||||
<br/>
|
||||
<input style="position:relative; z-index:2; width:100px" type="button" id="ok_button" value="{{ 'boutton::valider' | trans }}" onclick="ok();">
|
||||
|
||||
<input style="position:relative; z-index:2; width:100px" type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="self.close();">
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input class="cancel_btn" type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="closeModal();">
|
||||
<input class="validate_btn" type="button" id="ok_button" value="{{ 'boutton::valider' | trans }}" onclick="ok();">
|
||||
</div>
|
||||
</form>
|
||||
</center>
|
||||
{% else %}
|
||||
@@ -171,13 +168,9 @@
|
||||
<br/>
|
||||
{% trans with {'%cfield%' : cfield} %}thesaurus:: A cet emplacement du thesaurus , un candidat du champ %cfield% ne peut etre accepte{% endtrans %}
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<input style="position:relative; z-index:2; width:100px" type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="self.close();">
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input class="cancel_btn" type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="closeModal();">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@@ -13,12 +13,13 @@
|
||||
switch(button)
|
||||
{
|
||||
case "submit":
|
||||
document.forms[0].action = "export_" + format + ".php";
|
||||
document.forms[0].submit();
|
||||
$('.export-form').attr('action',"export_" + format + ".php");
|
||||
$('.export-form').submit();
|
||||
$('.close-dialog').trigger('click');
|
||||
break;
|
||||
case "cancel":
|
||||
self.returnValue = null;
|
||||
self.close();
|
||||
$('.close-dialog').trigger('click');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -49,19 +50,22 @@
|
||||
{
|
||||
var i, f;
|
||||
url = "./export_"+format+".php?bid={{ bid }}&piv={{ piv }}&id={{ id }}&typ={{ typ }}&dlg=0&smp=1";
|
||||
url += "&osl=" + (document.forms[0].osl[0].checked ? "1" : "0");
|
||||
url += "&iln=" + (document.forms[0].iln.checked ? "1" : "0");
|
||||
url += "&hit=" + (document.forms[0].hit.checked ? "1" : "0");
|
||||
url += "&ilg=" + (document.forms[0].ilg.checked ? "1" : "0");
|
||||
url += "&osl=" + ($('.osl_1')[0].checked ? "1" : $('.osl_0')[0].checked ? "0" : "0");
|
||||
url += "&iln=" + ($('.iln')[0].checked ? "1" : "0");
|
||||
url += "&hit=" + ($('.hit')[0].checked ? "1" : "0");
|
||||
url += "&ilg=" + ($('.ilg')[0].checked ? "1" : "0");
|
||||
document.getElementById("ifrsample").src = url;
|
||||
}
|
||||
$( document ).ready(function() {
|
||||
loaded();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loaded();" class="dialog">
|
||||
<body class="dialog">
|
||||
<center>
|
||||
<br/>
|
||||
<form onsubmit="clkBut('submit');return(false);" action="export_topics.php" target="EXPORT2">
|
||||
<input type="hidden" name="bid" value="{{ bid }}" >
|
||||
<form class="export-form" action="export_topics.php" target="EXPORT2">
|
||||
<input type="hidden" name="bid" value="{{ bid }}">
|
||||
<input type="hidden" name="piv" value="{{ piv }}" >
|
||||
<input type="hidden" name="id" value="{{ id }}" >
|
||||
<input type="hidden" name="typ" value="{{ typ }}" >
|
||||
@@ -82,23 +86,23 @@
|
||||
</div>
|
||||
<div id='subform_text' style="margin-left:10px;">
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='osl' checked value='1' onclick="chgFormat();">
|
||||
<input type='radio' name='osl' class="osl_1" checked value='1' onclick="chgFormat();">
|
||||
{{ 'thesaurus:: exporter avec les synonymes sur la meme ligne' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='osl' value='0' onclick="chgFormat();">
|
||||
<input type='radio' name='osl' class="osl_0" value='0' onclick="chgFormat();">
|
||||
{{ 'thesaurus:: exporter avec une ligne par synonyme' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='checkbox' name='iln' value='1' onclick="chgFormat();">
|
||||
<input type='checkbox' name='iln' class="iln" value='1' onclick="chgFormat();">
|
||||
{{ 'thesaurus:: export : numeroter les lignes' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='checkbox' name='ilg' value='1' onclick="chgFormat();">
|
||||
<input type='checkbox' name='ilg' class="ilg" value='1' onclick="chgFormat();">
|
||||
{{ 'thesaurus:: export : inclure la langue' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='checkbox' name='hit' value='1' onclick="chgFormat();">
|
||||
<input type='checkbox' name='hit' class="hit" value='1' onclick="chgFormat();">
|
||||
{{ 'thesaurus:: export : inclure les hits' | trans }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,10 +114,11 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
<br/>
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" style="width:100px;">
|
||||
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');" style="width:100px;">
|
||||
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" id="cancel_button" class="cancel_btn" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');">
|
||||
<input type="button" id="submit_button" class="validate_btn" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
</div>
|
||||
</form>
|
||||
</center>
|
||||
</body>
|
||||
|
@@ -11,12 +11,12 @@
|
||||
switch(button)
|
||||
{
|
||||
case "submit":
|
||||
document.forms[0].target = (format == 'tofiles' ? "_self" : "EXPORT2");
|
||||
document.forms[0].submit();
|
||||
$('.export-topics-form').submit();
|
||||
$('.close-dialog').trigger('click');
|
||||
break;
|
||||
case "cancel":
|
||||
self.returnValue = null;
|
||||
self.close();
|
||||
$('.close-dialog').trigger('click');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -45,21 +45,25 @@
|
||||
}
|
||||
function chgFormat()
|
||||
{
|
||||
var i, f;
|
||||
for(i=0; i<document.forms[0].ofm.length; i++)
|
||||
var i;
|
||||
for(i=0; i<$('.ofm').length; i++)
|
||||
{
|
||||
f = document.forms[0].ofm[i].value;
|
||||
if(document.forms[0].ofm[i].checked)
|
||||
{
|
||||
format = f;
|
||||
if($(".ofm_1")[0].checked) {
|
||||
format = $(".ofm_1").val();
|
||||
}
|
||||
if($(".ofm_2")[0].checked) {
|
||||
format = $(".ofm_2").val();
|
||||
}
|
||||
}
|
||||
}
|
||||
$( document ).ready(function() {
|
||||
loaded();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loaded();" class="dialog">
|
||||
<body class="dialog">
|
||||
<center>
|
||||
<form onsubmit="clkBut('submit');return(false);" action="export_topics.php">
|
||||
<form action="export_topics.php" class="export-topics-form" target="EXPORT2">
|
||||
<input type="hidden" name="bid" value="{{ bid }}" >
|
||||
<input type="hidden" name="piv" value="{{ piv }}" >
|
||||
<input type="hidden" name="id" value="{{ id }}" >
|
||||
@@ -67,15 +71,15 @@
|
||||
<input type="hidden" name="dlg" value="{{ dlg }}" >
|
||||
<input type="hidden" name="obr" value="{{ obr }}" >
|
||||
|
||||
<div style="padding:10px;">
|
||||
<div style="padding: 5px 15px">
|
||||
<div class="x3Dbox">
|
||||
<span class="title">{{ 'thesaurus:: exporter' | trans }}</span>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='ofm' checked value='tofiles' onclick="chgFormat();">
|
||||
<input type='radio' name='ofm' class="ofm ofm_1" checked value='tofiles' onclick="chgFormat();">
|
||||
{{ 'thesaurus:: exporter vers topics pour toutes les langues' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='ofm' value='toscreen' onclick="chgFormat();">
|
||||
<input type='radio' name='ofm' value='toscreen' class="ofm ofm_2" onclick="chgFormat();">
|
||||
{% trans with {'%piv%' : piv} %}thesaurus:: exporter a l'ecran pour la langue %piv%{% endtrans %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -85,7 +89,7 @@
|
||||
<div class="x3Dbox">
|
||||
<span class="title">{{ 'phraseanet:: tri' | trans }}</span>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='checkbox' name='srt' checked onclick="chgFormat();">
|
||||
<input type='checkbox' name='srt' checked >
|
||||
{{ 'phraseanet:: tri par date' | trans }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -95,15 +99,15 @@
|
||||
<div class="x3Dbox">
|
||||
<span class="title">{{ 'thesaurus:: recherche' | trans }}</span>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='sth' value="1" checked onclick="chgFormat();">
|
||||
<input type='radio' name='sth' value="1" checked >
|
||||
{{ 'thesaurus:: recherche thesaurus *:"query"' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='sth' value="0" onclick="chgFormat();">
|
||||
<input type='radio' name='sth' value="0" >
|
||||
{{ 'thesaurus:: recherche fulltext' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='checkbox' name='sand' onclick="chgFormat();">
|
||||
<input type='checkbox' name='sand' >
|
||||
{{ 'thesaurus:: question complete (avec operateurs)' | trans }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -113,30 +117,31 @@
|
||||
<div class="x3Dbox">
|
||||
<span class="title">{{ 'thesaurus:: presentation' | trans }}</span>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='obrf' value="from_itf_closable" checked onclick="chgFormat();">
|
||||
<input type='radio' name='obrf' value="from_itf_closable" checked >
|
||||
{{ 'thesaurus:: presentation : branches refermables' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='obrf' value="from_itf_static" onclick="chgFormat();">
|
||||
<input type='radio' name='obrf' value="from_itf_static" >
|
||||
{{ 'thesaurus:: presentation : branche ouvertes' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='obrf' value="all_opened_closable" onclick="chgFormat();">
|
||||
<input type='radio' name='obrf' value="all_opened_closable" >
|
||||
{{ 'thesaurus:: tout deployer - refermable' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='obrf' value="all_opened_static" onclick="chgFormat();">
|
||||
<input type='radio' name='obrf' value="all_opened_static" >
|
||||
{{ 'thesaurus:: tout deployer - statique' | trans }}
|
||||
</div>
|
||||
<div style="white-space:nowrap">
|
||||
<input type='radio' name='obrf' value="all_closed" onclick="chgFormat();">
|
||||
<input type='radio' name='obrf' value="all_closed" >
|
||||
{{ 'thesaurus:: tout fermer' | trans }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" style="width:100px;">
|
||||
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');" style="width:100px;">
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" id="cancel_button" class="cancel_btn" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');">
|
||||
<input type="button" id="submit_button" class="validate_btn" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
</div>
|
||||
</form>
|
||||
</center>
|
||||
</body>
|
||||
|
@@ -32,12 +32,9 @@
|
||||
{% endfor %}
|
||||
|
||||
{% if ofm == 'tofiles' %}
|
||||
<center>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<input type="button" value="{{ 'boutton::fermer' | trans }}" onclick="self.close();" style="width:100px;">
|
||||
</center>
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" class="cancel_btn" value="{{ 'boutton::fermer' | trans }}" onclick=" self.close();" style="width:120px;">
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
|
@@ -15,13 +15,12 @@
|
||||
{
|
||||
switch(button)
|
||||
{
|
||||
case "submit":
|
||||
document.forms[0].target='IFRIM';
|
||||
document.forms[0].submit();
|
||||
case "submit":=
|
||||
$('.import-form').submit();
|
||||
break;
|
||||
case "cancel":
|
||||
self.returnValue = null;
|
||||
self.close();
|
||||
$('.close-dialog').trigger('click');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -32,8 +31,7 @@
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
{{ opener }}.reload();
|
||||
self.close();
|
||||
$('.close-dialog').trigger('click');
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -44,7 +42,7 @@
|
||||
</head>
|
||||
<body onload="loaded();" class="dialog">
|
||||
<br/>
|
||||
<form onsubmit="clkBut('submit');return(false);" action="import.php" enctype="multipart/form-data" method="post">
|
||||
<form onsubmit="clkBut('submit');return(false);" action="import.php" enctype="multipart/form-data" method="post" class="import-form" target="IFRIM">
|
||||
<input type="hidden" name="bid" value="{{ bid }}" >
|
||||
<input type="hidden" name="piv" value="{{ piv }}" >
|
||||
<input type="hidden" name="id" value="{{ id }}" >
|
||||
@@ -57,7 +55,7 @@
|
||||
<input type="file" name="fil" /> (max 16Mo)
|
||||
<br/>
|
||||
|
||||
<div style="text-align:center">
|
||||
<div class="text-center">
|
||||
<table>
|
||||
<tr>
|
||||
<td style="text-align:left"><input type="checkbox" disabled="disabled" name="dlk" checked="checked">{{ 'thesaurus:: supprimer les liens des champs tbranch' | trans }}</td>
|
||||
@@ -67,10 +65,11 @@
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" style="width:100px;">
|
||||
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');" style="width:100px;">
|
||||
</div>
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" >
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
</div>
|
||||
</divclass>
|
||||
</form>
|
||||
<iframe style="display:block; height:50px;" name="IFRIM"></iframe>
|
||||
</body>
|
||||
|
@@ -25,41 +25,55 @@
|
||||
switch(button)
|
||||
{
|
||||
case "submit":
|
||||
// document.forms[0].target="LINKFIELD";
|
||||
document.forms[0].submit();
|
||||
$('.link-field-1').submit(
|
||||
$.ajax({
|
||||
url : 'linkfield2.php',
|
||||
type : 'POST',
|
||||
data : $('.link-field-1').serialize(),
|
||||
success : function( data ) {
|
||||
$("#DLG_LINK_FIELD_1").html('');
|
||||
$("#DLG_LINK_FIELD_1").append(data);
|
||||
},
|
||||
error : function( xhr, err ) {
|
||||
alert('Error');
|
||||
}
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "cancel":
|
||||
self.close();
|
||||
$('.close-dialog').trigger('click');
|
||||
break;
|
||||
}
|
||||
}
|
||||
function loaded()
|
||||
{
|
||||
window.name="LINKFIELD";
|
||||
ckField();
|
||||
}
|
||||
$( document ).ready(function() {
|
||||
loaded();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loaded();" class="dialog">
|
||||
<center>
|
||||
<form action="linkfield2.php" method="post" target="LINKFIELD">
|
||||
<input type="hidden" name="piv" value="{{ piv }}">
|
||||
<input type="hidden" name="bid" value="{{ bid }}">
|
||||
<input type="hidden" name="tid" value="{{ tid }}">
|
||||
<body class="dialog">
|
||||
|
||||
{% set branch = "<br/><b>" ~ fullBranch ~ "</b><br/>" %}
|
||||
{% trans with {'%branch%' : branch} %}thesaurus:: Lier la branche de thesaurus au champ %branch%{% endtrans %}
|
||||
<form class="link-field-1" action="linkfield2.php" method="post" target="LINKFIELD" style="padding: 5px 15px">
|
||||
<input type="hidden" name="piv" value="{{ piv }}">
|
||||
<input type="hidden" name="bid" value="{{ bid }}">
|
||||
<input type="hidden" name="tid" value="{{ tid }}">
|
||||
|
||||
<div style="width:70%; height:200px; overflow:scroll;" class="x3Dbox">
|
||||
{% for fieldname, checked in fieldnames %}
|
||||
<input type="checkbox" name="field[]" value="{{ fieldname }}" {% if checked %}checked{% endif %} ck0="{% if checked %}1{% else %}0{% endif %}" onclick="return(ckField());">{{ fieldname }}<br/>
|
||||
{% endfor %}
|
||||
{% set branch = "<br/><b>" ~ fullBranch ~ "</b><br/>" %}
|
||||
{% trans with {'%branch%' : branch} %}thesaurus:: Lier la branche de thesaurus au champ %branch%{% endtrans %}
|
||||
|
||||
<div style="width:100%; height:270px; overflow:scroll;" class="x3Dbox">
|
||||
{% for fieldname, checked in fieldnames %}
|
||||
<input type="checkbox" name="field[]" value="{{ fieldname }}" {% if checked %}checked{% endif %} ck0="{% if checked %}1{% else %}0{% endif %}" onclick="return(ckField());">{{ fieldname }}<br/>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" id="cancel_button" class="cancel_btn" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');">
|
||||
<input type="button" id="submit_button" class="validate_btn" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
</div>
|
||||
<br/>
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');">
|
||||
</form>
|
||||
</center>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -12,10 +12,23 @@
|
||||
switch(button)
|
||||
{
|
||||
case "submit":
|
||||
document.forms[0].submit();
|
||||
$('.link-field-2').submit(
|
||||
$.ajax({
|
||||
url : 'linkfield3.php',
|
||||
type : 'POST',
|
||||
data : $('.link-field-2').serialize(),
|
||||
success : function( data ) {
|
||||
$("#DLG_LINK_FIELD_1").html('');
|
||||
$("#DLG_LINK_FIELD_1").append(data);
|
||||
},
|
||||
error : function( xhr, err ) {
|
||||
alert('Error');
|
||||
}
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "cancel":
|
||||
self.close();
|
||||
$('.close-dialog').trigger('click');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -23,11 +36,15 @@
|
||||
{
|
||||
window.name="LINKFIELD";
|
||||
}
|
||||
$( document ).ready(function() {
|
||||
loaded();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loaded();" class="dialog">
|
||||
<body class="dialog">
|
||||
<center>
|
||||
<form action="linkfield3.php" method="post" target="LINKFIELD">
|
||||
<form class="link-field-2" action="linkfield3.php" method="post" target="LINKFIELD">
|
||||
<div class="text-center">
|
||||
<input type="hidden" name="piv" value="{{ piv }}">
|
||||
<input type="hidden" name="bid" value="{{ bid }}">
|
||||
<input type="hidden" name="tid" value="{{ tid }}">
|
||||
@@ -68,10 +85,11 @@
|
||||
{% else %}
|
||||
<div style='position:absolute; top:5px; left:0px; width:100%; text-align:center; color:green'>{{ 'thesaurus:: pas de reindexation' | trans }}</div>
|
||||
{% endif %}
|
||||
<br/>
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');">
|
||||
</div>
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" id="cancel_button" class="cancel_btn" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');">
|
||||
<input type="button" id="submit_button" class="validate_btn" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
</div>
|
||||
</form>
|
||||
</center>
|
||||
</body>
|
||||
|
@@ -41,8 +41,9 @@
|
||||
<br/>
|
||||
{% endif %}
|
||||
</div>
|
||||
<br/>
|
||||
<input type="button" value="{{ 'boutton::fermer' | trans }}" onclick="self.close();">
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" value="{{ 'boutton::fermer' | trans }}" class="cancel_btn" onclick="$('.close-dialog').trigger('click');">
|
||||
</div>
|
||||
</form>
|
||||
</center>
|
||||
</body>
|
||||
|
@@ -8,6 +8,7 @@
|
||||
{#<script type="text/javascript" src="{{ path('minifier', { 'f' : 'skins/thesaurus/xmlhttp.js' }) }}"></script>#}
|
||||
</head>
|
||||
<body onload="loaded();" class="dialog" style="text-align:center">
|
||||
<div class="text-center">
|
||||
{% if dlg is not none %}
|
||||
{% set opener = 'window.dialogArguments.win' %}
|
||||
{% else %}
|
||||
@@ -37,8 +38,9 @@
|
||||
<br/>
|
||||
{{ prop_label }}
|
||||
<br/>
|
||||
<center>
|
||||
<form onsubmit="return(false);">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<form onsubmit="return(false);" class="thesaurus_confirm_bottom_block">
|
||||
<input type="hidden" name="bid" value="{{ bid }} ">
|
||||
<input type="hidden" name="pid" value="{{ pid }}">
|
||||
<div class='x3Dbox' style='margin:15px; height:100px; overflow:auto;'>
|
||||
@@ -50,34 +52,27 @@
|
||||
{{ 'thesaurus:: selectionner la provenance a accepter' | trans }}
|
||||
{% endif %}
|
||||
<br/>
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" style="width:100px;">
|
||||
<input type="button" id="cancel_button" class="cancel_btn" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" >
|
||||
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');" style="width:100px;">
|
||||
<input type="button" id="submit_button" class="validate_btn" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');">
|
||||
</form>
|
||||
</center>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if nb_candidates_bad > 0 %}
|
||||
{% set prop_label = 'thesaurus:: est candidat en provenance des champs mais ne peut etre accepte a cet emplacement du thesaurus' | trans %}
|
||||
{% else %}
|
||||
{% set prop_label = 'thesaurus:: n\'est pas present dans les candidats' | trans %}
|
||||
{% endif %}
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<br/>
|
||||
{{ zterm }}
|
||||
<br/>
|
||||
<br/>
|
||||
{{ prop_label }}
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<form>
|
||||
<input type="button" id="cancel_button" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" style="width:100px;">
|
||||
<form class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" id="cancel_button" class="cancel_btn" value="{{ 'boutton::annuler' | trans }}" onclick="clkBut('cancel');" >
|
||||
|
||||
<input type="button" id="submit_button" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');" style="width:100px;">
|
||||
<input type="button" id="submit_button" class="validate_btn" value="{{ 'boutton::valider' | trans }}" onclick="clkBut('submit');" >
|
||||
</form>
|
||||
{% endif %}
|
||||
</body>
|
||||
@@ -119,17 +114,19 @@
|
||||
switch(refresh.item(i).getAttribute("type"))
|
||||
{
|
||||
case "CT":
|
||||
{{ opener }}.reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
case "TH":
|
||||
{{ opener }}.reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.close();
|
||||
$("#NEWSY_DLG_CONFIRM").dialog('close');
|
||||
$("#NEWSY_DLG_CONFIRM").html('');
|
||||
break;
|
||||
case "cancel":
|
||||
self.close();
|
||||
$("#NEWSY_DLG_CONFIRM").dialog('close');
|
||||
$("#NEWSY_DLG_CONFIRM").html('');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -141,18 +138,18 @@
|
||||
switch(button)
|
||||
{
|
||||
case "submit":
|
||||
{% if typ == "TS" %}
|
||||
url = "xmlhttp/newts.x.php";
|
||||
{% else %}
|
||||
url = "xmlhttp/newsy.x.php";
|
||||
{% endif %}
|
||||
{% if typ == "TS" %}
|
||||
url = "xmlhttp/newts.x.php";
|
||||
{% else %}
|
||||
url = "xmlhttp/newsy.x.php";
|
||||
{% endif %}
|
||||
parms = "bid={{ bid }}";
|
||||
parms += "&piv={{ piv }}";
|
||||
parms += "&pid={{ pid }}";
|
||||
parms += "&t={{ term | url_encode }}";
|
||||
{% if context is not none %}
|
||||
parms += "&k={{ context | url_encode }}";
|
||||
{% endif %}
|
||||
{% if context is not none %}
|
||||
parms += "&k={{ context | url_encode }}";
|
||||
{% endif %}
|
||||
parms += "&sylng={{ sylng }}";
|
||||
parms += "&reindex=0";
|
||||
|
||||
@@ -163,17 +160,20 @@
|
||||
switch(refresh.item(i).getAttribute("type"))
|
||||
{
|
||||
case "CT":
|
||||
{{ opener }}.reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
$("#NEWSY_DLG_CONFIRM").dialog('close');
|
||||
reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
case "TH":
|
||||
{{ opener }}.reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
$("#NEWSY_DLG_CONFIRM").dialog('close');
|
||||
reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.close();
|
||||
break;
|
||||
case "cancel":
|
||||
self.close();
|
||||
$("#NEWSY_DLG_CONFIRM").dialog('close');
|
||||
$("#NEWSY_DLG_CONFIRM").html('');
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -3,11 +3,6 @@
|
||||
{% else %}
|
||||
{% set opener = "opener" %}
|
||||
{% endif %}
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html lang="{{ app['locale'] }}">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>{{ 'thesaurus:: Proprietes' | trans }}</title>
|
||||
<link type="text/css" rel="stylesheet" href="/assets/thesaurus/css/thesaurus{% if not app.debug %}.min{% endif %}.css" />
|
||||
<style type="text/css">
|
||||
a
|
||||
@@ -24,38 +19,31 @@
|
||||
font-weight:900;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="/assets/vendors/jquery/jquery{% if not app.debug %}.min{% endif %}.js"></script>
|
||||
<script type="text/javascript" src="/assets/thesaurus/js/thesaurus{% if not app.debug %}.min{% endif %}.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function loaded()
|
||||
{
|
||||
window.name="PROPERTIES";
|
||||
self.focus();
|
||||
}
|
||||
$( document ).ready(function() {
|
||||
loaded();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body id="desktop" onload="loaded();" class="dialog">
|
||||
<div class="menu" id="flagsMenu" style="z-index:50">
|
||||
{% for code, language in languages %}
|
||||
<a id='flagMenu_{{ code }}' href='javascript:void(0)' class=''>
|
||||
<img src='/assets/common/images/lng/{{ code }}_flag_18.gif' />{{ language }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="menu" id="syMenu" style="z-index:50">
|
||||
<a href="javascript:void(0)" id="delete_sy">{{ 'thesaurus::menu: supprimer' | trans }}</a>
|
||||
</div>
|
||||
<div class="menu" id="syMenu" style="z-index:999">
|
||||
<a href="javascript:void(0)" id="delete_sy">{{ 'thesaurus:properties:: Mettre dans le stock' | trans }}</a>
|
||||
</div>
|
||||
<div id="desktop" class="dialog">
|
||||
|
||||
<div style='text-align:right'>
|
||||
<H4>{{ fullpath | raw }}</H4>
|
||||
<div style='float:right'>
|
||||
<b>id:</b> {{ id }}
|
||||
</div>
|
||||
<H4>{{ fullpath | raw }}</H4><br/>
|
||||
{% if typ == "CT" %}
|
||||
<br/>
|
||||
{% elseif typ == "TH" %}
|
||||
{#{% elseif typ == "TH" %}
|
||||
{% trans with {'%hits%' : hits} %}thesaurus:: %hits% reponses retournees{% endtrans %}
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>#}
|
||||
{% endif %}
|
||||
<div id="TSY" class="tableContainer" style="margin:10px; position:relative; top:0px; left:0px">
|
||||
<div>
|
||||
@@ -71,9 +59,7 @@
|
||||
<th> </th>
|
||||
<th> </th>
|
||||
<th>{{ 'thesaurus:: synonymes' | trans }}</th>
|
||||
<th>{{ 'thesaurus:: hits' | trans }}</th>
|
||||
<th>{{ 'thesaurus:: ids' | trans }}</th>
|
||||
<th></th>
|
||||
<th colspan="3">{{ 'thesaurus:termePorperties:termeId' | trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
@@ -99,13 +85,13 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if data['lng'] %}
|
||||
<td id='FLG_{{ data['id'] }}'><img src='/assets/common/images/lng/{{ data['lng'] }}_flag_18.gif' /></td>
|
||||
<td id='FLG_{{ data['id'] }}'>{{ data['lng'] }}</td>
|
||||
{% else %}
|
||||
<td id='FLG_{{ data['id'] }}'><img src='/assets/thesaurus/images/noflag.gif' /></td>
|
||||
<td id='FLG_{{ data['id'] }}'></td>
|
||||
{% endif %}
|
||||
<td>{{ data['t'] }}</td>
|
||||
<td>{{ data['hits'] }}</td>
|
||||
<td>{{ data['id'] }}</td>
|
||||
<td><span class="delete_term"></span></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -115,13 +101,17 @@
|
||||
</div>
|
||||
<center>
|
||||
<form onsubmit="return(false);">
|
||||
<input style="position:relative; z-index:2" type="button" id="close_button" value="{{ 'boutton::fermer' | trans }}" onclick="self.close();">
|
||||
<div class="thesaurus_confirm_bottom_block">
|
||||
<input type="button" id="close_button" class="close_button cancel_btn" value="{{ 'boutton::fermer' | trans }}" >
|
||||
</div>
|
||||
</form>
|
||||
</center>
|
||||
<script type="text/javascript">
|
||||
$(".close_button").on("click", function(){
|
||||
$('.close-dialog').trigger('click');
|
||||
});
|
||||
// gui callback du menu des drapeaux
|
||||
var nsy = {{ synonyms | length }};
|
||||
|
||||
function cbME_flags(action, cbParm, menuelem_id)
|
||||
{
|
||||
if(action != "SELECT" || !menuelem_id) {
|
||||
@@ -148,17 +138,23 @@
|
||||
switch(refresh.item(i).getAttribute("type"))
|
||||
{
|
||||
case "CT":
|
||||
{{ opener }}.reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
{{ opener }}.myGUI.select({{ opener }}.document.getElementById("THE_{{ id }}"));
|
||||
reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
myGUI.select(document.getElementById("THE_{{ id }}"));
|
||||
break;
|
||||
case "TH":
|
||||
{{ opener }}.reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
{{ opener }}.myGUI.select({{ opener }}.document.getElementById("THE_{{ id }}"));
|
||||
reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
myGUI.select(document.getElementById("THE_{{ id }}"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$('.delete_term').click(function (e) {
|
||||
e.preventDefault();
|
||||
$('#delete_sy').trigger('click');
|
||||
});
|
||||
|
||||
// gui callback du menu des synonymes
|
||||
function cbME_synonym(action, cbParm, menuelem_id)
|
||||
{
|
||||
@@ -169,6 +165,7 @@
|
||||
// pas d'action possible s'il ne reste qu'un seul synonyme
|
||||
// alert(nsy);
|
||||
document.getElementById("delete_sy").className = "disabled";
|
||||
$('.delete_term').addClass('disabled');
|
||||
// document.getElementById("reject_sy").className = "disabled";
|
||||
}
|
||||
else
|
||||
@@ -178,12 +175,14 @@
|
||||
// y'a des hits, on peut pas supprimer
|
||||
// document.getElementById("reject_sy").className = "";
|
||||
document.getElementById("delete_sy").className = "";
|
||||
$('.delete_term').removeClass('disabled');
|
||||
}
|
||||
else
|
||||
{
|
||||
// pas de hits : on peut supprimer
|
||||
// document.getElementById("reject_sy").className = "";
|
||||
document.getElementById("delete_sy").className = "";
|
||||
$('.delete_term').removeClass('disabled');
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -216,7 +215,7 @@
|
||||
ret = loadXMLDoc(url, parms, true);
|
||||
|
||||
sy_list = ret.getElementsByTagName("sy_list").item(0);
|
||||
refresh_sy(sy_list);
|
||||
//refresh_sy(sy_list);
|
||||
|
||||
refresh = ret.getElementsByTagName("refresh");
|
||||
for(i=0; i<refresh.length; i++)
|
||||
@@ -224,15 +223,24 @@
|
||||
switch(refresh.item(i).getAttribute("type"))
|
||||
{
|
||||
case "CT":
|
||||
{{ opener }}.reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
{{ opener }}.myGUI.select({{ opener }}.document.getElementById("THE_{{ id }}"));
|
||||
reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
myGUI.select(document.getElementById("THE_{{ id }}"));
|
||||
break;
|
||||
case "TH":
|
||||
{{ opener }}.reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
{{ opener }}.myGUI.select({{ opener }}.document.getElementById("THE_{{ id }}"));
|
||||
reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
myGUI.select(document.getElementById("THE_{{ id }}"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
var new_url = $('#url_properties').val();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: `${new_url}`,
|
||||
success: function(data){
|
||||
$('#DLG_PROPERTIES').html('');
|
||||
$('#DLG_PROPERTIES').append(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -273,16 +281,16 @@
|
||||
td = tr.appendChild(document.createElement("td"));
|
||||
td.id = "FLG_"+(nsy+1);
|
||||
// td.innerText = n.getAttribute("lng");
|
||||
img = td.appendChild(document.createElement("img"));
|
||||
img.setAttribute("src", "/assets/common/images/lng/"+n.getAttribute("lng")+"_flag_18.gif");
|
||||
span = td.appendChild(document.createElement("span"));
|
||||
span.innerHTML = n.getAttribute("lng");
|
||||
|
||||
td = tr.appendChild(document.createElement("td"));
|
||||
// td.colSpan = "2";
|
||||
// td.setAttribute("colSpan", "3"); // attention au 'S' majuscule !!!
|
||||
td.innerHTML = n.getAttribute("t");
|
||||
|
||||
td = tr.appendChild(document.createElement("td"));
|
||||
td.innerHTML = n.getAttribute("hits");
|
||||
/*td = tr.appendChild(document.createElement("td"));
|
||||
td.innerHTML = n.getAttribute("hits");*/
|
||||
|
||||
td = tr.appendChild(document.createElement("td"));
|
||||
td.innerHTML = n.getAttribute("id");
|
||||
@@ -308,15 +316,6 @@
|
||||
;
|
||||
if(tr)
|
||||
myGUI.select(tr);
|
||||
switch(o.id.substr(0, 4))
|
||||
{
|
||||
case "FLG_": // le drapeau
|
||||
document.getElementById("flagsMenu").runAsMenu( evt, tr );
|
||||
break;
|
||||
case "SYN_": // le synonyme
|
||||
document.getElementById("syMenu").runAsMenu( evt, tr );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "MOUSEDOWN":
|
||||
@@ -335,6 +334,21 @@
|
||||
syChgPos(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(o.id.substr(0, 4))
|
||||
{
|
||||
case "FLG_": // le drapeau
|
||||
document.getElementById("flagsMenu").runAsMenu( evt, tr );
|
||||
break;
|
||||
case "SYN_": // le synonyme
|
||||
if (stock == false)
|
||||
{
|
||||
document.getElementById("syMenu").runAsMenu(evt, tr);
|
||||
$('.delete_term').html('');
|
||||
$('.delete_term', tr).append($('#syMenu').html());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "DBLCLICK":
|
||||
@@ -368,12 +382,12 @@
|
||||
switch(refresh.item(i).getAttribute("type"))
|
||||
{
|
||||
case "CT":
|
||||
{{ opener }}.reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
{{ opener }}.myGUI.select({{ opener }}.document.getElementById("THE_{{ id }}"));
|
||||
reloadCtermsBranch(refresh.item(i).getAttribute("id"));
|
||||
myGUI.select(document.getElementById("THE_{{ id }}"));
|
||||
break;
|
||||
case "TH":
|
||||
{{ opener }}.reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
{{ opener }}.myGUI.select({{ opener }}.document.getElementById("THE_{{ id }}"));
|
||||
reloadThesaurusBranch(refresh.item(i).getAttribute("id"));
|
||||
myGUI.select(document.getElementById("THE_{{ id }}"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -383,7 +397,5 @@
|
||||
myGUI.setClickable("TSY", cbDD_TSY);
|
||||
myGUI.setAsMenu("flagsMenu", cbME_flags);
|
||||
myGUI.setAsMenu("syMenu", cbME_synonym);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</div>
|
||||
|