├── .github ├── ISSUE_TEMPLATE │ └── bug_report.yml ├── dependabot.yml ├── label-commenter-config.yml ├── pull_request_template.md └── workflows │ ├── auto-tag-new-version.yml │ ├── close_stale_issue.yml │ ├── continuous-integration.yml │ ├── label-commenter.yml │ ├── locales-sync.yml │ ├── locales-update-source.yml │ └── release.yml ├── .gitignore ├── .php-cs-fixer.php ├── .phpcs.xml ├── .twig_cs.dist.php ├── .tx └── config ├── CHANGELOG.md ├── LICENSE ├── README.md ├── SECURITY.md ├── ajax ├── container.php ├── container_display_condition.php ├── container_itemtypes_dropdown.php ├── container_subtype_dropdown.php ├── field_specific_fields.php ├── reorder.php ├── status_override.php └── viewtranslations.php ├── composer.json ├── composer.lock ├── css └── fields.css ├── docs ├── glpi_network.png ├── logo.png └── screenshots │ ├── fields.gif │ ├── hide_block.png │ └── override_by_status.png ├── front ├── commondropdown.form.php ├── commondropdown.php ├── container.form.php ├── container.php ├── containerdisplaycondition.form.php ├── export_to_yaml.php ├── field.form.php ├── labeltranslation.form.php ├── profile.form.php ├── regenerate_files.php └── statusoverride.form.php ├── hook.php ├── inc ├── abstractcontainerinstance.class.php ├── autoload.php ├── checkdatabasecommand.class.php ├── command │ └── regeneratefilescommand.class.php ├── container.class.php ├── containerdisplaycondition.class.php ├── dropdown.class.php ├── field.class.php ├── inventory.class.php ├── labeltranslation.class.php ├── menu.class.php ├── migration.class.php ├── profile.class.php ├── statusoverride.class.php └── toolbox.class.php ├── js └── drag-field-row.js ├── lib └── redips-drag-min.js ├── locales ├── cs_CZ.mo ├── cs_CZ.po ├── de_DE.mo ├── de_DE.po ├── en_GB.mo ├── en_GB.po ├── en_US.mo ├── en_US.po ├── es_AR.mo ├── es_AR.po ├── es_EC.mo ├── es_EC.po ├── es_ES.mo ├── es_ES.po ├── es_MX.mo ├── es_MX.po ├── fi_FI.mo ├── fi_FI.po ├── fields.pot ├── fr_FR.mo ├── fr_FR.po ├── hr_HR.mo ├── hr_HR.po ├── it_IT.mo ├── it_IT.po ├── ja_JP.mo ├── ja_JP.po ├── ko_KR.mo ├── ko_KR.po ├── pl_PL.mo ├── pl_PL.po ├── pt_BR.mo ├── pt_BR.po ├── pt_PT.mo ├── pt_PT.po ├── ro_RO.mo ├── ro_RO.po ├── ru_RU.mo ├── ru_RU.po ├── sk_SK.mo ├── sk_SK.po ├── tr_TR.mo ├── tr_TR.po ├── uk_UA.mo ├── uk_UA.po ├── zh_CN.mo └── zh_CN.po ├── phpstan.neon ├── pics ├── container.png └── field.png ├── plugin.xml ├── setup.php ├── templates ├── container.class.tpl ├── container_display_conditions.html.twig ├── dropdown.class.tpl ├── dropdown.form.tpl ├── dropdown.tpl ├── fields.html.twig ├── forms │ ├── container_display_condition.html.twig │ ├── container_display_condition_so_condition.html.twig │ └── status_override.html.twig ├── injection.class.tpl └── status_overrides.html.twig └── tools └── HEADER /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a report to help us improve fields 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | 8 | Dear GLPI plugin user. 9 | 10 | **⚠️ Please never use standard issues to report security problems. See [security policy](https://github.com/pluginsGLPI/fields/security/policy) for more details. ⚠️** 11 | 12 | BEFORE SUBMITTING YOUR ISSUE, please make sure to read and follow these steps: 13 | 14 | * We do not track feature requests nor enhancements here. Propose them on the [suggest dedicated site](https://suggest.glpi-project.org). 15 | * Keep this tracker in ENGLISH. If you want support in your language, the [community forum](https://forum.glpi-project.org) is the best place. 16 | * Always try to reproduce your issue at least on latest stable release. 17 | 18 | The GLPI team. 19 | - type: markdown 20 | attributes: 21 | value: | 22 | ## Professional Support 23 | 24 | We do not guarantee any processing / resolution time for community issues. 25 | 26 | If you need a quick fix or any guarantee, you should consider to buy a GLPI Network Subscription. 27 | 28 | More information here: https://glpi-project.org/subscriptions/ 29 | - type: checkboxes 30 | id: terms 31 | attributes: 32 | label: Code of Conduct 33 | description: By submitting this issue, you agree to follow hereinabove rules and [Contribution guide](https://github.com/glpi-project/glpi/blob/main/CONTRIBUTING.md) 34 | options: 35 | - label: I agree to follow this project's Code of Conduct 36 | validations: 37 | required: true 38 | - type: checkboxes 39 | attributes: 40 | label: Is there an existing issue for this? 41 | description: Please search to see if an issue already exists for the bug you encountered. 42 | options: 43 | - label: I have searched the existing issues 44 | validations: 45 | required: true 46 | - type: input 47 | id: glpi-version 48 | attributes: 49 | label: GLPI Version 50 | description: What version of our GLPI are you running? 51 | validations: 52 | required: true 53 | - type: input 54 | id: plugin-version 55 | attributes: 56 | label: Plugin version 57 | description: What version of `fields` are you running? 58 | validations: 59 | required: true 60 | - type: textarea 61 | attributes: 62 | label: Bug description 63 | description: A concise description of the problem you are experiencing and what you expected to happen. 64 | validations: 65 | required: false 66 | - type: textarea 67 | id: logs 68 | attributes: 69 | label: Relevant log output 70 | description: | 71 | Please copy and paste any relevant log output. Find them in `*-error.log` files under `glpi/files/_log/`. 72 | 73 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 74 | render: shell 75 | - type: input 76 | id: url 77 | attributes: 78 | label: Page URL 79 | description: If applicable, page URL where the bug happens. 80 | validations: 81 | required: false 82 | - type: textarea 83 | attributes: 84 | label: Steps To reproduce 85 | description: Steps to reproduce the behavior. 86 | placeholder: | 87 | 1. With this config... 88 | 2. Go to... 89 | 3. Scroll down to... 90 | 4. See error... 91 | validations: 92 | required: false 93 | - type: textarea 94 | attributes: 95 | label: Your GLPI setup information 96 | description: Please copy and paste information you will find in GLPI in `Setup > General` menu, `System` tab. 97 | validations: 98 | required: false 99 | - type: textarea 100 | attributes: 101 | label: Anything else? 102 | description: Add any other context about the problem here. 103 | validations: 104 | required: false 105 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Ensure GitHub Actions are used in their latest version 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "monthly" 8 | 9 | # Strategy for composer dependencies 10 | - package-ecosystem: "composer" 11 | directory: "/" 12 | schedule: 13 | interval: "monthly" 14 | allow: 15 | - dependency-type: "direct" 16 | open-pull-requests-limit: 100 17 | versioning-strategy: "increase" 18 | groups: 19 | dev-dependencies: 20 | dependency-type: "development" 21 | -------------------------------------------------------------------------------- /.github/label-commenter-config.yml: -------------------------------------------------------------------------------- 1 | labels: 2 | - name: "invalid" 3 | labeled: 4 | issue: 5 | body: | 6 | This issue has been closed because you did not provide the requested information. 7 | action: "close" 8 | - name: "support" 9 | labeled: 10 | issue: 11 | body: | 12 | This issue has been closed as we only track bugs here. 13 | 14 | You can get community support on [forums](https://forum.glpi-project.org/) or you can consider [taking a subscription](https://glpi-project.org/subscriptions/) to get professional support. 15 | You can also [contact GLPI editor team](https://portal.glpi-network.com/contact-us) directly. 16 | action: close 17 | - name: "feature suggestion" 18 | labeled: 19 | issue: 20 | body: | 21 | This issue has been closed as we only track bugs here. 22 | 23 | You can open a topic to discuss with community about this enhancement on [suggestion website](https://glpi.userecho.com/). 24 | You can also [contact GLPI editor team](https://portal.glpi-network.com/contact-us) directly if you are willing to sponsor this feature. 25 | action: close 26 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Checklist before requesting a review 2 | 3 | *Please delete options that are not relevant.* 4 | 5 | - [ ] I have performed a self-review of my code. 6 | - [ ] I have added tests (when available) that prove my fix is effective or that my feature works. 7 | - [ ] I have updated the CHANGELOG with a short functional description of the fix or new feature. 8 | - [ ] This change requires a documentation update. 9 | 10 | ## Description 11 | 12 | - It fixes # (issue number, if applicable) 13 | - Here is a brief description of what this PR does 14 | 15 | ## Screenshots (if appropriate): 16 | -------------------------------------------------------------------------------- /.github/workflows/auto-tag-new-version.yml: -------------------------------------------------------------------------------- 1 | name: "Automatically tag new version" 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | paths: 8 | - "setup.php" 9 | 10 | jobs: 11 | auto-tag-new-version: 12 | name: "Automatically tag new version" 13 | uses: "glpi-project/plugin-release-workflows/.github/workflows/auto-tag-new-version.yml@v1" 14 | secrets: 15 | github-token: "${{ secrets.AUTOTAG_TOKEN }}" 16 | -------------------------------------------------------------------------------- /.github/workflows/close_stale_issue.yml: -------------------------------------------------------------------------------- 1 | name: 'Close stale issues' 2 | on: 3 | schedule: 4 | - cron: '0 8 * * *' 5 | 6 | jobs: 7 | stale: 8 | if: github.repository == 'pluginsGLPI/fields' 9 | permissions: 10 | issues: write # for actions/stale to close stale issues 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/stale@v9 14 | with: 15 | stale-issue-message: >- 16 | There has been no activity on this issue for some time and therefore it is considered stale 17 | and will be closed automatically in 10 days. 18 | 19 | 20 | If this issue is related to a bug, please try to reproduce on latest release. If the problem persist, 21 | feel free to add a comment to revive this issue. 22 | 23 | If it is related to a new feature, please open a topic to discuss with community about this enhancement 24 | on [suggestion website](https://glpi.userecho.com/). 25 | 26 | 27 | You may also consider taking a [subscription](https://glpi-project.org/subscriptions/) to get professionnal 28 | support or [contact GLPI editor team](https://portal.glpi-network.com/contact-us) directly. 29 | days-before-issue-stale: 15 30 | days-before-pr-stale: -1 # PR will be marked as stale manually. 31 | days-before-close: 5 32 | exempt-issue-labels: "bug,enhancement,question,security" # Issues with "bug", "enhancement", "question" or "security" labels will not be marked as stale 33 | exempt-all-milestones: true # Do not check issues/PR with defined milestone. 34 | ascending: true # First check older issues/PR. 35 | operations-per-run: 750 # Max API calls per run. 36 | -------------------------------------------------------------------------------- /.github/workflows/continuous-integration.yml: -------------------------------------------------------------------------------- 1 | name: "Continuous integration" 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | tags: 8 | - "*" 9 | pull_request: 10 | schedule: 11 | - cron: "0 0 * * *" 12 | workflow_dispatch: 13 | 14 | concurrency: 15 | group: "${{ github.workflow }}-${{ github.ref }}" 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | generate-ci-matrix: 20 | name: "Generate CI matrix" 21 | uses: "glpi-project/plugin-ci-workflows/.github/workflows/generate-ci-matrix.yml@v1" 22 | with: 23 | glpi-version: "10.0.x" 24 | ci: 25 | name: "GLPI ${{ matrix.glpi-version }} - php:${{ matrix.php-version }} - ${{ matrix.db-image }}" 26 | needs: "generate-ci-matrix" 27 | strategy: 28 | fail-fast: false 29 | matrix: ${{ fromJson(needs.generate-ci-matrix.outputs.matrix) }} 30 | uses: "glpi-project/plugin-ci-workflows/.github/workflows/continuous-integration.yml@v1" 31 | with: 32 | plugin-key: "fields" 33 | glpi-version: "${{ matrix.glpi-version }}" 34 | php-version: "${{ matrix.php-version }}" 35 | db-image: "${{ matrix.db-image }}" 36 | -------------------------------------------------------------------------------- /.github/workflows/label-commenter.yml: -------------------------------------------------------------------------------- 1 | name: "Label commenter" 2 | 3 | on: 4 | issues: 5 | types: 6 | - "labeled" 7 | - "unlabeled" 8 | 9 | jobs: 10 | comment: 11 | permissions: 12 | contents: "read" 13 | issues: "write" 14 | runs-on: "ubuntu-latest" 15 | steps: 16 | - name: "Checkout" 17 | uses: "actions/checkout@v4" 18 | 19 | - name: "Label commenter" 20 | uses: "peaceiris/actions-label-commenter@v1" 21 | -------------------------------------------------------------------------------- /.github/workflows/locales-sync.yml: -------------------------------------------------------------------------------- 1 | name: "Synchronize locales" 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * 1-5" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | sync-with-transifex: 10 | name: "Sync with transifex" 11 | uses: "glpi-project/plugin-translation-workflows/.github/workflows/transifex-sync.yml@v1" 12 | secrets: 13 | github-token: "${{ secrets.LOCALES_SYNC_TOKEN }}" 14 | transifex-token: "${{ secrets.TRANSIFEX_TOKEN }}" 15 | -------------------------------------------------------------------------------- /.github/workflows/locales-update-source.yml: -------------------------------------------------------------------------------- 1 | name: "Update locales sources" 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | 8 | jobs: 9 | push-on-transifex: 10 | name: "Push locales sources" 11 | uses: "glpi-project/plugin-translation-workflows/.github/workflows/transifex-push-sources.yml@v1" 12 | secrets: 13 | transifex-token: "${{ secrets.TRANSIFEX_TOKEN }}" 14 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: "Publish release" 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | publish-release: 10 | permissions: 11 | contents: "write" 12 | name: "Publish release" 13 | uses: "glpi-project/plugin-release-workflows/.github/workflows/publish-release.yml@v1" 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | vendor/ 3 | .gh_token 4 | *.min.* 5 | -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | in(__DIR__) 8 | ->name('*.php'); 9 | 10 | $config = new Config(); 11 | 12 | $rules = [ 13 | '@PER-CS2.0' => true, 14 | 'trailing_comma_in_multiline' => ['elements' => ['arguments', 'array_destructuring', 'arrays']], // For PHP 7.4 compatibility 15 | ]; 16 | 17 | return $config 18 | ->setRules($rules) 19 | ->setFinder($finder) 20 | ->setUsingCache(false); 21 | -------------------------------------------------------------------------------- /.phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | . 4 | /.git/ 5 | ^vendor/ 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.twig_cs.dist.php: -------------------------------------------------------------------------------- 1 | in(__DIR__ . '/templates') 9 | ->name('*.html.twig') 10 | ->ignoreVCSIgnored(true); 11 | 12 | return Twigcs\Config\Config::create() 13 | ->setFinder($finder) 14 | ->setRuleSet(\Glpi\Tools\GlpiTwigRuleset::class) 15 | ; 16 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [o:teclib:p:glpi-plugin-plugin-fields:r:fields-pot] 5 | file_filter = locales/.po 6 | source_file = locales/fields.pot 7 | source_lang = en 8 | type = PO 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/). 7 | 8 | ## [UNRELEASE] 9 | 10 | ## [1.21.22] - 2025-05-28 11 | 12 | ### Fixed 13 | - Fix condition check logic for dropdown field values 14 | - Fix validation for mandatory multiple dropdown 15 | 16 | ## [1.21.21] - 2025-03-21 17 | 18 | ### Fixed 19 | 20 | - Fix of GLPI native fields update for objects with `fields` containers. 21 | 22 | ## [1.21.20] - 2025-03-20 23 | 24 | ### Fixed 25 | 26 | - Fix `numeric` field search 27 | - Fix containers migration while adding `is_recursive` field 28 | - Fix container update from other context (like plugins) 29 | - Fix "not equals" search operator for dropdown `multiple` 30 | - Fix container data (`entities_id`) insert from `dom` type 31 | 32 | ## [1.21.19] - 2025-02-03 33 | 34 | ### Fixed 35 | 36 | - Fix container update from `API` 37 | - Fix: fix default value for `dropdown` field to avoid empty dropdown 38 | 39 | ## [1.21.18] - 2024-01-16 40 | 41 | ### Fixed 42 | 43 | - Fix `PluginFieldsContainerDisplayCondition` display when value is no more available. 44 | - Fix issue where the value of custom fields could not be saved 45 | 46 | ## [1.21.17] - 2024-12-26 47 | 48 | ### Fixed 49 | 50 | - Force decimal `datatype` of `numeric` fields for more accurate display. 51 | - Do not destroy the dropdown table/class if it is being used by another container. 52 | 53 | ## [1.21.16] - 2024-12-11 54 | 55 | ### Fixed 56 | 57 | - Fix `container` to prevent calls from `API` returning full container data 58 | 59 | ## [1.21.15] - 2024-10-09 60 | 61 | ### Fixed 62 | 63 | - Removes multiple document selection in a single field, as the core does not support it. 64 | 65 | ## [1.21.14] - 2024-10-02 66 | 67 | ### Fixed 68 | 69 | - Fix call to get_parent_class() for PHP 8.3 (#839) 70 | - Fix datatype for search (#836) 71 | 72 | ## [1.21.13] - 2024-09-12 73 | 74 | ### CVE-2024-45600 75 | 76 | - Fix SQL injection 77 | 78 | ### Added 79 | 80 | - Add ```ComputerVirtualMachine``` 81 | 82 | ## [1.21.12] - 2024-09-06 83 | 84 | ### Fixed 85 | 86 | - Fix handling of empty mandatory fields in generic objects. 87 | - Fix massive update for dropdown (shared by several containers) 88 | 89 | ## [1.21.11] - 2024-07-10 90 | 91 | ### Fixed 92 | 93 | - Fix ```strpslashes``` log error 94 | - Update main item ```date_mod``` after updating additional fields 95 | - Fix ```datainjection``` mapping error with additional fields 96 | 97 | ## [1.21.10] - 2024-06-11 98 | 99 | ### Fixed 100 | 101 | - Prevent compatibility issues when importing with the Datainjection plugin (#798) 102 | 103 | ## [1.21.9] - 2024-06-11 104 | 105 | ### Fixed 106 | 107 | - Fix dropdown recursion (#775) 108 | - Fix list of allowed Search Option (#778) 109 | - Fix(core): load plugin from CLI context 110 | - Fix: multiple dropdown fields emptied when solution added (#795) 111 | 112 | 113 | ## [1.21.8] - 2024-02-22 114 | 115 | ### Fixed 116 | 117 | - Fix crash about undefined array key 118 | 119 | 120 | ## [1.21.7] - 2024-02-22 121 | 122 | ### Added 123 | 124 | - Display generic label for field if not available 125 | 126 | ### Fixed 127 | 128 | - Fix search on dropdown ```multiple``` 129 | - Load all users from User dropdown 130 | - Handle / save empty choice for dropdown 131 | - Load overrides from related item if container is ```tab``` type 132 | - Deactivate ```domtab``` that no longer works and handle ```ITILSolution``` (see https://github.com/pluginsGLPI/fields/pull/741) 133 | 134 | 135 | ## [1.6.1] - 2017-03-09 136 | 137 | - Drop namespaces added in 1.6.0; GLPI is not ready 138 | - Revert back to zend-loader 139 | 140 | ## [1.6.0] - 2017-03-03 141 | 142 | - Use Fedora/Autoloader, add namespaces 143 | - Normalize backslashes 144 | - Fix permissions issues (cannot create containers or fields) 145 | 146 | ## [1.5.0] - 2017-01-27 147 | 148 | **Compatible with GLPI 9.1.2 and above** 149 | 150 | - Use post_item_form hook instead of javascript to display fields 151 | - Fix (and limit) dom tab possibilities 152 | 153 | ## [1.4.5] - 2017-01-13 154 | - Set minimal PHP version to 5.4 155 | - Prevent values to be kept from a new ticket to another 156 | - Do not check files if plugin is not initialized 157 | - Limit to one domtab per tab 158 | 159 | ## [1.4.4] - 2017-01-11 160 | - Fix issue on updating items on some cases 161 | - Fix issue on creating item on some cases 162 | - Fix cross plugin issue 163 | 164 | ## [1.4.3] - 2016-12-30 165 | 166 | ### Changed 167 | - Fix plugin blocks item update 168 | - Display translated headers 169 | - Do notable used minified files when debug mode is active 170 | 171 | ## [1.4.2] - 2016-12-21 172 | 173 | ### Changed 174 | - Fix field update 175 | - Fix path issue on windows 176 | - Fix profile restriction issues 177 | - Fix display on classic and vsplitted views 178 | 179 | ## [1.4.1] - 2016-12-15 180 | 181 | ### Added 182 | - Prepare translation on dropdown fields (inactive because of GLPI's issue #953) 183 | 184 | ### Changed 185 | - Translate labels in search options 186 | - Fix adding bloc for specific tab 187 | - Fix dropdown pagination links 188 | - Fix validation issue creating new tickets 189 | - Fix checks consistency 190 | - Ensure we target only the first tab 191 | 192 | ## [1.4.0] - 2016-12-13 193 | 194 | ### Added 195 | - New URL field type. 196 | - Labels translation for containers and fields. 197 | 198 | ### Changed 199 | - Improve uninstallation when generated classes are missing. 200 | - Update translations from [Transifex](https://www.transifex.com/teclib/glpi-plugin-plugin-fields) 201 | - Fix self-service missing field on tickets 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fields GLPI plugin 2 | 3 | [![License](https://img.shields.io/github/license/pluginsGLPI/fields.svg?&label=License)](https://github.com/pluginsGLPI/fields/blob/develop/LICENSE) 4 | [![Follow twitter](https://img.shields.io/twitter/follow/Teclib.svg?style=social&label=Twitter&style=flat-square)](https://twitter.com/teclib) 5 | [![Telegram Group](https://img.shields.io/badge/Telegram-Group-blue.svg)](https://t.me/glpien) 6 | [![Project Status: Active](http://www.repostatus.org/badges/latest/active.svg)](http://www.repostatus.org/#active) 7 | [![GitHub release](https://img.shields.io/github/release/pluginsGLPI/fields.svg)](https://github.com/pluginsGLPI/fields/releases) 8 | [![GitHub build](https://travis-ci.org/pluginsGLPI/fields.svg?)](https://travis-ci.org/pluginsGLPI/fields/) 9 | 10 | ![Screenshot](./docs/screenshots/fields.gif) 11 | 12 | The fields plugin allows you to add custom fields on GLPI items forms. 13 | 14 | Additionnal data can be added: 15 | * In object tab 16 | * In main form of object, above save button 17 | * In form of a tab, above save button 18 | 19 | Supported GLPI items are listed on below, see [Supported GLPI items](#Supported-GLPI-items) 20 | 21 | Possible fields type are: 22 | * Header (title bloc) 23 | * Text (single line) 24 | * Text (multiple lines) 25 | * Number 26 | * URL 27 | * Custom dropdown (always a tree dropdown) 28 | * Yes / No 29 | * Date 30 | * Date / Hour 31 | * GLPI item dropdown based on a single item type, see [Supported GLPI items](#Supported-GLPI-items) 32 | * GLPI item dropdown based on a multiple item types, see [Supported GLPI items](#Supported-GLPI-items) 33 | 34 | ## Supported GLPI items 35 | 36 | Following list contains GLPI item types that are handled by this plugin. 37 | These item types will be available to attach field containers to, and will be usable in GLPI item dropdowns fields. 38 | 39 |
40 | Click to expand list 41 | 42 | * Assets 43 | * Computers 44 | * Monitors 45 | * Software 46 | * Network devices 47 | * Devices 48 | * Printers 49 | * Cartridge models 50 | * Consumable models 51 | * Phones 52 | * Racks 53 | * Enclosures 54 | * PDUs 55 | * Passive devices 56 | * Cables 57 | * Assistance 58 | * Tickets 59 | * Problems 60 | * Changes 61 | * Recurrent tickets 62 | * Recurrent changes 63 | * External events 64 | * Management 65 | * Licenses 66 | * Versions 67 | * Budgets 68 | * Suppliers 69 | * Contacts 70 | * Contract 71 | * Documents 72 | * Lines 73 | * Certificates 74 | * Data centers 75 | * Clusters 76 | * Domains 77 | * Appliances 78 | * Databases 79 | * Database instances 80 | * Tools 81 | * Projects 82 | * Project tasks 83 | * Reminders 84 | * RSS feed 85 | * Administration 86 | * Users 87 | * Groups 88 | * Entities 89 | * Profiles 90 | * Components 91 | * Batteries 92 | * Cameras 93 | * Cases 94 | * Controllers 95 | * Drives 96 | * Firmware 97 | * Generic devices 98 | * Graphics cards 99 | * Hard drives 100 | * Memories 101 | * System boards 102 | * Network cards 103 | * PCI devices 104 | * Power supplies 105 | * Processors 106 | * Sensors 107 | * Simcards 108 | * Soundcards 109 | * Dropdowns: Common 110 | * Locations 111 | * Statuses of items 112 | * Manufacturers 113 | * Blacklists 114 | * Blacklisted mail content 115 | * Dropdowns: Assistance 116 | * ITIL categories 117 | * Task categories 118 | * Task templates 119 | * Solution types 120 | * Solution templates 121 | * Request sources 122 | * Followup templates 123 | * Project states 124 | * Project types 125 | * Project tasks types 126 | * Project task templates 127 | * External events templates 128 | * Event categories 129 | * Pending reasons 130 | * Dropdowns: Types 131 | * Computer types 132 | * Networking equipment types 133 | * Printer types 134 | * Monitor types 135 | * Devices types 136 | * Phone types 137 | * License types 138 | * Cartridge types 139 | * Consumable types 140 | * Contract types 141 | * Contact types 142 | * Generic types 143 | * Sensor types 144 | * Memory types 145 | * Third party types 146 | * Interface types (Hard drive...) 147 | * Case types 148 | * Phone power supply types 149 | * File systems 150 | * Certificate types 151 | * Budget types 152 | * Simcard types 153 | * Line types 154 | * Rack types 155 | * PDU types 156 | * Passive device types 157 | * Cluster types 158 | * Database instance types 159 | * Dropdowns: Models 160 | * Computer models 161 | * Networking equipment models 162 | * Printer models 163 | * Monitor models 164 | * Peripheral models 165 | * Phone models 166 | * Device camera models 167 | * Device case models 168 | * Device control models 169 | * Device drive models 170 | * Device generic models 171 | * Device graphic card models 172 | * Device hard drive models 173 | * Device memory models 174 | * System board models 175 | * Network card models 176 | * Other component models 177 | * Device power supply models 178 | * Device processor models 179 | * Device sound card models 180 | * Device sensor models 181 | * Rack models 182 | * Enclosure models 183 | * PDU models 184 | * Passive device models 185 | * Dropdowns: Virtual machines 186 | * Virtualization systems 187 | * Virtualization models 188 | * States of the virtual machine 189 | * Dropdowns: Management 190 | * Document headings 191 | * Document types 192 | * Business criticities 193 | * Dropdowns: Tools 194 | * Knowledge base categories 195 | * Dropdowns: Calendar 196 | * Calendars 197 | * Close times 198 | * Dropdowns: Operating systems 199 | * Operating systems 200 | * Versions of the operating systems 201 | * Service packs 202 | * Operating system architectures 203 | * Editions 204 | * Kernels 205 | * Kernel versions 206 | * Update Sources 207 | * Dropdowns: Networking 208 | * Network interfaces 209 | * Networks 210 | * Network port types 211 | * VLANs 212 | * Line operators 213 | * Domain types 214 | * Domains relations 215 | * Records types 216 | * Fiber types 217 | * Dropdowns: Cable management 218 | * Cable types 219 | * Cable strands 220 | * Socket models 221 | * Dropdowns: Internet 222 | * IP networks 223 | * Internet domains 224 | * Wifi networks 225 | * Network names 226 | * Dropdowns: Software 227 | * Software categories 228 | * Dropdowns: User 229 | * Users titles 230 | * User categories 231 | * Dropdowns: Authorizations assignment rules 232 | * LDAP criteria 233 | * Dropdowns: Fields unicity 234 | * Ignored values for the unicity 235 | * Dropdowns: External authentications 236 | * Fields storage of the login in the HTTP request 237 | * Dropdowns: Power management 238 | * Plugs 239 | * Dropdowns: Appliances 240 | * Appliance types 241 | * Appliance environments 242 | * Dropdowns: Camera 243 | * Image formats 244 | * Dropdowns: Others 245 | * USB vendors 246 | * PCI vendors 247 | * Other 248 | * Network ports 249 | * Notifications 250 | * Notification templates 251 | 252 |
253 | 254 | ## New features 255 | 256 | The block can be hidden according to conditions. These are defined by rules evaluating main item properties. 257 | 258 | ![Screenshot](./docs/screenshots/hide_block.png) 259 | 260 | Fields options (mandatory / read only) can be overridden for some item statuses. 261 | 262 | ![Screenshot](./docs/screenshots/override_by_status.png) 263 | 264 | ## Download 265 | 266 | Releases can be donwloaded on [GitHub](https://github.com/PluginsGLPI/fields/releases). 267 | 268 | ## Documentation 269 | 270 | We maintain a detailed [documentation](http://glpi-plugins.rtfd.io/en/latest/fields/index.html). 271 | 272 | ## Contact 273 | 274 | For notices about major changes and general discussion of fields, subscribe to the [/r/glpi](https://www.reddit.com/r/glpi/) subreddit. 275 | You can also chat with us via [@glpi on Telegram](https://t.me/glpien). 276 | 277 | ## Professional Services 278 | 279 | ![GLPI Network](./docs/glpi_network.png "GLPI network") 280 | 281 | The GLPI Network services are available through our [Partner's Network](http://www.teclib-edition.com/en/partners/). 282 | We provide special training, bug fixes with editor subscription, contributions for new features, and more. 283 | 284 | Obtain a personalized service experience, associated with benefits and opportunities. 285 | 286 | ## Contributing 287 | 288 | * Open a ticket for each bug/feature so it can be discussed 289 | * Follow [development guidelines](http://glpi-developer-documentation.readthedocs.io/en/latest/plugins/index.html) 290 | * Refer to [GitFlow](http://git-flow.readthedocs.io/) process for branching 291 | * Work on a new branch on your own fork 292 | * Open a PR that will be reviewed by a developer 293 | 294 | ## Copying 295 | 296 | * **Code**: you can redistribute it and/or modify it under the terms of the GNU General Public License ([GPL-2.0](https://www.gnu.org/licenses/gpl-2.0.en.html)). 297 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | **⚠️ Please never use standard issues to report security problems; vulnerabilities are published once a fix release is available. ⚠️** 4 | 5 | ## Reporting a Vulnerability 6 | 7 | If you found a security issue, please contact us by: 8 | 9 | - [our huntr page](https://huntr.dev/repos/pluginsGLPI/fields/) 10 | - a mail to \[glpi-security AT ow2.org\] 11 | 12 | You should provide us all details about the issue and the way to reproduce it. 13 | You may also provide a script that can be used to check the issue exists. 14 | 15 | Once the report will be handled, and if the issue is not yet fixed (or in progress) 16 | we'll add it to the GitHub security tab, and add you as observer. Meanwhile, 17 | you will reserve a CVE for the issue. 18 | 19 | Thank you for improving the security of GLPI and its plugins. 20 | 21 | ## Supported Versions 22 | 23 | We follow the same version support policy as GLPI. 24 | This means that we provide security patches to versions of the plugin that target a version of GLPI itself maintained from a security point of view. 25 | -------------------------------------------------------------------------------- /ajax/container.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | use Glpi\Http\Response; 35 | 36 | if (isset($_GET['action']) && $_GET['action'] === 'get_fields_html') { 37 | 38 | $right = PluginFieldsProfile::getRightOnContainer($_SESSION['glpiactiveprofile']['id'], $_GET['id']); 39 | if ($right < READ) { 40 | Response::sendError(403, 'Forbidden'); 41 | return; 42 | } 43 | 44 | $containers_id = $_GET['id']; 45 | $itemtype = $_GET['itemtype']; 46 | $items_id = (int) $_GET['items_id']; 47 | $type = $_GET['type']; 48 | $subtype = $_GET['subtype']; 49 | $input = $_GET['input']; 50 | 51 | $item = new $itemtype(); 52 | if ($items_id > 0 && !$item->getFromDB($items_id)) { 53 | Response::sendError(404, 'Not Found'); 54 | } 55 | $item->input = $input; 56 | 57 | $display_condition = new PluginFieldsContainerDisplayCondition(); 58 | if ($display_condition->computeDisplayContainer($item, $containers_id)) { 59 | PluginFieldsField::showDomContainer( 60 | $containers_id, 61 | $item, 62 | $type, 63 | $subtype, 64 | ); 65 | } else { 66 | echo ''; 67 | } 68 | } else { 69 | Response::sendError(404, 'Not Found'); 70 | } 71 | -------------------------------------------------------------------------------- /ajax/container_display_condition.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | if (isset($_GET['action'])) { 35 | if ($_GET['action'] === 'get_add_form') { 36 | $status_override = new PluginFieldsContainerDisplayCondition(); 37 | $status_override->showForm(0, $_GET); 38 | } elseif ($_GET['action'] === 'get_edit_form') { 39 | $status_override = new PluginFieldsContainerDisplayCondition(); 40 | $status_override->getFromDB($_GET['id']); 41 | $status_override->showForm($_GET['id'], $_GET); 42 | } 43 | } elseif (isset($_POST['action'])) { 44 | if ($_POST['action'] === 'get_itemtype_so') { 45 | if (isset($_POST['itemtype']) && class_exists($_POST['itemtype'])) { 46 | echo PluginFieldsContainerDisplayCondition::showItemtypeFieldForm($_POST['itemtype']) ; 47 | } else { 48 | echo ''; 49 | } 50 | } elseif ($_POST['action'] === 'get_condition_switch_so') { 51 | if (isset($_POST['search_option_id']) && (isset($_POST['itemtype']) && class_exists($_POST['itemtype']))) { 52 | echo PluginFieldsContainerDisplayCondition::showSearchOptionCondition($_POST['search_option_id'], $_POST['itemtype']); 53 | } else { 54 | echo ''; 55 | } 56 | } 57 | } else { 58 | http_response_code(400); 59 | die(); 60 | } 61 | -------------------------------------------------------------------------------- /ajax/container_itemtypes_dropdown.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | PluginFieldsContainer::showFormItemtype($_REQUEST); 35 | -------------------------------------------------------------------------------- /ajax/container_subtype_dropdown.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | PluginFieldsContainer::showFormSubtype($_REQUEST, true); 35 | -------------------------------------------------------------------------------- /ajax/field_specific_fields.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @copyright 2015-2022 Teclib' and contributors. 27 | * @copyright 2003-2014 by the INDEPNET Development Team. 28 | * @licence https://www.gnu.org/licenses/gpl-3.0.html 29 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 30 | * @link https://github.com/pluginsGLPI/fields 31 | * ------------------------------------------------------------------------- 32 | */ 33 | 34 | include('../../../inc/includes.php'); 35 | header('Content-Type: text/html; charset=UTF-8'); 36 | Html::header_nocache(); 37 | Session::checkLoginUser(); 38 | 39 | $id = $_POST['id']; 40 | $type = $_POST['type']; 41 | $rand = $_POST['rand']; 42 | 43 | $field = new PluginFieldsField(); 44 | if ($id > 0) { 45 | $field->getFromDB($id); 46 | } else { 47 | $field->getEmpty(); 48 | } 49 | 50 | if ($type === 'glpi_item') { 51 | // Display "allowed values" field 52 | echo ''; 53 | echo __('Allowed values', 'fields') . ' :'; 54 | echo ''; 55 | 56 | echo ''; 57 | if ($field->isNewItem()) { 58 | Dropdown::showFromArray('allowed_values', PluginFieldsToolbox::getGlpiItemtypes(), [ 59 | 'display_emptychoice' => true, 60 | 'multiple' => true, 61 | ]); 62 | } else { 63 | $allowed_itemtypes = !empty($field->fields['allowed_values']) 64 | ? json_decode($field->fields['allowed_values']) 65 | : []; 66 | echo implode( 67 | ', ', 68 | array_map( 69 | function ($itemtype) { 70 | return is_a($itemtype, CommonDBTM::class, true) 71 | ? $itemtype::getTypeName(Session::getPluralNumber()) 72 | : $itemtype; 73 | }, 74 | $allowed_itemtypes, 75 | ), 76 | ); 77 | } 78 | echo ''; 79 | } else { 80 | $dropdown_matches = []; 81 | $is_dropdown = $type == 'dropdown' || preg_match('/^dropdown-(?.+)$/', $type, $dropdown_matches) === 1; 82 | $is_dropdown_multi = ($is_dropdown && ($type != 'dropdown-Document')); 83 | 84 | // Display "default value(s)" field 85 | echo ''; 86 | if ($is_dropdown_multi) { 87 | echo __('Multiple dropdown', 'fields') . ' :'; 88 | echo '
'; 89 | } 90 | echo __('Default value', 'fields') . ' :'; 91 | if (in_array($type, ['date', 'datetime'])) { 92 | echo ''; 93 | } 94 | echo ''; 95 | 96 | echo ''; 97 | if ($is_dropdown) { 98 | if ($is_dropdown_multi) { 99 | $multiple = (bool) ($_POST['multiple'] ?? $field->fields['multiple']); 100 | 101 | if ($field->isNewItem()) { 102 | Dropdown::showYesNo( 103 | 'multiple', 104 | $multiple, 105 | -1, 106 | [ 107 | 'rand' => $rand, 108 | ], 109 | ); 110 | } else { 111 | echo Dropdown::getYesNo($multiple); 112 | } 113 | echo '
'; 114 | } else { 115 | $multiple = false; 116 | } 117 | 118 | echo '
'; 119 | if ($field->isNewItem() && $type == 'dropdown') { 120 | echo ''; 121 | echo __s('Default value will be configurable once field will be created.', 'fields'); 122 | if (!$multiple) { 123 | echo ''; 124 | } 125 | echo ''; 126 | } else { 127 | $itemtype = $type == 'dropdown' 128 | ? PluginFieldsDropdown::getClassname($field->fields['name']) 129 | : $dropdown_matches['class']; 130 | if ($field->fields['default_value'] === null) { 131 | $field->fields['default_value'] = ''; 132 | } 133 | $default_value = $multiple ? json_decode($field->fields['default_value']) : $field->fields['default_value']; 134 | Dropdown::show( 135 | $itemtype, 136 | [ 137 | 'name' => 'default_value' . ($multiple ? '[]' : ''), 138 | 'value' => $default_value, 139 | 'entity_restrict' => -1, 140 | 'multiple' => $multiple, 141 | 'rand' => $rand, 142 | ], 143 | ); 144 | } 145 | echo '
'; 146 | Ajax::updateItemOnSelectEvent( 147 | "dropdown_multiple$rand", 148 | "plugin_fields_specific_fields_$rand", 149 | '../ajax/field_specific_fields.php', 150 | [ 151 | 'id' => $id, 152 | 'type' => $type, 153 | 'multiple' => '__VALUE__', 154 | 'rand' => $rand, 155 | ], 156 | ); 157 | } else { 158 | echo Html::input( 159 | 'default_value', 160 | [ 161 | 'value' => $field->fields['default_value'], 162 | ], 163 | ); 164 | } 165 | echo ''; 166 | } 167 | -------------------------------------------------------------------------------- /ajax/reorder.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | if ( 35 | !array_key_exists('container_id', $_POST) 36 | || !array_key_exists('old_order', $_POST) 37 | || !array_key_exists('new_order', $_POST) 38 | ) { 39 | // Missing input 40 | exit(); 41 | } 42 | 43 | $table = PluginFieldsField::getTable(); 44 | $container_id = (int) $_POST['container_id']; 45 | $old_order = (int) $_POST['old_order']; 46 | $new_order = (int) $_POST['new_order']; 47 | 48 | /** @var DBmysql $DB */ 49 | global $DB; 50 | 51 | // Retrieve id of field to update 52 | $field_iterator = $DB->request( 53 | [ 54 | 'SELECT' => 'id', 55 | 'FROM' => $table, 56 | 'WHERE' => [ 57 | 'plugin_fields_containers_id' => $container_id, 58 | 'ranking' => $old_order, 59 | ], 60 | ], 61 | ); 62 | 63 | if (0 === $field_iterator->count()) { 64 | // Unknown field 65 | exit(); 66 | } 67 | 68 | $field_id = $field_iterator->current()['id']; 69 | 70 | // Move all elements to their new ranking 71 | if ($old_order < $new_order) { 72 | $DB->update( 73 | $table, 74 | [ 75 | 'ranking' => new \QueryExpression($DB->quoteName('ranking') . ' - 1'), 76 | ], 77 | [ 78 | 'plugin_fields_containers_id' => $container_id, 79 | ['ranking' => ['>', $old_order]], 80 | ['ranking' => ['<=', $new_order]], 81 | ], 82 | ); 83 | } else { 84 | $DB->update( 85 | $table, 86 | [ 87 | 'ranking' => new \QueryExpression($DB->quoteName('ranking') . ' + 1'), 88 | ], 89 | [ 90 | 'plugin_fields_containers_id' => $container_id, 91 | ['ranking' => ['<', $old_order]], 92 | ['ranking' => ['>=', $new_order]], 93 | ], 94 | ); 95 | } 96 | 97 | // Update current element 98 | $DB->update( 99 | $table, 100 | [ 101 | 'ranking' => $new_order, 102 | ], 103 | [ 104 | 'id' => $field_id, 105 | ], 106 | ); 107 | -------------------------------------------------------------------------------- /ajax/status_override.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | if (isset($_GET['action'])) { 35 | if ($_GET['action'] === 'get_status_dropdown') { 36 | echo PluginFieldsStatusOverride::getStatusDropdownForItemtype($_GET['itemtype']); 37 | } elseif ($_GET['action'] === 'get_add_form') { 38 | $status_override = new PluginFieldsStatusOverride(); 39 | $status_override->showForm(0, $_GET); 40 | } elseif ($_GET['action'] === 'get_edit_form') { 41 | $status_override = new PluginFieldsStatusOverride(); 42 | $status_override->getFromDB($_GET['id']); 43 | $status_override->showForm($_GET['id'], $_GET); 44 | } 45 | } else { 46 | http_response_code(400); 47 | die(); 48 | } 49 | -------------------------------------------------------------------------------- /ajax/viewtranslations.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | /** @file 32 | * @brief 33 | */ 34 | 35 | include('../../../inc/includes.php'); 36 | header('Content-Type: text/html; charset=UTF-8'); 37 | Html::header_nocache(); 38 | 39 | Session::checkLoginUser(); 40 | 41 | if (!isset($_POST['itemtype']) || !isset($_POST['items_id']) || !isset($_POST['id'])) { 42 | exit(); 43 | } 44 | 45 | $translation = new PluginFieldsLabelTranslation(); 46 | if ($_POST['id'] == -1) { 47 | $canedit = $translation->can(-1, CREATE, $_POST); 48 | } else { 49 | $canedit = $translation->can($_POST['id'], UPDATE); 50 | } 51 | if ($canedit) { 52 | $translation->showFormForItem($_POST['itemtype'], $_POST['items_id'], $_POST['id']); 53 | } else { 54 | echo __('Access denied'); 55 | } 56 | 57 | Html::ajaxFooter(); 58 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "php": ">=7.4", 4 | "symfony/yaml": "^5.4" 5 | }, 6 | "require-dev": { 7 | "friendsofphp/php-cs-fixer": "^3.75", 8 | "friendsoftwig/twigcs": "^6.1", 9 | "glpi-project/tools": "^0.7.5", 10 | "php-parallel-lint/php-parallel-lint": "^1.4", 11 | "phpstan/extension-installer": "^1.4", 12 | "phpstan/phpstan": "^2.1", 13 | "phpstan/phpstan-deprecation-rules": "^2.0" 14 | }, 15 | "config": { 16 | "optimize-autoloader": true, 17 | "platform": { 18 | "php": "7.4.0" 19 | }, 20 | "sort-packages": true, 21 | "allow-plugins": { 22 | "phpstan/extension-installer": true 23 | } 24 | }, 25 | "autoload-dev": { 26 | "psr-4": { 27 | "Glpi\\Tools\\": "../../tools/src/" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /css/fields.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * ------------------------------------------------------------------------- 3 | * Fields plugin for GLPI 4 | * ------------------------------------------------------------------------- 5 | * 6 | * LICENSE 7 | * 8 | * This file is part of Fields. 9 | * 10 | * Fields is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * Fields is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with Fields. If not, see . 22 | * ------------------------------------------------------------------------- 23 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | * @link https://github.com/pluginsGLPI/fields 26 | * ------------------------------------------------------------------------- 27 | */ 28 | 29 | //config 30 | ul.fields_config li { 31 | cursor:pointer; 32 | float:left; 33 | width:20%; 34 | -moz-border-radius: 5px; 35 | -webkit-border-radius:5px; 36 | border-radius: 5px; 37 | margin:0 1% 10px 1%; 38 | padding:5px 1px; 39 | } 40 | ul.fields_config li:hover { 41 | background-color:#E8E8E8; 42 | } 43 | ul.fields_config li p { 44 | padding-top: 8px; 45 | } 46 | ul.fields_config li img { 47 | float: left; 48 | margin-right: 2px; 49 | } 50 | div.fields_clear { 51 | clear: both; 52 | width:100%; 53 | } 54 | -------------------------------------------------------------------------------- /docs/glpi_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/docs/glpi_network.png -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/docs/logo.png -------------------------------------------------------------------------------- /docs/screenshots/fields.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/docs/screenshots/fields.gif -------------------------------------------------------------------------------- /docs/screenshots/hide_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/docs/screenshots/hide_block.png -------------------------------------------------------------------------------- /docs/screenshots/override_by_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/docs/screenshots/override_by_status.png -------------------------------------------------------------------------------- /front/commondropdown.form.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include '../../../inc/includes.php'; 32 | Session::checkLoginUser(); 33 | if (preg_match('/[a-z]/i', $_REQUEST['ddtype']) !== 1) { 34 | throw new \RuntimeException(sprintf('Invalid itemtype "%1$s"', $_REQUEST['ddtype'])); 35 | } 36 | $path = PLUGINFIELDS_FRONT_PATH . '/' . $_REQUEST['ddtype'] . '.form.php'; 37 | require_once $path; 38 | -------------------------------------------------------------------------------- /front/commondropdown.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include '../../../inc/includes.php'; 32 | Session::checkLoginUser(); 33 | if (preg_match('/[a-z]/i', $_REQUEST['ddtype']) !== 1) { 34 | throw new \RuntimeException(sprintf('Invalid itemtype "%1$s"', $_REQUEST['ddtype'])); 35 | } 36 | $path = PLUGINFIELDS_FRONT_PATH . '/' . $_REQUEST['ddtype'] . '.php'; 37 | require_once $path; 38 | -------------------------------------------------------------------------------- /front/container.form.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | if (empty($_GET['id'])) { 35 | $_GET['id'] = ''; 36 | } 37 | 38 | $container = new PluginFieldsContainer(); 39 | 40 | if (isset($_POST['add'])) { 41 | $container->check(-1, CREATE, $_POST); 42 | $newID = $container->add($_POST); 43 | Html::redirect(PLUGINFIELDS_WEB_DIR . "/front/container.form.php?id=$newID"); 44 | } elseif (isset($_POST['delete'])) { 45 | $container->check($_POST['id'], DELETE); 46 | $ok = $container->delete($_POST); 47 | Html::redirect(PLUGINFIELDS_WEB_DIR . '/front/container.php'); 48 | } elseif (isset($_REQUEST['purge'])) { 49 | $container->check($_REQUEST['id'], PURGE); 50 | $container->delete($_REQUEST, true); 51 | Html::redirect(PLUGINFIELDS_WEB_DIR . '/front/container.php'); 52 | } elseif (isset($_POST['update'])) { 53 | $container->check($_POST['id'], UPDATE); 54 | $container->update($_POST); 55 | Html::back(); 56 | } elseif (isset($_POST['update_fields_values'])) { 57 | $right = PluginFieldsProfile::getRightOnContainer($_SESSION['glpiactiveprofile']['id'], $_POST['plugin_fields_containers_id']); 58 | if ($right > READ) { 59 | $container->updateFieldsValues($_REQUEST, $_REQUEST['itemtype'], false); 60 | } 61 | Html::back(); 62 | } else { 63 | 64 | if ((int) $_GET['id'] > 0) { 65 | $right = PluginFieldsProfile::getRightOnContainer($_SESSION['glpiactiveprofile']['id'], $_GET['id']); 66 | if ($right < READ) { 67 | Html::displayRightError("User is missing the " . READ . " ('read') right for container"); 68 | } 69 | } 70 | 71 | Html::header( 72 | __('Additional fields', 'fields'), 73 | $_SERVER['PHP_SELF'], 74 | 'config', 75 | 'pluginfieldsmenu', 76 | 'fieldscontainer', 77 | ); 78 | $container->display(['id' => $_GET['id']]); 79 | Html::footer(); 80 | } 81 | -------------------------------------------------------------------------------- /front/container.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkLoginUser(); 33 | 34 | Html::header( 35 | __('Additional fields', 'fields'), 36 | $_SERVER['PHP_SELF'], 37 | 'config', 38 | 'pluginfieldsmenu', 39 | 'fieldscontainer', 40 | ); 41 | 42 | Session::checkRight('config', READ); 43 | 44 | PluginFieldsContainer::titleList(); 45 | Search::show('PluginFieldsContainer'); 46 | 47 | Html::footer(); 48 | -------------------------------------------------------------------------------- /front/containerdisplaycondition.form.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkRight('config', READ); 33 | 34 | $status_override = new PluginFieldsContainerDisplayCondition(); 35 | if (isset($_POST['add'])) { 36 | $status_override->check(-1, CREATE, $_POST); 37 | $status_override->add($_POST); 38 | Html::back(); 39 | } elseif (isset($_POST['update'])) { 40 | $status_override->check($_POST['id'], UPDATE); 41 | $status_override->update($_POST); 42 | Html::back(); 43 | } elseif (isset($_POST['delete'])) { 44 | $status_override->check($_POST['id'], PURGE); 45 | $status_override->delete([ 46 | 'id' => $_POST['id'], 47 | ]); 48 | Html::back(); 49 | } 50 | Html::back(); 51 | -------------------------------------------------------------------------------- /front/export_to_yaml.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | include('../hook.php'); 33 | 34 | Session::checkRight('config', READ); 35 | 36 | $ID = null; 37 | if (isset($_GET['id'])) { 38 | $ID = $_GET['id']; 39 | } 40 | 41 | if (plugin_fields_exportBlockAsYaml($ID)) { 42 | $filename = 'fields_conf.yaml'; 43 | $path = GLPI_TMP_DIR . '/fields_conf.yaml'; 44 | Toolbox::sendFile($path, $filename, 'text/yaml'); 45 | } else { 46 | Session::addMessageAfterRedirect('No data to export', false, INFO); 47 | Html::back(); 48 | } 49 | -------------------------------------------------------------------------------- /front/field.form.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | 33 | if (empty($_GET['id'])) { 34 | $_GET['id'] = ''; 35 | } 36 | 37 | Session::checkRight('config', READ); 38 | 39 | $field = new PluginFieldsField(); 40 | 41 | if (isset($_POST['add'])) { 42 | $field->check(-1, CREATE, $_POST); 43 | $field->add($_POST); 44 | Html::back(); 45 | } elseif (isset($_POST['delete'])) { 46 | $field->check($_POST['id'], DELETE); 47 | $field->delete($_POST); 48 | Html::back(); 49 | } elseif (isset($_REQUEST['purge'])) { 50 | $field->check($_REQUEST['id'], PURGE); 51 | $field->delete($_REQUEST, true); 52 | $field->redirectToList(); 53 | } elseif (isset($_POST['update'])) { 54 | $field->check($_POST['id'], UPDATE); 55 | $field->update($_POST); 56 | Html::back(); 57 | } else { 58 | $field->check($_GET['id'], READ); 59 | 60 | Html::header(PluginFieldsField::getTypeName(1), $_SERVER['PHP_SELF']); 61 | 62 | $field->getFromDB($_GET['id']); 63 | $field->display(['id' => $_GET['id'], 64 | 'parent_id' => $field->fields['plugin_fields_containers_id'], 65 | ]); 66 | 67 | Html::footer(); 68 | } 69 | -------------------------------------------------------------------------------- /front/labeltranslation.form.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkRight('config', UPDATE); 33 | 34 | $translation = new PluginFieldsLabelTranslation(); 35 | if (isset($_POST['add'])) { 36 | $translation->add($_POST); 37 | } elseif (isset($_POST['update'])) { 38 | $translation->update($_POST); 39 | } elseif (isset($_POST['purge'])) { 40 | $translation->delete($_POST, true); 41 | } 42 | Html::back(); 43 | -------------------------------------------------------------------------------- /front/profile.form.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkRight('config', UPDATE); 33 | 34 | if (isset($_POST['update'])) { 35 | PluginFieldsProfile::updateProfile($_POST); 36 | } 37 | Html::back(); 38 | -------------------------------------------------------------------------------- /front/regenerate_files.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | include('../hook.php'); 33 | 34 | Session::checkRight('config', READ); 35 | 36 | plugin_fields_checkFiles(); 37 | 38 | Html::back(); 39 | -------------------------------------------------------------------------------- /front/statusoverride.form.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | include('../../../inc/includes.php'); 32 | Session::checkRight('config', READ); 33 | 34 | $status_override = new PluginFieldsStatusOverride(); 35 | if (isset($_POST['add'])) { 36 | $status_override->check(-1, CREATE, $_POST); 37 | $status_override->add($_POST); 38 | Html::back(); 39 | } elseif (isset($_POST['update'])) { 40 | $status_override->check($_POST['id'], UPDATE); 41 | $status_override->update($_POST); 42 | Html::back(); 43 | } elseif (isset($_POST['delete'])) { 44 | $status_override->check($_POST['id'], PURGE); 45 | $status_override->delete([ 46 | 'id' => $_POST['id'], 47 | ]); 48 | Html::back(); 49 | } 50 | Html::back(); 51 | -------------------------------------------------------------------------------- /inc/abstractcontainerinstance.class.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | abstract class PluginFieldsAbstractContainerInstance extends CommonDBChild 32 | { 33 | public static $itemtype = 'itemtype'; 34 | public static $items_id = 'items_id'; 35 | 36 | public static $mustBeAttached = false; 37 | 38 | /** 39 | * This function relies on the static property `static::$plugins_forward_entity`, 40 | * which should be populated using the following method (from setup): 41 | * 42 | * Plugin::registerClass( 43 | * PluginFields, 44 | * ['forwardentityfrom' => ] 45 | * ); 46 | * 47 | * However, the order in which plugins are loaded can affect the behavior. 48 | * For example, if a container is defined on a `GenericObject` itemtype and 49 | * the `fields` plugin initializes before the `genericobject` plugin, the 50 | * `itemtype` for the container will not yet exist, leading to potential issues. 51 | * 52 | * Modification of this function to meet specific requirements. 53 | */ 54 | public function addNeededInfoToInput($input) 55 | { 56 | if ($this->tryEntityForwarding()) { 57 | $completeinput = array_merge($this->fields, $input); 58 | if ( 59 | $itemToGetEntity = static::getItemFromArray( 60 | static::$itemtype, 61 | static::$items_id, 62 | $completeinput, 63 | ) 64 | ) { 65 | if ( 66 | ($itemToGetEntity instanceof CommonDBTM) 67 | ) { 68 | if ($itemToGetEntity->isEntityAssign()) { 69 | $input['entities_id'] = $itemToGetEntity->getEntityID(); 70 | } 71 | 72 | if ($itemToGetEntity->maybeRecursive()) { 73 | $input['is_recursive'] = intval($itemToGetEntity->isRecursive()); 74 | } 75 | } 76 | } 77 | } 78 | return $input; 79 | } 80 | 81 | public static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) 82 | { 83 | if (!is_array($values)) { 84 | $values = [$field => $values]; 85 | } 86 | 87 | $field_id = $options['searchopt']['pfields_fields_id'] ?? null; 88 | 89 | $field_specs = new PluginFieldsField(); 90 | if ($field_id !== null && $field_specs->getFromDB($field_id)) { 91 | $dropdown_matches = []; 92 | if ( 93 | preg_match('/^dropdown-(?.+)$/i', $field_specs->fields['type'], $dropdown_matches) === 1 94 | && $field_specs->fields['multiple'] 95 | ) { 96 | $itemtype = $dropdown_matches['class']; 97 | if (!is_a($itemtype, CommonDBTM::class, true)) { 98 | return ''; // Itemtype not exists (maybe a deactivated plugin) 99 | } 100 | $display_with = []; 101 | if ($itemtype == User::class) { 102 | $display_with = ['realname', 'firstname']; 103 | } 104 | 105 | return Dropdown::show($itemtype, ['displaywith' => $display_with, 'name' => $name, 'display' => false]); 106 | } elseif ( 107 | $field_specs->fields['type'] === 'dropdown' 108 | && $field_specs->fields['multiple'] 109 | ) { 110 | $itemtype = PluginFieldsDropdown::getClassname($field_specs->fields['name']); 111 | 112 | return Dropdown::show($itemtype, ['name' => $name, 'display' => false]); 113 | } 114 | } 115 | 116 | return parent::getSpecificValueToSelect($field, $name, $values, $options); 117 | } 118 | 119 | public static function getSpecificValueToDisplay($field, $values, array $options = []) 120 | { 121 | if (!is_array($values)) { 122 | $values = [$field => $values]; 123 | } 124 | 125 | $field_id = $options['searchopt']['pfields_fields_id'] ?? null; 126 | 127 | $field_specs = new PluginFieldsField(); 128 | if ($field_id !== null && $field_specs->getFromDB($field_id)) { 129 | $dropdown_matches = []; 130 | if ( 131 | preg_match('/^dropdown-(?.+)$/i', $field_specs->fields['type'], $dropdown_matches) === 1 132 | && $field_specs->fields['multiple'] 133 | ) { 134 | $itemtype = $dropdown_matches['class']; 135 | if (!is_a($itemtype, CommonDBTM::class, true)) { 136 | return ''; // Itemtype not exists (maybe a deactivated plugin) 137 | } 138 | 139 | if (empty($values[$field])) { 140 | return ''; // Value not defined 141 | } 142 | $values = json_decode($values[$field]); 143 | if (!is_array($values)) { 144 | return ''; // Invalid value 145 | } 146 | 147 | $names = []; 148 | foreach ($values as $id) { 149 | $item = new $itemtype(); 150 | if ($item->getFromDB($id)) { 151 | $names[] = $item->getName(); 152 | } 153 | } 154 | 155 | return implode($options['separator'] ?? '
', $names); 156 | } elseif ( 157 | $field_specs->fields['type'] === 'dropdown' 158 | && $field_specs->fields['multiple'] 159 | ) { 160 | $itemtype = PluginFieldsDropdown::getClassname($field_specs->fields['name']); 161 | if (empty($values[$field])) { 162 | return ''; // Value not defined 163 | } 164 | $values = json_decode($values[$field]); 165 | if (!is_array($values)) { 166 | return ''; // Invalid value 167 | } 168 | 169 | return implode( 170 | $options['separator'] ?? '
', 171 | Dropdown::getDropdownArrayNames($itemtype::getTable(), $values), 172 | ); 173 | } 174 | } 175 | 176 | return parent::getSpecificValueToDisplay($field, $values, $options); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /inc/autoload.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | class PluginFieldsAutoloader 32 | { 33 | protected $paths = []; 34 | 35 | public function __construct($options = null) 36 | { 37 | if (null !== $options) { 38 | $this->setOptions($options); 39 | } 40 | } 41 | 42 | public function setOptions($options) 43 | { 44 | if (!is_array($options) && !($options instanceof \Traversable)) { 45 | throw new \InvalidArgumentException(); 46 | } 47 | 48 | foreach ($options as $path) { 49 | if (!in_array($path, $this->paths)) { 50 | $this->paths[] = $path; 51 | } 52 | } 53 | 54 | return $this; 55 | } 56 | 57 | public function processClassname($classname) 58 | { 59 | $matches = []; 60 | preg_match("/Plugin([A-Z][a-z0-9]+)([A-Z]\w+)/", $classname, $matches); 61 | 62 | if (count($matches) < 3) { 63 | return false; 64 | } else { 65 | return $matches; 66 | } 67 | } 68 | 69 | public function autoload($classname) 70 | { 71 | $matches = $this->processClassname($classname); 72 | 73 | if ($matches !== false) { 74 | $plugin_name = strtolower($matches[1]); 75 | $class_name = strtolower($matches[2]); 76 | 77 | if ($plugin_name !== 'fields') { 78 | return false; 79 | } 80 | 81 | $filename = implode('.', [ 82 | $class_name, 83 | 'class', 84 | 'php', 85 | ]); 86 | 87 | foreach ($this->paths as $path) { 88 | $test = $path . DIRECTORY_SEPARATOR . $filename; 89 | if (file_exists($test)) { 90 | return include_once($test); 91 | } 92 | } 93 | } 94 | 95 | return false; 96 | } 97 | 98 | public function register() 99 | { 100 | spl_autoload_register([$this, 'autoload']); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /inc/checkdatabasecommand.class.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | use Glpi\Console\AbstractCommand; 32 | use Symfony\Component\Console\Command\Command; 33 | use Symfony\Component\Console\Input\InputInterface; 34 | use Symfony\Component\Console\Input\InputOption; 35 | use Symfony\Component\Console\Output\OutputInterface; 36 | 37 | class PluginFieldsCheckDatabaseCommand extends AbstractCommand 38 | { 39 | protected function configure() 40 | { 41 | $this->setName('plugin:fields:check_database'); 42 | $this->setDescription(__('Check database to detect inconsistencies.', 'fields')); 43 | $this->setHelp( 44 | __('This command will check database to detect following inconsistencies:', 'fields') 45 | . "\n" 46 | . sprintf( 47 | __('- some deleted fields may still be present in database (bug introduced in version %s and fixed in version %s)', 'fields'), 48 | '1.15.0', 49 | '1.15.3', 50 | ), 51 | ); 52 | 53 | $this->addOption( 54 | 'fix', 55 | null, 56 | InputOption::VALUE_NONE, 57 | __('Use this option to actually fix database', 'fields'), 58 | ); 59 | } 60 | 61 | protected function execute(InputInterface $input, OutputInterface $output) 62 | { 63 | // Read option 64 | $fix = $input->getOption('fix'); 65 | 66 | $dead_fields = PluginFieldsMigration::checkDeadFields($fix); 67 | $dead_fields_count = count($dead_fields, COUNT_RECURSIVE) - count($dead_fields); 68 | 69 | // No invalid fields found 70 | if ($dead_fields_count === 0) { 71 | $output->writeln( 72 | '' . __('Everything is in order - no action needed.', 'fields') . '', 73 | ); 74 | 75 | return Command::SUCCESS; 76 | } 77 | 78 | // Indicate which fields will have been or must be deleted 79 | $error = $fix 80 | ? sprintf(__('Database was containing orphaned data from %s improperly deleted field(s).', 'fields'), $dead_fields_count) 81 | : sprintf(__('Database contains orphaned data from %s improperly deleted field(s).', 'fields'), $dead_fields_count); 82 | $output->writeln('' . $error . '', OutputInterface::VERBOSITY_QUIET); 83 | 84 | foreach ($dead_fields as $table => $fields) { 85 | foreach ($fields as $field) { 86 | $info = $fix 87 | ? sprintf(__('-> "%s.%s" has been deleted.', 'fields'), $table, $field) 88 | : sprintf(__('-> "%s.%s" should be deleted.', 'fields'), $table, $field); 89 | $output->writeln($info); 90 | } 91 | } 92 | 93 | // Show extra info in dry-run mode 94 | if (!$fix) { 95 | // Print command to do the actual deletion 96 | $next_command = sprintf( 97 | __('Run "%s" to fix database inconsistencies.', 'fields'), 98 | sprintf('php bin/console %s --fix', $this->getName()), 99 | ); 100 | $output->writeln( 101 | '' . $next_command . '', 102 | OutputInterface::VERBOSITY_QUIET, 103 | ); 104 | } 105 | 106 | return Command::SUCCESS; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /inc/command/regeneratefilescommand.class.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | namespace PluginFieldsCommand; 32 | 33 | use Glpi\Console\AbstractCommand; 34 | use Symfony\Component\Console\Command\Command; 35 | 36 | class RegenerateFilesCommand extends AbstractCommand 37 | { 38 | protected function configure() 39 | { 40 | $this->setName('plugin:fields:regenerate_files'); 41 | $this->setDescription(__('Regenerates containers files.', 'fields')); 42 | $this->setHelp( 43 | __('This command will clean up all files generated by the plugin and regenerate them.', 'fields'), 44 | ); 45 | } 46 | 47 | protected function execute($input, $output) 48 | { 49 | plugin_fields_checkFiles(); 50 | 51 | return Command::SUCCESS; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /inc/inventory.class.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | class PluginFieldsInventory extends CommonDBTM 32 | { 33 | public static function updateInventory($params = []) 34 | { 35 | if ( 36 | !empty($params) 37 | && isset($params['inventory_data']) && !empty($params['inventory_data']) 38 | ) { 39 | $availaibleItemType = ['Computer', 'Printer', 'NetworkEquipment']; 40 | foreach (array_keys($params['inventory_data']) as $itemtype) { 41 | if (in_array($itemtype, $availaibleItemType)) { 42 | $items_id = 0; 43 | //retrieve items id switch itemtype 44 | switch ($itemtype) { 45 | case Computer::getType(): 46 | $items_id = $params['computers_id']; 47 | break; 48 | 49 | case NetworkEquipment::getType(): 50 | $items_id = $params['networkequipments_id']; 51 | break; 52 | 53 | case Printer::getType(): 54 | $items_id = $params['printers_id']; 55 | break; 56 | } 57 | 58 | if (class_exists('PluginFusioninventoryInventoryComputerComputer')) { 59 | if ($itemtype == Computer::getType()) { 60 | //load inventory from DB because 61 | //FI not update XML file if computer is not update 62 | $db_info = new PluginFusioninventoryInventoryComputerComputer(); 63 | if ($db_info->getFromDBByCrit(['computers_id' => $items_id])) { 64 | $arrayinventory = unserialize(gzuncompress($db_info->fields['serialized_inventory'])); 65 | if (isset($arrayinventory['custom'])) { 66 | self::updateFields($arrayinventory['custom']['container'], $itemtype, $items_id); 67 | } 68 | } 69 | } else { 70 | //Load XML file because FI always update XML file and don't store inventory into DB 71 | $file = self::loadXMLFile($itemtype, $items_id); 72 | if ( 73 | $file !== false 74 | && class_exists('PluginFusioninventoryFormatconvert') 75 | ) { 76 | $arrayinventory = PluginFusioninventoryFormatconvert::XMLtoArray($file); 77 | if (isset($arrayinventory['CUSTOM'])) { 78 | self::updateFields($arrayinventory['CUSTOM']['CONTAINER'], $itemtype, $items_id); 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | 88 | public static function updateFields($containersData, $itemtype, $items_id) 89 | { 90 | if (isset($containersData['ID'])) { 91 | // $containersData contains only one element, encapsulate it into an array 92 | $containersData = [$containersData]; 93 | } 94 | foreach ($containersData as $key => $containerData) { 95 | $container = new PluginFieldsContainer(); 96 | $container->getFromDB($containerData['ID']); 97 | $data = []; 98 | $data['items_id'] = $items_id; 99 | $data['itemtype'] = $itemtype; 100 | $data['plugin_fields_containers_id'] = $containerData['ID']; 101 | foreach ($containerData['FIELDS'] as $key => $value) { 102 | $data[strtolower($key)] = $value; 103 | } 104 | $container->updateFieldsValues($data, $itemtype, false); 105 | } 106 | } 107 | 108 | public static function loadXMLFile($itemtype, $items_id) 109 | { 110 | $pxml = false; 111 | $folder = substr($items_id, 0, -1); 112 | if (empty($folder)) { 113 | $folder = '0'; 114 | } 115 | 116 | //Check if the file exists with the .xml extension (new format) 117 | /** @phpstan-ignore-next-line */ 118 | $file = PLUGIN_FUSIONINVENTORY_XML_DIR . strtolower($itemtype) . '/' . $folder . '/' . $items_id; 119 | if (file_exists($file . '.xml')) { 120 | $file .= '.xml'; 121 | } elseif (!file_exists($file)) { 122 | return false; 123 | } 124 | $pxml = simplexml_load_file($file, 'SimpleXMLElement', LIBXML_NOCDATA); 125 | 126 | return $pxml; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /inc/menu.class.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | class PluginFieldsMenu extends CommonGLPI 32 | { 33 | public static $rightname = 'entity'; 34 | 35 | public static function getMenuName() 36 | { 37 | return __('Additional fields', 'fields'); 38 | } 39 | 40 | public static function getMenuContent() 41 | { 42 | if (!Session::haveRight('entity', READ)) { 43 | return false; 44 | } 45 | 46 | $front_fields = Plugin::getPhpDir('fields', false) . '/front'; 47 | $menu = [ 48 | 'title' => self::getMenuName(), 49 | 'page' => "$front_fields/container.php", 50 | 'icon' => PluginFieldsContainer::getIcon(), 51 | ]; 52 | 53 | $itemtypes = ['PluginFieldsContainer' => 'fieldscontainer']; 54 | 55 | foreach ($itemtypes as $itemtype => $option) { 56 | $menu['options'][$option] = [ 57 | 'title' => $itemtype::getTypeName(2), 58 | 'page' => $itemtype::getSearchURL(false), 59 | 'links' => [ 60 | 'search' => $itemtype::getSearchURL(false), 61 | ], 62 | ]; 63 | 64 | if ($itemtype::canCreate()) { 65 | $menu['options'][$option]['links']['add'] = $itemtype::getFormURL(false); 66 | } 67 | } 68 | 69 | return $menu; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /inc/migration.class.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | class PluginFieldsMigration extends Migration 32 | { 33 | public function displayMessage($msg) 34 | { 35 | Session::addMessageAfterRedirect($msg); 36 | } 37 | 38 | /** 39 | * Return SQL fields corresponding to given additionnal field. 40 | * 41 | * @param string $field_name 42 | * @param string $field_type 43 | * @param array $options 44 | * 45 | * @return array 46 | */ 47 | public static function getSQLFields(string $field_name, string $field_type, array $options = []): array 48 | { 49 | $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); 50 | 51 | $fields = []; 52 | switch (true) { 53 | case $field_type === 'header': 54 | // header type is for read-only display purpose only and has no SQL field 55 | break; 56 | case $field_type === 'dropdown': 57 | case preg_match('/^dropdown-.+/i', $field_type): 58 | if ($field_type === 'dropdown') { 59 | $field_name = getForeignKeyFieldForItemType(PluginFieldsDropdown::getClassname($field_name)); 60 | } 61 | if ($options['multiple'] ?? false) { 62 | $fields[$field_name] = 'LONGTEXT'; 63 | } else { 64 | $fields[$field_name] = "INT {$default_key_sign} NOT NULL DEFAULT 0"; 65 | } 66 | break; 67 | case $field_type === 'textarea': 68 | case $field_type === 'url': 69 | $fields[$field_name] = 'TEXT DEFAULT NULL'; 70 | break; 71 | case $field_type === 'richtext': 72 | $fields[$field_name] = 'LONGTEXT DEFAULT NULL'; 73 | break; 74 | case $field_type === 'yesno': 75 | $fields[$field_name] = 'INT NOT NULL DEFAULT 0'; 76 | break; 77 | case $field_type === 'glpi_item': 78 | $fields[sprintf('itemtype_%s', $field_name)] = 'varchar(100) DEFAULT NULL'; 79 | $fields[sprintf('items_id_%s', $field_name)] = "int {$default_key_sign} NOT NULL DEFAULT 0"; 80 | break; 81 | case $field_type === 'date': 82 | case $field_type === 'datetime': 83 | case $field_type === 'number': 84 | case $field_type === 'text': 85 | default: 86 | $fields[$field_name] = 'VARCHAR(255) DEFAULT NULL'; 87 | break; 88 | } 89 | 90 | return $fields; 91 | } 92 | 93 | /** 94 | * An issue affected field removal in 1.15.0, 1.15.1 and 1.15.2. 95 | * Using these versions, removing a field from a container would drop the 96 | * field from glpi_plugin_fields_fields but not from the custom container 97 | * table 98 | * 99 | * This function looks into containers tables for fields that 100 | * should have been removed and list them. 101 | * If parameter $fix is true, fields are deleted from database. 102 | * 103 | * @param bool $fix 104 | * 105 | * @return array 106 | */ 107 | public static function checkDeadFields(bool $fix): array 108 | { 109 | /** @var DBmysql $DB */ 110 | global $DB; 111 | 112 | $dead_fields = []; 113 | 114 | // For each existing container 115 | $containers = (new PluginFieldsContainer())->find([]); 116 | foreach ($containers as $row) { 117 | // Get expected fields 118 | $valid_fields = self::getValidFieldsForContainer($row['id']); 119 | 120 | // Read itemtypes and container name 121 | $itemtypes = importArrayFromDB($row['itemtypes']); 122 | $name = $row['name']; 123 | 124 | // One table to handle per itemtype 125 | foreach ($itemtypes as $itemtype) { 126 | // Build table name 127 | $table = getTableForItemType("PluginFields{$itemtype}{$name}"); 128 | 129 | if (!$DB->tableExists($table)) { 130 | // Missing table; skip (abnormal) 131 | continue; 132 | } 133 | 134 | // Get the actual fields defined in the container table 135 | $found_fields = self::getCustomFieldsInContainerTable($table); 136 | 137 | // Compute which fields should be removed 138 | $fields_to_drop = array_diff($found_fields, $valid_fields); 139 | 140 | if (count($fields_to_drop) > 0) { 141 | $dead_fields[$table] = $fields_to_drop; 142 | } 143 | } 144 | } 145 | 146 | if ($fix) { 147 | $migration = new PluginFieldsMigration('0'); 148 | 149 | foreach ($dead_fields as $table => $fields) { 150 | foreach ($fields as $field) { 151 | $migration->dropField($table, $field); 152 | } 153 | } 154 | 155 | $migration->executeMigration(); 156 | } 157 | 158 | return $dead_fields; 159 | } 160 | 161 | /** 162 | * Get all fields defined for a container in glpi_plugin_fields_fields 163 | * 164 | * @param int $container_id Id of the container 165 | * 166 | * @return array 167 | */ 168 | private static function getValidFieldsForContainer(int $container_id): array 169 | { 170 | $valid_fields = []; 171 | 172 | // For each defined fields in the given container 173 | $fields = (new PluginFieldsField())->find(['plugin_fields_containers_id' => $container_id]); 174 | foreach ($fields as $row) { 175 | $fields = self::getSQLFields($row['name'], $row['type'], $row); 176 | array_push($valid_fields, ...array_keys($fields)); 177 | } 178 | 179 | return $valid_fields; 180 | } 181 | 182 | /** 183 | * Get custom fields in a given container table 184 | * This means all fields found in the table expect those defined in 185 | * $basic_fields 186 | * 187 | * @param string $table 188 | * 189 | * @return array 190 | */ 191 | private static function getCustomFieldsInContainerTable( 192 | string $table 193 | ): array { 194 | /** @var DBmysql $DB */ 195 | global $DB; 196 | 197 | // Read table fields 198 | $fields = $DB->listFields($table); 199 | 200 | // Reduce to fields name only 201 | $fields = array_column($fields, 'Field'); 202 | 203 | // Remove basic fields 204 | $basic_fields = [ 205 | 'id', 206 | 'items_id', 207 | 'itemtype', 208 | 'plugin_fields_containers_id', 209 | ]; 210 | 211 | return array_filter( 212 | $fields, 213 | function (string $field) use ($basic_fields) { 214 | return !in_array($field, $basic_fields); 215 | }, 216 | ); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /inc/profile.class.php: -------------------------------------------------------------------------------- 1 | . 24 | * ------------------------------------------------------------------------- 25 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 26 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 27 | * @link https://github.com/pluginsGLPI/fields 28 | * ------------------------------------------------------------------------- 29 | */ 30 | 31 | class PluginFieldsProfile extends CommonDBRelation 32 | { 33 | use Glpi\Features\Clonable; 34 | 35 | public static $itemtype_1 = PluginFieldsContainer::class; 36 | public static $items_id_1 = 'plugin_fields_containers_id'; 37 | public static $itemtype_2 = Profile::class; 38 | public static $items_id_2 = 'profiles_id'; 39 | 40 | /** 41 | * Install or update plugin base data. 42 | * 43 | * @param Migration $migration Migration instance 44 | * @param string $version Plugin current version 45 | * 46 | * @return boolean 47 | */ 48 | public static function installBaseData(Migration $migration, $version) 49 | { 50 | /** @var DBmysql $DB */ 51 | global $DB; 52 | 53 | $default_charset = DBConnection::getDefaultCharset(); 54 | $default_collation = DBConnection::getDefaultCollation(); 55 | $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); 56 | 57 | $table = self::getTable(); 58 | 59 | if (!$DB->tableExists($table)) { 60 | $migration->displayMessage(sprintf(__('Installing %s'), $table)); 61 | 62 | $query = "CREATE TABLE IF NOT EXISTS `$table` ( 63 | `id` INT {$default_key_sign} NOT NULL auto_increment, 64 | `profiles_id` INT {$default_key_sign} NOT NULL DEFAULT '0', 65 | `plugin_fields_containers_id` INT {$default_key_sign} NOT NULL DEFAULT '0', 66 | `right` CHAR(1) DEFAULT NULL, 67 | PRIMARY KEY (`id`), 68 | KEY `profiles_id` (`profiles_id`), 69 | KEY `plugin_fields_containers_id` (`plugin_fields_containers_id`) 70 | ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; 71 | $DB->doQuery($query) or die($DB->error()); 72 | } 73 | 74 | return true; 75 | } 76 | 77 | public static function uninstall() 78 | { 79 | /** @var DBmysql $DB */ 80 | global $DB; 81 | 82 | $DB->doQuery('DROP TABLE IF EXISTS `' . self::getTable() . '`'); 83 | 84 | return true; 85 | } 86 | 87 | public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) 88 | { 89 | return self::createTabEntry(_n('Profile', 'Profiles', 2)); 90 | } 91 | 92 | public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) 93 | { 94 | if (!($item instanceof CommonDBTM)) { 95 | return false; 96 | } 97 | 98 | $profile = new Profile(); 99 | $found_profiles = $profile->find(); 100 | 101 | $fields_profile = new self(); 102 | echo "
"; 103 | echo "
"; 104 | echo ""; 105 | 106 | echo "'; 107 | foreach ($found_profiles as $profile_item) { 108 | //get right for current profile 109 | $found = $fields_profile->find([ 110 | 'profiles_id' => $profile_item['id'], 111 | 'plugin_fields_containers_id' => $item->fields['id'], 112 | ]); 113 | $first_found = array_shift($found); 114 | 115 | //display right 116 | echo ''; 117 | echo ''; 118 | echo ''; 124 | echo ''; 125 | } 126 | echo '
    '; 127 | echo "
'; 131 | echo ''; 132 | echo '
" . _n('Profile', 'Profiles', 2) . '
' . $profile_item['name'] . ''; 119 | Profile::dropdownRight( 120 | 'rights[' . $profile_item['id'] . ']', 121 | ['value' => $first_found['right']], 122 | ); 123 | echo '
"; 128 | echo ""; 129 | echo ""; 130 | echo '
'; 133 | Html::closeForm(); 134 | 135 | return true; 136 | } 137 | 138 | public static function updateProfile($input) 139 | { 140 | $fields_profile = new self(); 141 | foreach ($input['rights'] as $profiles_id => $right) { 142 | $found = $fields_profile->find( 143 | [ 144 | 'profiles_id' => $profiles_id, 145 | 'plugin_fields_containers_id' => $input['plugin_fields_containers_id'], 146 | ], 147 | ); 148 | if (count($found) > 0) { 149 | $first_found = array_shift($found); 150 | 151 | $fields_profile->update([ 152 | 'id' => $first_found['id'], 153 | 'profiles_id' => $profiles_id, 154 | 'plugin_fields_containers_id' => $input['plugin_fields_containers_id'], 155 | 'right' => $right, 156 | ]); 157 | } else { 158 | $fields_profile->add([ 159 | 'profiles_id' => $profiles_id, 160 | 'plugin_fields_containers_id' => $input['plugin_fields_containers_id'], 161 | 'right' => $right, 162 | ]); 163 | } 164 | } 165 | 166 | return true; 167 | } 168 | 169 | public static function createForContainer(PluginFieldsContainer $container) 170 | { 171 | $profile = new Profile(); 172 | $found_profiles = $profile->find(); 173 | 174 | $fields_profile = new self(); 175 | foreach ($found_profiles as $profile_item) { 176 | $fields_profile->add([ 177 | 'profiles_id' => $profile_item['id'], 178 | 'plugin_fields_containers_id' => $container->fields['id'], 179 | 'right' => CREATE, 180 | ]); 181 | } 182 | 183 | return true; 184 | } 185 | 186 | public static function addNewProfile(Profile $profile) 187 | { 188 | $containers = new PluginFieldsContainer(); 189 | $found_containers = $containers->find(); 190 | 191 | $fields_profile = new self(); 192 | foreach ($found_containers as $container) { 193 | $fields_profile->add([ 194 | 'profiles_id' => $profile->fields['id'], 195 | 'plugin_fields_containers_id' => $container['id'], 196 | ]); 197 | } 198 | 199 | return true; 200 | } 201 | 202 | public static function deleteProfile(Profile $profile) 203 | { 204 | $fields_profile = new self(); 205 | $fields_profile->deleteByCriteria(['profiles_id' => $profile->fields['id']]); 206 | 207 | return true; 208 | } 209 | 210 | public static function getRightOnContainer(int $profile_id, int $container_id): int 211 | { 212 | /** @var DBmysql $DB */ 213 | global $DB; 214 | 215 | $container_profile = $DB->request( 216 | [ 217 | 'SELECT' => ['MAX' => 'right AS right'], 218 | 'FROM' => self::getTable(), 219 | 'WHERE' => [ 220 | 'profiles_id' => $profile_id, 221 | 'plugin_fields_containers_id' => $container_id, 222 | ], 223 | ], 224 | ); 225 | 226 | return (int) $container_profile->current()['right']; 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /js/drag-field-row.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ------------------------------------------------------------------------- 3 | * Fields plugin for GLPI 4 | * ------------------------------------------------------------------------- 5 | * 6 | * LICENSE 7 | * 8 | * This file is part of Fields. 9 | * 10 | * Fields is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * Fields is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with Fields. If not, see . 22 | * ------------------------------------------------------------------------- 23 | * @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | * @link https://github.com/pluginsGLPI/fields 26 | * ------------------------------------------------------------------------- 27 | */ 28 | 29 | /* enable strict mode */ 30 | "use strict"; 31 | 32 | var redipsInit; // function sets dropMode parameter 33 | 34 | // redips initialization 35 | redipsInit = function () { 36 | // reference to the REDIPS.drag lib 37 | var rd = REDIPS.drag; 38 | // initialization 39 | rd.init(); 40 | 41 | rd.event.rowDroppedBefore = function (sourceTable, sourceRowIndex) { 42 | var pos = rd.getPosition(); 43 | 44 | var old_index = sourceRowIndex; 45 | var new_index = pos[1]; 46 | var container = document.getElementById('plugin_fields_containers_id').value; 47 | 48 | jQuery.ajax({ 49 | type: "POST", 50 | url: "../ajax/reorder.php", 51 | data: { 52 | old_order: old_index, 53 | new_order: new_index, 54 | container_id: container 55 | } 56 | }) 57 | .fail(function() { 58 | return false; 59 | }); 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /locales/cs_CZ.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/cs_CZ.mo -------------------------------------------------------------------------------- /locales/de_DE.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/de_DE.mo -------------------------------------------------------------------------------- /locales/en_GB.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/en_GB.mo -------------------------------------------------------------------------------- /locales/en_US.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/en_US.mo -------------------------------------------------------------------------------- /locales/es_AR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/es_AR.mo -------------------------------------------------------------------------------- /locales/es_EC.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/es_EC.mo -------------------------------------------------------------------------------- /locales/es_ES.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/es_ES.mo -------------------------------------------------------------------------------- /locales/es_MX.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/es_MX.mo -------------------------------------------------------------------------------- /locales/fi_FI.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/fi_FI.mo -------------------------------------------------------------------------------- /locales/fi_FI.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # Markku Vepsä, 2018 7 | # Markku Vepsä, 2018 8 | msgid "" 9 | msgstr "" 10 | "Project-Id-Version: GLPI Plugin - Fields\n" 11 | "Report-Msgid-Bugs-To: \n" 12 | "POT-Creation-Date: 2023-10-04 14:23+0000\n" 13 | "PO-Revision-Date: 2015-09-18 09:34+0000\n" 14 | "Last-Translator: Markku Vepsä, 2018\n" 15 | "Language-Team: Finnish (Finland) (http://app.transifex.com/teclib/glpi-plugin-plugin-fields/language/fi_FI/)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Language: fi_FI\n" 20 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 21 | 22 | #: inc/checkdatabasecommand.class.php:47 23 | #, php-format 24 | msgid "" 25 | "- some deleted fields may still be present in database (bug introduced in " 26 | "version %s and fixed in version %s)" 27 | msgstr "" 28 | 29 | #: inc/checkdatabasecommand.class.php:86 30 | #, php-format 31 | msgid "-> \"%s.%s\" has been deleted." 32 | msgstr "" 33 | 34 | #: inc/checkdatabasecommand.class.php:87 35 | #, php-format 36 | msgid "-> \"%s.%s\" should be deleted." 37 | msgstr "" 38 | 39 | #: inc/field.class.php:573 40 | msgid "Add a new field" 41 | msgstr "Lisää uusi kenttä" 42 | 43 | #: templates/container_display_conditions.html.twig 44 | msgid "Add condition to hide block" 45 | msgstr "" 46 | 47 | #: templates/status_overrides.html.twig 48 | msgid "Add new status override" 49 | msgstr "" 50 | 51 | #: inc/container.class.php:994 52 | msgid "Add tab" 53 | msgstr "Lisää välilehti" 54 | 55 | #: inc/menu.class.php:37 front/container.php:34 front/container.form.php:63 56 | #: setup.php:200 57 | msgid "Additional fields" 58 | msgstr "Lisäkentät" 59 | 60 | #: ajax/field_specific_fields.php:53 61 | msgid "Allowed values" 62 | msgstr "" 63 | 64 | #: inc/container.class.php:742 65 | msgid "Block" 66 | msgstr "Osio" 67 | 68 | #: inc/checkdatabasecommand.class.php:42 69 | msgid "Check database to detect inconsistencies." 70 | msgstr "" 71 | 72 | #: inc/toolbox.class.php:316 73 | msgid "Component items" 74 | msgstr "" 75 | 76 | #: templates/container_display_conditions.html.twig 77 | #: inc/containerdisplaycondition.class.php:153 78 | msgid "Condition to hide block" 79 | msgid_plural "Conditions to hide block" 80 | msgstr[0] "" 81 | msgstr[1] "" 82 | 83 | #: inc/container.class.php:565 84 | msgid "" 85 | "Container name is too long for database (digits in name are replaced by " 86 | "characters, try to remove them)" 87 | msgstr "" 88 | 89 | #: inc/checkdatabasecommand.class.php:80 90 | #, php-format 91 | msgid "Database contains orphaned data from %s improperly deleted field(s)." 92 | msgstr "" 93 | 94 | #: inc/checkdatabasecommand.class.php:79 95 | #, php-format 96 | msgid "" 97 | "Database was containing orphaned data from %s improperly deleted field(s)." 98 | msgstr "" 99 | 100 | #: inc/field.class.php:1309 101 | msgid "Date" 102 | msgstr "Päivämäärä" 103 | 104 | #: inc/field.class.php:1310 105 | msgid "Date & time" 106 | msgstr "Päivämäärä ja aika" 107 | 108 | #: ajax/field_specific_fields.php:89 109 | msgid "Default value" 110 | msgstr "" 111 | 112 | #: ajax/field_specific_fields.php:116 113 | msgid "Default value will be configurable once field will be created." 114 | msgstr "" 115 | 116 | #: inc/field.class.php:1307 117 | msgid "Dropdown" 118 | msgstr "Pudotusvalikko" 119 | 120 | #: inc/checkdatabasecommand.class.php:72 121 | msgid "Everything is in order - no action needed." 122 | msgstr "" 123 | 124 | #: inc/container.class.php:53 inc/container.class.php:752 125 | msgid "Export to YAML" 126 | msgstr "" 127 | 128 | #: templates/forms/status_override.html.twig inc/field.class.php:241 129 | msgid "Field" 130 | msgstr "Kenttä" 131 | 132 | #: inc/field.class.php:257 inc/field.class.php:282 133 | msgid "" 134 | "Field name is too long for database (digits in name are replaced by " 135 | "characters, try to remove them)" 136 | msgstr "" 137 | 138 | #: inc/field.class.php:515 139 | msgid "Fields" 140 | msgstr "Kentät" 141 | 142 | #: inc/container.class.php:208 143 | msgid "Fix container names" 144 | msgstr "" 145 | 146 | #: inc/toolbox.class.php:122 147 | msgid "Fix fields names" 148 | msgstr "" 149 | 150 | #: inc/field.class.php:1311 151 | msgid "GLPI item" 152 | msgstr "" 153 | 154 | #: inc/field.class.php:1301 155 | msgid "Header" 156 | msgstr "Ylätunniste" 157 | 158 | #: inc/container.class.php:995 159 | msgid "Insertion in the form (before save button)" 160 | msgstr "Lisää lomakkeeseen (ennen tallennuspainiketta)" 161 | 162 | #: inc/container.class.php:996 163 | msgid "Insertion in the form of a specific tab (before save button)" 164 | msgstr "Lisää lomakkeeseen tietyssä välilehdessä (ennen tallennuspainiketta)" 165 | 166 | #: inc/labeltranslation.class.php:192 167 | msgid "Label" 168 | msgstr "Etiketti" 169 | 170 | #: inc/labeltranslation.class.php:191 171 | msgid "Language" 172 | msgstr "Kieli" 173 | 174 | #: ajax/field_specific_fields.php:86 175 | msgid "Multiple dropdown" 176 | msgstr "" 177 | 178 | #: hook.php:55 hook.php:59 179 | msgid "MySQL tables installation" 180 | msgstr "MySQL-taulukoiden asennus" 181 | 182 | #: hook.php:121 183 | msgid "MySQL tables uninstallation" 184 | msgstr "MySQL-taulukoiden poistaminen" 185 | 186 | #: inc/field.class.php:577 187 | msgid "No field for this block" 188 | msgstr "Ei kenttää tälle osiolle" 189 | 190 | #: templates/status_overrides.html.twig 191 | msgid "No item found" 192 | msgstr "" 193 | 194 | #: inc/field.class.php:1305 195 | msgid "Number" 196 | msgstr "Numero" 197 | 198 | #: inc/statusoverride.class.php:88 199 | msgid "Override by status" 200 | msgstr "" 201 | 202 | #: templates/forms/status_override.html.twig inc/field.class.php:590 203 | #: inc/field.class.php:770 204 | msgid "Read only" 205 | msgstr "Vain luku" 206 | 207 | #: inc/container.class.php:52 208 | msgid "Regenerate container files" 209 | msgstr "Luo uudelleen säilötiedostot" 210 | 211 | #: inc/container.class.php:187 212 | msgid "Regenerate containers files" 213 | msgstr "" 214 | 215 | #: inc/command/regeneratefilescommand.class.php:41 216 | msgid "Regenerates containers files." 217 | msgstr "" 218 | 219 | #: inc/field.class.php:1304 220 | msgid "Rich Text" 221 | msgstr "" 222 | 223 | #: inc/checkdatabasecommand.class.php:96 224 | #, php-format 225 | msgid "Run \"%s\" to fix database inconsistencies." 226 | msgstr "" 227 | 228 | #: inc/container.class.php:1504 229 | msgid "Some URL fields contains invalid links" 230 | msgstr "Joissakin URL-kentissä on virheellisiä linkkejä" 231 | 232 | #: inc/container.class.php:1494 233 | msgid "Some mandatory fields are empty" 234 | msgstr "Jotkut pakolliset kentät ovat tyhjiä" 235 | 236 | #: inc/container.class.php:1499 237 | msgid "Some numeric fields contains non numeric values" 238 | msgstr "Jotkin numeeriset kentät sisältävät ei-numeerisia arvoja" 239 | 240 | #: templates/status_overrides.html.twig 241 | msgid "Status overrides" 242 | msgstr "" 243 | 244 | #: inc/container.class.php:846 245 | msgid "Tab" 246 | msgstr "Välilehti" 247 | 248 | #: inc/field.class.php:1303 249 | msgid "Text (multiples lines)" 250 | msgstr "Teksti (useita rivejä)" 251 | 252 | #: inc/field.class.php:1302 253 | msgid "Text (single line)" 254 | msgstr "Teksti (yksi rivi)" 255 | 256 | #: hook.php:109 257 | msgid "The plugin can't be uninstalled when the plugin is disabled" 258 | msgstr "Liitännäistä ei voi poistaa, kun liitännäinen on poistettu käytöstä" 259 | 260 | #: inc/checkdatabasecommand.class.php:44 261 | msgid "This command will check database to detect following inconsistencies:" 262 | msgstr "" 263 | 264 | #: inc/command/regeneratefilescommand.class.php:43 265 | msgid "" 266 | "This command will clean up all files generated by the plugin and regenerate " 267 | "them." 268 | msgstr "" 269 | 270 | #: inc/field.class.php:1306 271 | msgid "URL" 272 | msgstr "URL" 273 | 274 | #: inc/container.class.php:328 275 | msgid "Updating generated containers files" 276 | msgstr "Päivitetään luodut säilötiedostot" 277 | 278 | #: inc/dropdown.class.php:78 279 | msgid "Updating generated dropdown files" 280 | msgstr "Päivitetään luodut pudotusvalikko tiedostot" 281 | 282 | #: inc/checkdatabasecommand.class.php:57 283 | msgid "Use this option to actually fix database" 284 | msgstr "" 285 | 286 | #: inc/field.class.php:1308 287 | msgid "Yes/No" 288 | msgstr "Kyllä/Ei" 289 | 290 | #: inc/container.class.php:514 291 | msgid "You cannot add block without associated element type" 292 | msgstr "Et voi lisätä osiota ilman liittyvää elementtityyppiä" 293 | 294 | #: inc/container.class.php:549 295 | msgid "" 296 | "You cannot add several blocks with type 'Insertion in the form of a specific" 297 | " tab' on same object tab" 298 | msgstr "Et voi lisätä useita osioita, joissa on tyyppi \"Liitettynä lomakkeeseen tietyssä välilehdessä\" samassa objektin välilehdessä" 299 | 300 | #: inc/container.class.php:534 301 | msgid "" 302 | "You cannot add several blocks with type 'Insertion in the form' on same " 303 | "object" 304 | msgstr "Et voi lisätä useita osioita, joiden tyyppi on \"Lisää lomakkeeseen\" samassa objektissa" 305 | 306 | #: inc/container.class.php:579 307 | msgid "You cannot add several blocs with identical name on same object" 308 | msgstr "Et voi lisätä useita osioita samalla nimellä samaan objektiin" 309 | 310 | #: inc/containerdisplaycondition.class.php:493 311 | #: inc/containerdisplaycondition.class.php:508 312 | msgid "You must specify an item type, search option and condition." 313 | msgstr "" 314 | 315 | #: inc/containerdisplaycondition.class.php:103 316 | #: inc/containerdisplaycondition.class.php:137 317 | msgid "not under" 318 | msgstr "" 319 | 320 | #: inc/containerdisplaycondition.class.php:109 321 | #: inc/containerdisplaycondition.class.php:131 322 | msgid "regular expression matches" 323 | msgstr "" 324 | 325 | #: templates/fields.html.twig 326 | msgid "show" 327 | msgstr "näytä" 328 | 329 | #: inc/containerdisplaycondition.class.php:102 330 | #: inc/containerdisplaycondition.class.php:134 331 | msgid "under" 332 | msgstr "" 333 | -------------------------------------------------------------------------------- /locales/fields.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2025-02-10 01:02+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=CHARSET\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 20 | 21 | #: inc/checkdatabasecommand.class.php:47 22 | #, php-format 23 | msgid "" 24 | "- some deleted fields may still be present in database (bug introduced in " 25 | "version %s and fixed in version %s)" 26 | msgstr "" 27 | 28 | #: inc/checkdatabasecommand.class.php:87 29 | #, php-format 30 | msgid "-> \"%s.%s\" has been deleted." 31 | msgstr "" 32 | 33 | #: inc/checkdatabasecommand.class.php:88 34 | #, php-format 35 | msgid "-> \"%s.%s\" should be deleted." 36 | msgstr "" 37 | 38 | #: inc/field.class.php:608 39 | msgid "Add a new field" 40 | msgstr "" 41 | 42 | #: templates/container_display_conditions.html.twig 43 | msgid "Add condition to hide block" 44 | msgstr "" 45 | 46 | #: templates/status_overrides.html.twig 47 | msgid "Add new status override" 48 | msgstr "" 49 | 50 | #: inc/container.class.php:1040 51 | msgid "Add tab" 52 | msgstr "" 53 | 54 | #: front/container.php:34 front/container.form.php:63 inc/menu.class.php:37 55 | #: setup.php:223 56 | msgid "Additional fields" 57 | msgstr "" 58 | 59 | #: ajax/field_specific_fields.php:53 60 | msgid "Allowed values" 61 | msgstr "" 62 | 63 | #: inc/container.class.php:781 64 | msgid "Block" 65 | msgstr "" 66 | 67 | #: inc/checkdatabasecommand.class.php:42 68 | msgid "Check database to detect inconsistencies." 69 | msgstr "" 70 | 71 | #: inc/toolbox.class.php:322 72 | msgid "Component items" 73 | msgstr "" 74 | 75 | #: templates/container_display_conditions.html.twig 76 | #: inc/containerdisplaycondition.class.php:155 77 | msgid "Condition to hide block" 78 | msgid_plural "Conditions to hide block" 79 | msgstr[0] "" 80 | msgstr[1] "" 81 | 82 | #: inc/container.class.php:600 83 | msgid "" 84 | "Container name is too long for database (digits in name are replaced by " 85 | "characters, try to remove them)" 86 | msgstr "" 87 | 88 | #: inc/checkdatabasecommand.class.php:81 89 | #, php-format 90 | msgid "Database contains orphaned data from %s improperly deleted field(s)." 91 | msgstr "" 92 | 93 | #: inc/checkdatabasecommand.class.php:80 94 | #, php-format 95 | msgid "" 96 | "Database was containing orphaned data from %s improperly deleted field(s)." 97 | msgstr "" 98 | 99 | #: inc/field.class.php:1343 100 | msgid "Date" 101 | msgstr "" 102 | 103 | #: inc/field.class.php:1344 104 | msgid "Date & time" 105 | msgstr "" 106 | 107 | #: ajax/field_specific_fields.php:90 108 | msgid "Default value" 109 | msgstr "" 110 | 111 | #: ajax/field_specific_fields.php:121 112 | msgid "Default value will be configurable once field will be created." 113 | msgstr "" 114 | 115 | #: inc/field.class.php:1341 116 | msgid "Dropdown" 117 | msgstr "" 118 | 119 | #: inc/checkdatabasecommand.class.php:72 120 | msgid "Everything is in order - no action needed." 121 | msgstr "" 122 | 123 | #: inc/container.class.php:53 inc/container.class.php:790 124 | msgid "Export to YAML" 125 | msgstr "" 126 | 127 | #: templates/forms/status_override.html.twig inc/field.class.php:243 128 | msgid "Field" 129 | msgstr "" 130 | 131 | #: inc/field.class.php:258 inc/field.class.php:285 132 | msgid "" 133 | "Field name is too long for database (digits in name are replaced by " 134 | "characters, try to remove them)" 135 | msgstr "" 136 | 137 | #: inc/field.class.php:545 138 | msgid "Fields" 139 | msgstr "" 140 | 141 | #: inc/container.class.php:211 142 | msgid "Fix container names" 143 | msgstr "" 144 | 145 | #: inc/toolbox.class.php:122 146 | msgid "Fix fields names" 147 | msgstr "" 148 | 149 | #: inc/field.class.php:1345 150 | msgid "GLPI item" 151 | msgstr "" 152 | 153 | #: inc/field.class.php:1335 154 | msgid "Header" 155 | msgstr "" 156 | 157 | #: inc/container.class.php:1041 158 | msgid "Insertion in the form (before save button)" 159 | msgstr "" 160 | 161 | #: inc/container.class.php:1042 162 | msgid "Insertion in the form of a specific tab (before save button)" 163 | msgstr "" 164 | 165 | #: inc/labeltranslation.class.php:205 166 | msgid "Label" 167 | msgstr "" 168 | 169 | #: inc/labeltranslation.class.php:204 170 | msgid "Language" 171 | msgstr "" 172 | 173 | #: ajax/field_specific_fields.php:87 174 | msgid "Multiple dropdown" 175 | msgstr "" 176 | 177 | #: hook.php:55 hook.php:59 178 | msgid "MySQL tables installation" 179 | msgstr "" 180 | 181 | #: hook.php:122 182 | msgid "MySQL tables uninstallation" 183 | msgstr "" 184 | 185 | #: inc/field.class.php:612 186 | msgid "No field for this block" 187 | msgstr "" 188 | 189 | #: templates/status_overrides.html.twig 190 | msgid "No item found" 191 | msgstr "" 192 | 193 | #: inc/field.class.php:1339 194 | msgid "Number" 195 | msgstr "" 196 | 197 | #: inc/statusoverride.class.php:90 198 | msgid "Override by status" 199 | msgstr "" 200 | 201 | #: templates/forms/status_override.html.twig inc/field.class.php:625 202 | #: inc/field.class.php:805 203 | msgid "Read only" 204 | msgstr "" 205 | 206 | #: inc/container.class.php:52 207 | msgid "Regenerate container files" 208 | msgstr "" 209 | 210 | #: inc/container.class.php:190 211 | msgid "Regenerate containers files" 212 | msgstr "" 213 | 214 | #: inc/command/regeneratefilescommand.class.php:41 215 | msgid "Regenerates containers files." 216 | msgstr "" 217 | 218 | #: inc/field.class.php:1338 219 | msgid "Rich Text" 220 | msgstr "" 221 | 222 | #: inc/checkdatabasecommand.class.php:97 223 | #, php-format 224 | msgid "Run \"%s\" to fix database inconsistencies." 225 | msgstr "" 226 | 227 | #: inc/container.class.php:1550 228 | msgid "Some URL fields contains invalid links" 229 | msgstr "" 230 | 231 | #: inc/container.class.php:1540 232 | msgid "Some mandatory fields are empty" 233 | msgstr "" 234 | 235 | #: inc/container.class.php:1545 236 | msgid "Some numeric fields contains non numeric values" 237 | msgstr "" 238 | 239 | #: templates/status_overrides.html.twig 240 | msgid "Status overrides" 241 | msgstr "" 242 | 243 | #: inc/container.class.php:886 244 | msgid "Tab" 245 | msgstr "" 246 | 247 | #: inc/field.class.php:1337 248 | msgid "Text (multiples lines)" 249 | msgstr "" 250 | 251 | #: inc/field.class.php:1336 252 | msgid "Text (single line)" 253 | msgstr "" 254 | 255 | #: hook.php:109 256 | msgid "The plugin can't be uninstalled when the plugin is disabled" 257 | msgstr "" 258 | 259 | #: inc/checkdatabasecommand.class.php:44 260 | msgid "This command will check database to detect following inconsistencies:" 261 | msgstr "" 262 | 263 | #: inc/command/regeneratefilescommand.class.php:43 264 | msgid "" 265 | "This command will clean up all files generated by the plugin and regenerate " 266 | "them." 267 | msgstr "" 268 | 269 | #: inc/field.class.php:1340 270 | msgid "URL" 271 | msgstr "" 272 | 273 | #: inc/container.class.php:352 274 | msgid "Updating generated containers files" 275 | msgstr "" 276 | 277 | #: inc/dropdown.class.php:78 278 | msgid "Updating generated dropdown files" 279 | msgstr "" 280 | 281 | #: inc/checkdatabasecommand.class.php:57 282 | msgid "Use this option to actually fix database" 283 | msgstr "" 284 | 285 | #: inc/field.class.php:1342 286 | msgid "Yes/No" 287 | msgstr "" 288 | 289 | #: inc/field.class.php:277 290 | msgid "You cannot add same field 'dropdown' on same bloc" 291 | msgstr "" 292 | 293 | #: inc/container.class.php:583 294 | msgid "" 295 | "You cannot add several blocks with type 'Insertion in the form of a specific " 296 | "tab' on same object tab" 297 | msgstr "" 298 | 299 | #: inc/container.class.php:567 300 | msgid "" 301 | "You cannot add several blocks with type 'Insertion in the form' on same " 302 | "object" 303 | msgstr "" 304 | 305 | #: inc/container.class.php:615 306 | msgid "You cannot add several blocs with identical name on same object" 307 | msgstr "" 308 | 309 | #: inc/containerdisplaycondition.class.php:500 310 | #: inc/containerdisplaycondition.class.php:516 311 | msgid "You must specify an item type, search option and condition." 312 | msgstr "" 313 | 314 | #: inc/containerdisplaycondition.class.php:105 315 | #: inc/containerdisplaycondition.class.php:139 316 | msgid "not under" 317 | msgstr "" 318 | 319 | #: inc/containerdisplaycondition.class.php:111 320 | #: inc/containerdisplaycondition.class.php:133 321 | msgid "regular expression matches" 322 | msgstr "" 323 | 324 | #: templates/fields.html.twig 325 | msgid "show" 326 | msgstr "" 327 | 328 | #: inc/containerdisplaycondition.class.php:104 329 | #: inc/containerdisplaycondition.class.php:136 330 | msgid "under" 331 | msgstr "" 332 | -------------------------------------------------------------------------------- /locales/fr_FR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/fr_FR.mo -------------------------------------------------------------------------------- /locales/hr_HR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/hr_HR.mo -------------------------------------------------------------------------------- /locales/it_IT.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/it_IT.mo -------------------------------------------------------------------------------- /locales/ja_JP.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/ja_JP.mo -------------------------------------------------------------------------------- /locales/ko_KR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/ko_KR.mo -------------------------------------------------------------------------------- /locales/ko_KR.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # 조성현 (jaymz9634) , 2020-2021 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: GLPI Plugin - Fields\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2023-10-04 14:23+0000\n" 12 | "PO-Revision-Date: 2015-09-18 09:34+0000\n" 13 | "Last-Translator: 조성현 (jaymz9634) , 2020-2021\n" 14 | "Language-Team: Korean (Korea) (http://app.transifex.com/teclib/glpi-plugin-plugin-fields/language/ko_KR/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: ko_KR\n" 19 | "Plural-Forms: nplurals=1; plural=0;\n" 20 | 21 | #: inc/checkdatabasecommand.class.php:47 22 | #, php-format 23 | msgid "" 24 | "- some deleted fields may still be present in database (bug introduced in " 25 | "version %s and fixed in version %s)" 26 | msgstr "" 27 | 28 | #: inc/checkdatabasecommand.class.php:86 29 | #, php-format 30 | msgid "-> \"%s.%s\" has been deleted." 31 | msgstr "" 32 | 33 | #: inc/checkdatabasecommand.class.php:87 34 | #, php-format 35 | msgid "-> \"%s.%s\" should be deleted." 36 | msgstr "" 37 | 38 | #: inc/field.class.php:573 39 | msgid "Add a new field" 40 | msgstr "새 항목 추가" 41 | 42 | #: templates/container_display_conditions.html.twig 43 | msgid "Add condition to hide block" 44 | msgstr "" 45 | 46 | #: templates/status_overrides.html.twig 47 | msgid "Add new status override" 48 | msgstr "" 49 | 50 | #: inc/container.class.php:994 51 | msgid "Add tab" 52 | msgstr "탭 추가" 53 | 54 | #: inc/menu.class.php:37 front/container.php:34 front/container.form.php:63 55 | #: setup.php:200 56 | msgid "Additional fields" 57 | msgstr "추가 항목" 58 | 59 | #: ajax/field_specific_fields.php:53 60 | msgid "Allowed values" 61 | msgstr "" 62 | 63 | #: inc/container.class.php:742 64 | msgid "Block" 65 | msgstr "블록" 66 | 67 | #: inc/checkdatabasecommand.class.php:42 68 | msgid "Check database to detect inconsistencies." 69 | msgstr "" 70 | 71 | #: inc/toolbox.class.php:316 72 | msgid "Component items" 73 | msgstr "" 74 | 75 | #: templates/container_display_conditions.html.twig 76 | #: inc/containerdisplaycondition.class.php:153 77 | msgid "Condition to hide block" 78 | msgid_plural "Conditions to hide block" 79 | msgstr[0] "" 80 | 81 | #: inc/container.class.php:565 82 | msgid "" 83 | "Container name is too long for database (digits in name are replaced by " 84 | "characters, try to remove them)" 85 | msgstr "컨테이너 이름이 데이터베이스 용으로 너무 깁니다 (이름의 숫자는 문자로 대체되니, 제거해 보세요)" 86 | 87 | #: inc/checkdatabasecommand.class.php:80 88 | #, php-format 89 | msgid "Database contains orphaned data from %s improperly deleted field(s)." 90 | msgstr "" 91 | 92 | #: inc/checkdatabasecommand.class.php:79 93 | #, php-format 94 | msgid "" 95 | "Database was containing orphaned data from %s improperly deleted field(s)." 96 | msgstr "" 97 | 98 | #: inc/field.class.php:1309 99 | msgid "Date" 100 | msgstr "날짜" 101 | 102 | #: inc/field.class.php:1310 103 | msgid "Date & time" 104 | msgstr "날짜 & 시간" 105 | 106 | #: ajax/field_specific_fields.php:89 107 | msgid "Default value" 108 | msgstr "" 109 | 110 | #: ajax/field_specific_fields.php:116 111 | msgid "Default value will be configurable once field will be created." 112 | msgstr "" 113 | 114 | #: inc/field.class.php:1307 115 | msgid "Dropdown" 116 | msgstr "드롭다운" 117 | 118 | #: inc/checkdatabasecommand.class.php:72 119 | msgid "Everything is in order - no action needed." 120 | msgstr "" 121 | 122 | #: inc/container.class.php:53 inc/container.class.php:752 123 | msgid "Export to YAML" 124 | msgstr "YAML로 내보내기" 125 | 126 | #: templates/forms/status_override.html.twig inc/field.class.php:241 127 | msgid "Field" 128 | msgstr "항목" 129 | 130 | #: inc/field.class.php:257 inc/field.class.php:282 131 | msgid "" 132 | "Field name is too long for database (digits in name are replaced by " 133 | "characters, try to remove them)" 134 | msgstr "항목 이름이 데이터베이스 용으로 너무 깁니다 (이름의 숫자는 문자로 대체되니, 제거해 보세요)" 135 | 136 | #: inc/field.class.php:515 137 | msgid "Fields" 138 | msgstr "항목" 139 | 140 | #: inc/container.class.php:208 141 | msgid "Fix container names" 142 | msgstr "컨테이너 이름 수정" 143 | 144 | #: inc/toolbox.class.php:122 145 | msgid "Fix fields names" 146 | msgstr "항목 이름 수정" 147 | 148 | #: inc/field.class.php:1311 149 | msgid "GLPI item" 150 | msgstr "" 151 | 152 | #: inc/field.class.php:1301 153 | msgid "Header" 154 | msgstr "헤더" 155 | 156 | #: inc/container.class.php:995 157 | msgid "Insertion in the form (before save button)" 158 | msgstr "(저장 버튼 전에) 양식에 삽입" 159 | 160 | #: inc/container.class.php:996 161 | msgid "Insertion in the form of a specific tab (before save button)" 162 | msgstr "(저장 버튼 전에) 특정 탭의 양식에 삽입" 163 | 164 | #: inc/labeltranslation.class.php:192 165 | msgid "Label" 166 | msgstr "라벨" 167 | 168 | #: inc/labeltranslation.class.php:191 169 | msgid "Language" 170 | msgstr "언어" 171 | 172 | #: ajax/field_specific_fields.php:86 173 | msgid "Multiple dropdown" 174 | msgstr "" 175 | 176 | #: hook.php:55 hook.php:59 177 | msgid "MySQL tables installation" 178 | msgstr "MySQL 테이블 삽입" 179 | 180 | #: hook.php:121 181 | msgid "MySQL tables uninstallation" 182 | msgstr "MySQL 테이블 제거" 183 | 184 | #: inc/field.class.php:577 185 | msgid "No field for this block" 186 | msgstr "이 블럭에 대한 항목 없음" 187 | 188 | #: templates/status_overrides.html.twig 189 | msgid "No item found" 190 | msgstr "" 191 | 192 | #: inc/field.class.php:1305 193 | msgid "Number" 194 | msgstr "숫자" 195 | 196 | #: inc/statusoverride.class.php:88 197 | msgid "Override by status" 198 | msgstr "" 199 | 200 | #: templates/forms/status_override.html.twig inc/field.class.php:590 201 | #: inc/field.class.php:770 202 | msgid "Read only" 203 | msgstr "읽기 전용" 204 | 205 | #: inc/container.class.php:52 206 | msgid "Regenerate container files" 207 | msgstr "컨테이너 파일 재생성" 208 | 209 | #: inc/container.class.php:187 210 | msgid "Regenerate containers files" 211 | msgstr "" 212 | 213 | #: inc/command/regeneratefilescommand.class.php:41 214 | msgid "Regenerates containers files." 215 | msgstr "" 216 | 217 | #: inc/field.class.php:1304 218 | msgid "Rich Text" 219 | msgstr "" 220 | 221 | #: inc/checkdatabasecommand.class.php:96 222 | #, php-format 223 | msgid "Run \"%s\" to fix database inconsistencies." 224 | msgstr "" 225 | 226 | #: inc/container.class.php:1504 227 | msgid "Some URL fields contains invalid links" 228 | msgstr "일부 URL 항목에 잘못된 링크가 포함되었습니다" 229 | 230 | #: inc/container.class.php:1494 231 | msgid "Some mandatory fields are empty" 232 | msgstr "일부 필수 항목이 비었습니다" 233 | 234 | #: inc/container.class.php:1499 235 | msgid "Some numeric fields contains non numeric values" 236 | msgstr "일부 숫자 항목에 비 숫자 값이 포함되었습니다" 237 | 238 | #: templates/status_overrides.html.twig 239 | msgid "Status overrides" 240 | msgstr "" 241 | 242 | #: inc/container.class.php:846 243 | msgid "Tab" 244 | msgstr "탭" 245 | 246 | #: inc/field.class.php:1303 247 | msgid "Text (multiples lines)" 248 | msgstr "문구 (여러 줄)" 249 | 250 | #: inc/field.class.php:1302 251 | msgid "Text (single line)" 252 | msgstr "문구 (한 줄)" 253 | 254 | #: hook.php:109 255 | msgid "The plugin can't be uninstalled when the plugin is disabled" 256 | msgstr "플러그인 비활성화 시 플러그인을 삭제할 수 없습니다" 257 | 258 | #: inc/checkdatabasecommand.class.php:44 259 | msgid "This command will check database to detect following inconsistencies:" 260 | msgstr "" 261 | 262 | #: inc/command/regeneratefilescommand.class.php:43 263 | msgid "" 264 | "This command will clean up all files generated by the plugin and regenerate " 265 | "them." 266 | msgstr "" 267 | 268 | #: inc/field.class.php:1306 269 | msgid "URL" 270 | msgstr "URL" 271 | 272 | #: inc/container.class.php:328 273 | msgid "Updating generated containers files" 274 | msgstr "생성된 컨테이너 파일 갱신" 275 | 276 | #: inc/dropdown.class.php:78 277 | msgid "Updating generated dropdown files" 278 | msgstr "생성된 드롭다운 파일 갱신" 279 | 280 | #: inc/checkdatabasecommand.class.php:57 281 | msgid "Use this option to actually fix database" 282 | msgstr "" 283 | 284 | #: inc/field.class.php:1308 285 | msgid "Yes/No" 286 | msgstr "예/아니오" 287 | 288 | #: inc/container.class.php:514 289 | msgid "You cannot add block without associated element type" 290 | msgstr "관련된 요소 형식이 없으면 추가할 수 없습니다" 291 | 292 | #: inc/container.class.php:549 293 | msgid "" 294 | "You cannot add several blocks with type 'Insertion in the form of a specific" 295 | " tab' on same object tab" 296 | msgstr "동일한 객체 탭에 '특정 탭의 양식에 삽입' 유형이 있는 몇개의 블록을 추가할 수 없습니다." 297 | 298 | #: inc/container.class.php:534 299 | msgid "" 300 | "You cannot add several blocks with type 'Insertion in the form' on same " 301 | "object" 302 | msgstr "동일한 객체에 '양식에 삽입' 유형이 있는 몇개의 블록을 추가할 수 없습니다." 303 | 304 | #: inc/container.class.php:579 305 | msgid "You cannot add several blocs with identical name on same object" 306 | msgstr "동일한 객체에 동일한 이름을 가진 몇개의 블록을 추가할 수 없습니다." 307 | 308 | #: inc/containerdisplaycondition.class.php:493 309 | #: inc/containerdisplaycondition.class.php:508 310 | msgid "You must specify an item type, search option and condition." 311 | msgstr "" 312 | 313 | #: inc/containerdisplaycondition.class.php:103 314 | #: inc/containerdisplaycondition.class.php:137 315 | msgid "not under" 316 | msgstr "" 317 | 318 | #: inc/containerdisplaycondition.class.php:109 319 | #: inc/containerdisplaycondition.class.php:131 320 | msgid "regular expression matches" 321 | msgstr "" 322 | 323 | #: templates/fields.html.twig 324 | msgid "show" 325 | msgstr "표시" 326 | 327 | #: inc/containerdisplaycondition.class.php:102 328 | #: inc/containerdisplaycondition.class.php:134 329 | msgid "under" 330 | msgstr "" 331 | -------------------------------------------------------------------------------- /locales/pl_PL.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/pl_PL.mo -------------------------------------------------------------------------------- /locales/pt_BR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/pt_BR.mo -------------------------------------------------------------------------------- /locales/pt_PT.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/pt_PT.mo -------------------------------------------------------------------------------- /locales/ro_RO.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/ro_RO.mo -------------------------------------------------------------------------------- /locales/ru_RU.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/ru_RU.mo -------------------------------------------------------------------------------- /locales/sk_SK.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/sk_SK.mo -------------------------------------------------------------------------------- /locales/tr_TR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/tr_TR.mo -------------------------------------------------------------------------------- /locales/uk_UA.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/uk_UA.mo -------------------------------------------------------------------------------- /locales/zh_CN.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/locales/zh_CN.mo -------------------------------------------------------------------------------- /locales/zh_CN.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # 5 | # Translators: 6 | # liAnGjiA , 2018 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: GLPI Plugin - Fields\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2023-10-04 14:23+0000\n" 12 | "PO-Revision-Date: 2015-09-18 09:34+0000\n" 13 | "Last-Translator: liAnGjiA , 2018\n" 14 | "Language-Team: Chinese (China) (http://app.transifex.com/teclib/glpi-plugin-plugin-fields/language/zh_CN/)\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Language: zh_CN\n" 19 | "Plural-Forms: nplurals=1; plural=0;\n" 20 | 21 | #: inc/checkdatabasecommand.class.php:47 22 | #, php-format 23 | msgid "" 24 | "- some deleted fields may still be present in database (bug introduced in " 25 | "version %s and fixed in version %s)" 26 | msgstr "" 27 | 28 | #: inc/checkdatabasecommand.class.php:86 29 | #, php-format 30 | msgid "-> \"%s.%s\" has been deleted." 31 | msgstr "" 32 | 33 | #: inc/checkdatabasecommand.class.php:87 34 | #, php-format 35 | msgid "-> \"%s.%s\" should be deleted." 36 | msgstr "" 37 | 38 | #: inc/field.class.php:573 39 | msgid "Add a new field" 40 | msgstr "添加新字段" 41 | 42 | #: templates/container_display_conditions.html.twig 43 | msgid "Add condition to hide block" 44 | msgstr "" 45 | 46 | #: templates/status_overrides.html.twig 47 | msgid "Add new status override" 48 | msgstr "" 49 | 50 | #: inc/container.class.php:994 51 | msgid "Add tab" 52 | msgstr "添加标签" 53 | 54 | #: inc/menu.class.php:37 front/container.php:34 front/container.form.php:63 55 | #: setup.php:200 56 | msgid "Additional fields" 57 | msgstr "附加字段" 58 | 59 | #: ajax/field_specific_fields.php:53 60 | msgid "Allowed values" 61 | msgstr "" 62 | 63 | #: inc/container.class.php:742 64 | msgid "Block" 65 | msgstr "区域" 66 | 67 | #: inc/checkdatabasecommand.class.php:42 68 | msgid "Check database to detect inconsistencies." 69 | msgstr "" 70 | 71 | #: inc/toolbox.class.php:316 72 | msgid "Component items" 73 | msgstr "" 74 | 75 | #: templates/container_display_conditions.html.twig 76 | #: inc/containerdisplaycondition.class.php:153 77 | msgid "Condition to hide block" 78 | msgid_plural "Conditions to hide block" 79 | msgstr[0] "" 80 | 81 | #: inc/container.class.php:565 82 | msgid "" 83 | "Container name is too long for database (digits in name are replaced by " 84 | "characters, try to remove them)" 85 | msgstr "" 86 | 87 | #: inc/checkdatabasecommand.class.php:80 88 | #, php-format 89 | msgid "Database contains orphaned data from %s improperly deleted field(s)." 90 | msgstr "" 91 | 92 | #: inc/checkdatabasecommand.class.php:79 93 | #, php-format 94 | msgid "" 95 | "Database was containing orphaned data from %s improperly deleted field(s)." 96 | msgstr "" 97 | 98 | #: inc/field.class.php:1309 99 | msgid "Date" 100 | msgstr "日期" 101 | 102 | #: inc/field.class.php:1310 103 | msgid "Date & time" 104 | msgstr "时间&日期" 105 | 106 | #: ajax/field_specific_fields.php:89 107 | msgid "Default value" 108 | msgstr "" 109 | 110 | #: ajax/field_specific_fields.php:116 111 | msgid "Default value will be configurable once field will be created." 112 | msgstr "" 113 | 114 | #: inc/field.class.php:1307 115 | msgid "Dropdown" 116 | msgstr "拖动" 117 | 118 | #: inc/checkdatabasecommand.class.php:72 119 | msgid "Everything is in order - no action needed." 120 | msgstr "" 121 | 122 | #: inc/container.class.php:53 inc/container.class.php:752 123 | msgid "Export to YAML" 124 | msgstr "" 125 | 126 | #: templates/forms/status_override.html.twig inc/field.class.php:241 127 | msgid "Field" 128 | msgstr "字段" 129 | 130 | #: inc/field.class.php:257 inc/field.class.php:282 131 | msgid "" 132 | "Field name is too long for database (digits in name are replaced by " 133 | "characters, try to remove them)" 134 | msgstr "" 135 | 136 | #: inc/field.class.php:515 137 | msgid "Fields" 138 | msgstr "字段" 139 | 140 | #: inc/container.class.php:208 141 | msgid "Fix container names" 142 | msgstr "" 143 | 144 | #: inc/toolbox.class.php:122 145 | msgid "Fix fields names" 146 | msgstr "" 147 | 148 | #: inc/field.class.php:1311 149 | msgid "GLPI item" 150 | msgstr "" 151 | 152 | #: inc/field.class.php:1301 153 | msgid "Header" 154 | msgstr "头部" 155 | 156 | #: inc/container.class.php:995 157 | msgid "Insertion in the form (before save button)" 158 | msgstr "在窗体中插入(保存按钮前)" 159 | 160 | #: inc/container.class.php:996 161 | msgid "Insertion in the form of a specific tab (before save button)" 162 | msgstr "以特定选项卡的形式插入(保存按钮之前)" 163 | 164 | #: inc/labeltranslation.class.php:192 165 | msgid "Label" 166 | msgstr "标签" 167 | 168 | #: inc/labeltranslation.class.php:191 169 | msgid "Language" 170 | msgstr "语言" 171 | 172 | #: ajax/field_specific_fields.php:86 173 | msgid "Multiple dropdown" 174 | msgstr "" 175 | 176 | #: hook.php:55 hook.php:59 177 | msgid "MySQL tables installation" 178 | msgstr "安装MySQL数据表" 179 | 180 | #: hook.php:121 181 | msgid "MySQL tables uninstallation" 182 | msgstr "卸载MySQL数据表" 183 | 184 | #: inc/field.class.php:577 185 | msgid "No field for this block" 186 | msgstr "此区域无字段" 187 | 188 | #: templates/status_overrides.html.twig 189 | msgid "No item found" 190 | msgstr "" 191 | 192 | #: inc/field.class.php:1305 193 | msgid "Number" 194 | msgstr "整数" 195 | 196 | #: inc/statusoverride.class.php:88 197 | msgid "Override by status" 198 | msgstr "" 199 | 200 | #: templates/forms/status_override.html.twig inc/field.class.php:590 201 | #: inc/field.class.php:770 202 | msgid "Read only" 203 | msgstr "只读" 204 | 205 | #: inc/container.class.php:52 206 | msgid "Regenerate container files" 207 | msgstr "生成容器文件" 208 | 209 | #: inc/container.class.php:187 210 | msgid "Regenerate containers files" 211 | msgstr "" 212 | 213 | #: inc/command/regeneratefilescommand.class.php:41 214 | msgid "Regenerates containers files." 215 | msgstr "" 216 | 217 | #: inc/field.class.php:1304 218 | msgid "Rich Text" 219 | msgstr "" 220 | 221 | #: inc/checkdatabasecommand.class.php:96 222 | #, php-format 223 | msgid "Run \"%s\" to fix database inconsistencies." 224 | msgstr "" 225 | 226 | #: inc/container.class.php:1504 227 | msgid "Some URL fields contains invalid links" 228 | msgstr "有些URL字段包含无效链接" 229 | 230 | #: inc/container.class.php:1494 231 | msgid "Some mandatory fields are empty" 232 | msgstr "一些强制字段是空的。" 233 | 234 | #: inc/container.class.php:1499 235 | msgid "Some numeric fields contains non numeric values" 236 | msgstr "一些数值字段包含非数值" 237 | 238 | #: templates/status_overrides.html.twig 239 | msgid "Status overrides" 240 | msgstr "" 241 | 242 | #: inc/container.class.php:846 243 | msgid "Tab" 244 | msgstr "标签" 245 | 246 | #: inc/field.class.php:1303 247 | msgid "Text (multiples lines)" 248 | msgstr "文本(多行)" 249 | 250 | #: inc/field.class.php:1302 251 | msgid "Text (single line)" 252 | msgstr "文本(单行)" 253 | 254 | #: hook.php:109 255 | msgid "The plugin can't be uninstalled when the plugin is disabled" 256 | msgstr "插件处于禁用状态时无法卸载" 257 | 258 | #: inc/checkdatabasecommand.class.php:44 259 | msgid "This command will check database to detect following inconsistencies:" 260 | msgstr "" 261 | 262 | #: inc/command/regeneratefilescommand.class.php:43 263 | msgid "" 264 | "This command will clean up all files generated by the plugin and regenerate " 265 | "them." 266 | msgstr "" 267 | 268 | #: inc/field.class.php:1306 269 | msgid "URL" 270 | msgstr "网址" 271 | 272 | #: inc/container.class.php:328 273 | msgid "Updating generated containers files" 274 | msgstr "刷新生成容器文件" 275 | 276 | #: inc/dropdown.class.php:78 277 | msgid "Updating generated dropdown files" 278 | msgstr "更新生成下拉文件" 279 | 280 | #: inc/checkdatabasecommand.class.php:57 281 | msgid "Use this option to actually fix database" 282 | msgstr "" 283 | 284 | #: inc/field.class.php:1308 285 | msgid "Yes/No" 286 | msgstr "是/否" 287 | 288 | #: inc/container.class.php:514 289 | msgid "You cannot add block without associated element type" 290 | msgstr "您不能添加没有关联元素类型的块" 291 | 292 | #: inc/container.class.php:549 293 | msgid "" 294 | "You cannot add several blocks with type 'Insertion in the form of a specific" 295 | " tab' on same object tab" 296 | msgstr "不能在同一个对象选项卡上以特定选项卡的形式使用“表单中插入特殊标签”类型添加几个块" 297 | 298 | #: inc/container.class.php:534 299 | msgid "" 300 | "You cannot add several blocks with type 'Insertion in the form' on same " 301 | "object" 302 | msgstr "不能在同一个对象上添加几个带有'表单中插入'类型的块" 303 | 304 | #: inc/container.class.php:579 305 | msgid "You cannot add several blocs with identical name on same object" 306 | msgstr "不能在同一对象上添加名称相同的多个块" 307 | 308 | #: inc/containerdisplaycondition.class.php:493 309 | #: inc/containerdisplaycondition.class.php:508 310 | msgid "You must specify an item type, search option and condition." 311 | msgstr "" 312 | 313 | #: inc/containerdisplaycondition.class.php:103 314 | #: inc/containerdisplaycondition.class.php:137 315 | msgid "not under" 316 | msgstr "" 317 | 318 | #: inc/containerdisplaycondition.class.php:109 319 | #: inc/containerdisplaycondition.class.php:131 320 | msgid "regular expression matches" 321 | msgstr "" 322 | 323 | #: templates/fields.html.twig 324 | msgid "show" 325 | msgstr "显示" 326 | 327 | #: inc/containerdisplaycondition.class.php:102 328 | #: inc/containerdisplaycondition.class.php:134 329 | msgid "under" 330 | msgstr "" 331 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | parallel: 3 | maximumNumberOfProcesses: 2 4 | level: 5 5 | bootstrapFiles: 6 | - ../../inc/based_config.php 7 | paths: 8 | - inc 9 | - front 10 | - ajax 11 | - hook.php 12 | - setup.php 13 | scanDirectories: 14 | - ../../inc 15 | - ../../src 16 | stubFiles: 17 | - ../../stubs/glpi_constants.php 18 | rules: 19 | - GlpiProject\Tools\PHPStan\Rules\GlobalVarTypeRule 20 | -------------------------------------------------------------------------------- /pics/container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/pics/container.png -------------------------------------------------------------------------------- /pics/field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pluginsGLPI/fields/b7dfd445b085f17a9393ced74c0cc16526d38db8/pics/field.png -------------------------------------------------------------------------------- /templates/container.class.tpl: -------------------------------------------------------------------------------- 1 | getTable(); 16 | $migration = new PluginFieldsMigration(0); 17 | 18 | // create Table 19 | if (!$DB->tableExists($table)) { 20 | $query = "CREATE TABLE IF NOT EXISTS `$table` ( 21 | `id` INT {$default_key_sign} NOT NULL auto_increment, 22 | `items_id` INT {$default_key_sign} NOT NULL, 23 | `itemtype` VARCHAR(255) DEFAULT '%%ITEMTYPE%%', 24 | `plugin_fields_containers_id` INT {$default_key_sign} NOT NULL DEFAULT '%%CONTAINER%%', 25 | PRIMARY KEY (`id`), 26 | UNIQUE INDEX `itemtype_item_container` 27 | (`itemtype`, `items_id`, `plugin_fields_containers_id`) 28 | ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; 29 | $DB->query($query) or die ($DB->error()); 30 | } else { 31 | // 1.15.4 32 | // fix nullable state for 'glpi_item' field 33 | $result = $DB->query("SHOW COLUMNS FROM `$table`"); 34 | if ($result && $DB->numrows($result) > 0) { 35 | $changed = false; 36 | while ($data = $DB->fetchAssoc($result)) { 37 | if (str_starts_with($data['Field'], 'itemtype_') && $data['Null'] !== 'YES') { 38 | $migration->changeField($table, $data['Field'], $data['Field'], "varchar(100) DEFAULT NULL"); 39 | $changed = true; 40 | } 41 | } 42 | if ($changed) { 43 | $migration->executeMigration(); 44 | } 45 | } 46 | } 47 | 48 | /** 49 | * Adds the 'entities_id' field to the database table and migrates existing data. 50 | * 51 | * This block ensures that the 'entities_id' field is created and populated if it 52 | * associated item type requires entity assignment 53 | */ 54 | if (getItemForItemtype("%%ITEMTYPE%%")->isEntityAssign() && !$DB->fieldExists($table, 'entities_id')) { 55 | $migration->addField($table, 'entities_id', 'fkey', ['after' => 'plugin_fields_containers_id']); 56 | $migration->addKey($table, 'entities_id'); 57 | $migration->executeMigration(); 58 | 59 | // migrate data 60 | $query = $DB->buildUpdate( 61 | $table, 62 | ['entities_id' => new QueryParam()], 63 | ['id' => new QueryParam()] 64 | ); 65 | $stmt = $DB->prepare($query); 66 | 67 | //load all entries 68 | $data = $DB->request( 69 | [ 70 | 'SELECT' => '*', 71 | 'FROM' => $table, 72 | ] 73 | ); 74 | 75 | foreach ($data as $fields) { 76 | //load related item 77 | $related_item = $DB->request( 78 | [ 79 | 'SELECT' => '*', 80 | 'FROM' => getTableForItemType($fields['itemtype']), 81 | 'WHERE' => [ 82 | 'id' => $fields['items_id'], 83 | ] 84 | ] 85 | )->current(); 86 | 87 | if ($related_item === null) { 88 | continue; 89 | } 90 | 91 | //update if needed 92 | if ($fields['entities_id'] != $related_item['entities_id']) { 93 | $stmt->bind_param( 94 | 'ii', 95 | $related_item['entities_id'], 96 | $fields['id'] 97 | ); 98 | $stmt->execute(); 99 | } 100 | } 101 | } 102 | 103 | /** 104 | * Adds the 'is_recursive' field to the database table and migrates existing data. 105 | * 106 | * This block ensures that the 'is_recursive' field is created and populated if it 107 | * associated item type requires recursive assignment 108 | */ 109 | if ( 110 | getItemForItemtype("%%ITEMTYPE%%")->maybeRecursive() 111 | && !$DB->fieldExists($table, 'is_recursive') 112 | && $DB->fieldExists($table, 'entities_id')) { 113 | $migration->addField($table, 'is_recursive', 'bool', ['after' => 'entities_id']); 114 | $migration->addKey($table, 'is_recursive'); 115 | $migration->executeMigration(); 116 | 117 | //migrate data 118 | $query = $DB->buildUpdate( 119 | $table, 120 | ['is_recursive' => new QueryParam()], 121 | ['id' => new QueryParam()] 122 | ); 123 | $stmt = $DB->prepare($query); 124 | 125 | //load all entries 126 | $data = $DB->request( 127 | [ 128 | 'SELECT' => '*', 129 | 'FROM' => $table, 130 | ] 131 | ); 132 | 133 | foreach ($data as $fields) { 134 | //load related item 135 | $related_item = $DB->request( 136 | [ 137 | 'SELECT' => '*', 138 | 'FROM' => getTableForItemType($fields['itemtype']), 139 | 'WHERE' => [ 140 | 'id' => $fields['items_id'], 141 | ] 142 | ] 143 | )->current(); 144 | 145 | if ($related_item === null) { 146 | continue; 147 | } 148 | 149 | //update if needed 150 | if ($fields['is_recursive'] != $related_item['is_recursive']) { 151 | $stmt->bind_param( 152 | 'ii', 153 | $related_item['is_recursive'], 154 | $fields['id'] 155 | ); 156 | $stmt->execute(); 157 | } 158 | } 159 | } 160 | } 161 | 162 | static function uninstall() { 163 | global $DB; 164 | 165 | $obj = new self(); 166 | return $DB->query("DROP TABLE IF EXISTS `".$obj->getTable()."`"); 167 | } 168 | 169 | static function addField($fieldname, $type, array $options) { 170 | $migration = new PluginFieldsMigration(0); 171 | 172 | $sql_fields = PluginFieldsMigration::getSQLFields($fieldname, $type, $options); 173 | foreach ($sql_fields as $sql_field_name => $sql_field_type) { 174 | $migration->addField(self::getTable(), $sql_field_name, $sql_field_type); 175 | } 176 | 177 | $migration->migrationOneTable(self::getTable()); 178 | } 179 | 180 | static function removeField($fieldname, $type) { 181 | $migration = new PluginFieldsMigration(0); 182 | 183 | $sql_fields = PluginFieldsMigration::getSQLFields($fieldname, $type); 184 | foreach (array_keys($sql_fields) as $sql_field_name) { 185 | $migration->dropField(self::getTable(), $sql_field_name); 186 | } 187 | 188 | $migration->migrationOneTable(self::getTable()); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /templates/container_display_conditions.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # ------------------------------------------------------------------------- 3 | # Fields plugin for GLPI 4 | # ------------------------------------------------------------------------- 5 | # 6 | # LICENSE 7 | # 8 | # This file is part of Fields. 9 | # 10 | # Fields is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # Fields is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with Fields. If not, see . 22 | # ------------------------------------------------------------------------- 23 | # @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | # @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | # @link https://github.com/pluginsGLPI/fields 26 | # ------------------------------------------------------------------------- 27 | #} 28 | 29 | {% import 'components/form/fields_macros.html.twig' as fields %} 30 | {% set rand = random() %} 31 | 32 |
33 |
34 |
35 | {{ __('The engine is used for hide block when main object meets condition') }} 36 |
37 |
38 |
39 | {% if has_fields %} 40 | 48 | {% endif %} 49 |
50 | 51 | {{ fields.largeTitle(_n('Condition to hide block', 'Conditions to hide block', get_plural_number(), 'fields'), '', false) }} 52 |
53 |
54 |
55 |
56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {% if container_display_conditions|length > 0 %} 69 | {% for container_display_condition in container_display_conditions %} 70 | 71 | 72 | 73 | 74 | 75 | 92 | 93 | {% endfor %} 94 | {% else %} 95 | 96 | 97 | 98 | {% endif %} 99 | 100 |
{{ __('Item type') }}{{ __('Field') }}{{ __('Condition') }}{{ __('Value') }}
{{ container_display_condition.itemtype|itemtype_name }}{{ call('PluginFieldsContainerDisplayCondition::getFieldName', [container_display_condition.search_option, container_display_condition.itemtype]) }}{{ call('PluginFieldsContainerDisplayCondition::getConditionName', [container_display_condition.condition]) }}{{ call('PluginFieldsContainerDisplayCondition::getRawValue', [container_display_condition.search_option, container_display_condition.itemtype, container_display_condition.value]) }} 76 | 77 | 78 | 79 | 84 | 89 | 90 | 91 |
{{ __('No item found') }}
101 |
{# .row #} 102 |
{# .row #} 103 |
{# .flex-row #} 104 |
105 |
{# .card-body #} 106 | 148 |
149 | -------------------------------------------------------------------------------- /templates/dropdown.class.tpl: -------------------------------------------------------------------------------- 1 | PluginFieldsField::getType(), 10 | "id" => "%%FIELDID%%", 11 | "label" => "%%LABEL%%" 12 | ]; 13 | $label = PluginFieldsLabelTranslation::getLabelFor($item); 14 | return $label; 15 | } 16 | 17 | static function install() { 18 | global $DB; 19 | 20 | $default_charset = DBConnection::getDefaultCharset(); 21 | $default_collation = DBConnection::getDefaultCollation(); 22 | $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); 23 | 24 | $obj = new self(); 25 | $table = $obj->getTable(); 26 | 27 | if (!$DB->tableExists($table)) { 28 | $query = "CREATE TABLE IF NOT EXISTS `$table` ( 29 | `id` INT {$default_key_sign} NOT NULL auto_increment, 30 | `name` VARCHAR(255) DEFAULT NULL, 31 | `completename` TEXT DEFAULT NULL, 32 | `comment` TEXT DEFAULT NULL, 33 | `plugin_fields_%%FIELDNAME%%dropdowns_id` INT {$default_key_sign} DEFAULT NULL, 34 | `level` INT DEFAULT NULL, 35 | `ancestors_cache` TEXT DEFAULT NULL, 36 | `sons_cache` TEXT DEFAULT NULL, 37 | `entities_id` INT {$default_key_sign} NOT NULL DEFAULT '0', 38 | `is_recursive` TINYINT NOT NULL DEFAULT '0', 39 | PRIMARY KEY (`id`), 40 | KEY `entities_id` (`entities_id`), 41 | KEY `is_recursive` (`is_recursive`), 42 | KEY `plugin_fields_%%FIELDNAME%%dropdowns_id` 43 | (`plugin_fields_%%FIELDNAME%%dropdowns_id`) 44 | ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; 45 | $DB->query($query) or die ($DB->error()); 46 | } 47 | } 48 | 49 | static function uninstall() { 50 | global $DB; 51 | 52 | $obj = new self(); 53 | return $DB->query("DROP TABLE IF EXISTS `".$obj->getTable()."`"); 54 | } 55 | 56 | /** 57 | * Get the search page URL for the current classe 58 | * 59 | * @param $full path or relative one (true by default) 60 | **/ 61 | static function getTabsURL($full=true) { 62 | $url = Toolbox::getItemTypeTabsURL('PluginFieldsCommonDropdown', $full); 63 | $plug = isPluginItemType(get_called_class()); 64 | $url .= '?ddtype=' . strtolower($plug['class']); 65 | return $url; 66 | } 67 | 68 | /** 69 | * Get the search page URL for the current class 70 | * 71 | * @param $full path or relative one (true by default) 72 | **/ 73 | static function getSearchURL($full=true) { 74 | $url = Toolbox::getItemTypeSearchURL('PluginFieldsCommonDropdown', $full); 75 | $plug = isPluginItemType(get_called_class()); 76 | $url .= '?ddtype=' . strtolower($plug['class']); 77 | return $url; 78 | } 79 | 80 | /** 81 | * Get the form page URL for the current class 82 | * 83 | * @param $full path or relative one (true by default) 84 | **/ 85 | static function getFormURL($full=true) { 86 | $url = Toolbox::getItemTypeFormURL('PluginFieldsCommonDropdown', $full); 87 | $plug = isPluginItemType(get_called_class()); 88 | $url .= '?ddtype=' . strtolower($plug['class']); 89 | return $url; 90 | } 91 | 92 | /** 93 | * Get the form page URL for the current class and point to a specific ID 94 | * 95 | * @param $id (default 0) 96 | * @param $full path or relative one (true by default) 97 | * 98 | * @since version 0.90 99 | **/ 100 | static function getFormURLWithID($id=0, $full=true) { 101 | 102 | $link = self::getFormURL($full); 103 | $link .= '&id=' . $id; 104 | return $link; 105 | } 106 | 107 | /** 108 | * Get default values to search engine to override 109 | **/ 110 | static function getDefaultSearchRequest() { 111 | $plug = isPluginItemType(get_called_class()); 112 | $search = ['addhidden' => ['ddtype' => strtolower($plug['class'])]]; 113 | return $search; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /templates/dropdown.form.tpl: -------------------------------------------------------------------------------- 1 | $_GET['ddtype'] 6 | ]; 7 | include GLPI_ROOT . "/front/dropdown.common.form.php"; 8 | -------------------------------------------------------------------------------- /templates/dropdown.tpl: -------------------------------------------------------------------------------- 1 | . 22 | # ------------------------------------------------------------------------- 23 | # @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | # @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | # @link https://github.com/pluginsGLPI/fields 26 | # ------------------------------------------------------------------------- 27 | #} 28 | 29 | {% import 'components/form/fields_macros.html.twig' as macros %} 30 | 31 | {% set already_wrapped = item is instanceof('CommonITILObject') and container.fields['type'] == 'dom' %} 32 | 33 | {% if not already_wrapped %} 34 |
35 |
36 |
37 |
38 |
39 | {% endif %} 40 | 41 | {% for field in fields %} 42 | 43 | {% set type = field['type'] %} 44 | {% set name = field['name'] %} 45 | {% set label = field['label'] %} 46 | {% set value = item.input[name] ?: field['value'] %} 47 | {% set readonly = field['is_readonly'] %} 48 | {% set rand = random() %} 49 | 50 | {% set field_options = field_options|merge({ 51 | 'readonly': readonly or not canedit, 52 | 'required': field['mandatory'], 53 | 'full_width': already_wrapped 54 | }) %} 55 | 56 | {% if type == 'header' %} 57 | {{ macros.largeTitle(label) }} 58 | 59 | {% elseif type == 'text' %} 60 | {{ macros.textField(name, value, label, field_options) }} 61 | 62 | {% elseif type == 'number' %} 63 | {{ macros.numberField(name, value, label, field_options|merge({step: 'any', min: ''})) }} 64 | 65 | {% elseif type == 'url' %} 66 | {% set ext_link %} 67 | {% if value|length %} 68 | 69 | 70 | {{ __('show', 'fields') }} 71 | 72 | {% endif %} 73 | {% endset %} 74 | {{ macros.textField(name, value, label, field_options|merge({ 75 | 'type': 'url', 76 | 'add_field_html': ext_link 77 | })) }} 78 | 79 | {% elseif type == 'textarea' %} 80 | {{ macros.textareaField(name, value, label, field_options) }} 81 | 82 | {% elseif type == 'richtext' %} 83 | {{ macros.textareaField(name, value, label, field_options|merge({ 84 | 'enable_richtext': true, 85 | 'field_class': 'col-12', 86 | 'label_class': '', 87 | 'input_class': '', 88 | 'align_label_right': false, 89 | 'mb': 'm-2' 90 | })) }} 91 | 92 | {% elseif type == 'yesno' %} 93 | {{ macros.dropdownYesNo(name, value, label, field_options) }} 94 | 95 | {% elseif type == 'date' %} 96 | {{ macros.dateField(name, value, label, field_options) }} 97 | 98 | {% elseif type == 'datetime' %} 99 | {{ macros.datetimeField(name, value, label, field_options) }} 100 | 101 | {% elseif type == 'dropdown' %} 102 | {% set dropdown_options = {'entity': item.getEntityID()} %} 103 | {% if field['multiple'] %} 104 | {% set dropdown_options = dropdown_options|merge({'multiple': true}) %} 105 | {% endif %} 106 | {% if item.isRecursive() %} 107 | {% set dropdown_options = dropdown_options|merge({'entity_sons': true}) %} 108 | {% endif %} 109 | {% if "dropdowns_id" in name %} 110 | {% set dropdown_itemtype = call("getItemtypeForForeignKeyField", [name]) %} 111 | {% else %} 112 | {% set dropdown_itemtype = call("PluginFieldsDropdown::getClassname", [name]) %} 113 | {% endif %} 114 | {% set name_fk = call("getForeignKeyFieldForItemType", [dropdown_itemtype]) %} 115 | {{ macros.dropdownField(dropdown_itemtype, name_fk, value, label, field_options|merge(dropdown_options)) }} 116 | 117 | {% elseif type matches '/^dropdown-.+/i' %} 118 | {% if not massiveaction %} 119 | {% set dropdown_options = {'condition': field['dropdown_condition'], 'entity': item.getEntityID()} %} 120 | {% if field['dropdown_class'] == 'User' %} 121 | {% set dropdown_options = dropdown_options|merge({'entity': -1, 'right': 'all'}) %} 122 | {% elseif field['dropdown_class'] == 'Entity' or item.isRecursive() %} 123 | {% set dropdown_options = dropdown_options|merge({'entity_sons': true}) %} 124 | {% endif %} 125 | {% if field['multiple'] %} 126 | {% set dropdown_options = dropdown_options|merge({'multiple': true}) %} 127 | {% endif %} 128 | {{ macros.dropdownField(field['dropdown_class'], name, value, label, field_options|merge(dropdown_options)) }} 129 | {% endif %} 130 | 131 | {% elseif type == 'glpi_item' %} 132 | {% if not massiveaction %} 133 | {% set itemtype_prefix = 'itemtype_' %} 134 | {% set items_id_prefix = 'items_id_' %} 135 | 136 | {% if container.fields['type'] == 'tab' %} 137 | {# start new row for glpi object #} 138 |
139 | {% endif %} 140 | 141 | {{ macros.dropdownArrayField(itemtype_prefix ~ name, value.itemtype, field['allowed_values'], label, field_options|merge({ 142 | 'rand': rand, 143 | 'display_emptychoice': true, 144 | })) }} 145 |
146 | {% do call('Ajax::updateItemOnSelectEvent', 147 | [ 148 | 'dropdown_' ~ itemtype_prefix ~ name ~ rand, 149 | 'results_items_id' ~ (rand), 150 | config('root_doc') ~ '/ajax/dropdownAllItems.php', 151 | { 152 | 'idtable' : '__VALUE__', 153 | 'name' : items_id_prefix ~ name, 154 | 'entity_restrict' : item.getEntityID(), 155 | 'dom_name' : items_id_prefix ~ name, 156 | 'display_emptychoice' : false, 157 | 'action' : 'get_items_from_itemtype', 158 | 'dom_rand' : rand, 159 | 'width' : '100%', 160 | } 161 | ]) %} 162 | 163 | {# fake label for DOM disposition #} 164 | 166 | 167 |
168 | 169 | {% if value.itemtype != '' %} 170 | {{ macros.dropdownField(value.itemtype, items_id_prefix ~ name, value.items_id, ' ', field_options|merge({ 171 | 'entity': value.itemtype == 'User' ? -1 : item.getEntityID(), 172 | 'rand': rand, 173 | 'right': 'all', 174 | 'displaywith': ['otherserial', 'serial'], 175 | 'display_emptychoice' : false, 176 | 'no_label': true 177 | })) }} 178 | {% endif %} 179 | 180 |
181 |
182 | {% endif %} 183 | {% endif %} 184 | {% endfor %} 185 | 186 | {% if not already_wrapped %} 187 |
188 |
189 |
190 |
191 |
192 | {% endif %} 193 | -------------------------------------------------------------------------------- /templates/forms/container_display_condition.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # ------------------------------------------------------------------------- 3 | # Fields plugin for GLPI 4 | # ------------------------------------------------------------------------- 5 | # 6 | # LICENSE 7 | # 8 | # This file is part of Fields. 9 | # 10 | # Fields is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # Fields is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with Fields. If not, see . 22 | # ------------------------------------------------------------------------- 23 | # @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | # @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | # @link https://github.com/pluginsGLPI/fields 26 | # ------------------------------------------------------------------------- 27 | #} 28 | 29 | {% import 'components/form/fields_macros.html.twig' as fields %} 30 | {% set rand = random() %} 31 | 32 |
33 | 34 |
35 |
36 |
37 |
38 |
39 | {{ fields.dropdownArrayField('itemtype', container_display_condition.fields['itemtype']|default(null), container_itemtypes, __('Item type'), {'rand': rand, 'display_emptychoice': true}) }} 40 | {% do call('Ajax::updateItemOnSelectEvent', 41 | [ 42 | 'dropdown_itemtype' ~ rand, 43 | 'results_fields', 44 | get_plugin_web_dir('fields') ~ '/ajax/container_display_condition.php', 45 | { 46 | 'itemtype': '__VALUE__', 47 | 'action' : 'get_itemtype_so', 48 | } 49 | ]) %} 50 |
51 | {% if not container_display_condition.isNewItem() %} 52 | {{ fields.dropdownArrayField('search_option', container_display_condition.fields['search_option']|default(null), search_options, '', {'no_label': true, 'rand': rand, 'display_emptychoice': false}) }} 53 | {% do call('Ajax::updateItemOnSelectEvent', 54 | [ 55 | 'dropdown_search_option' ~ rand, 56 | 'results_condition', 57 | get_plugin_web_dir('fields') ~ '/ajax/container_display_condition.php', 58 | { 59 | 'search_option_id' : '__VALUE__', 60 | 'itemtype' : container_display_condition.fields['itemtype'], 61 | 'action' : 'get_condition_switch_so' 62 | } 63 | ]) %} 64 | {% endif %} 65 |
66 | 67 |
68 | {% if not container_display_condition.isNewItem() %} 69 | {{ call( 70 | 'PluginFieldsContainerDisplayCondition::showSearchOptionCondition', 71 | [ 72 | container_display_condition.fields['search_option'], 73 | container_display_condition.fields['itemtype'], 74 | container_display_condition.fields['condition'], 75 | container_display_condition.fields['value'] 76 | ] 77 | )|raw }} 78 | {% endif %} 79 |
80 | 81 |
{# .row #} 82 |
83 | {% if not container_display_condition.isNewItem() %} 84 | 85 | 89 | {% else %} 90 | 94 | {% endif %} 95 | 96 |
97 |
{# .row #} 98 |
{# .flex-row #} 99 |
100 |
{# .card-body #} 101 |
102 | -------------------------------------------------------------------------------- /templates/forms/container_display_condition_so_condition.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # ------------------------------------------------------------------------- 3 | # Fields plugin for GLPI 4 | # ------------------------------------------------------------------------- 5 | # 6 | # LICENSE 7 | # 8 | # This file is part of Fields. 9 | # 10 | # Fields is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # Fields is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with Fields. If not, see . 22 | # ------------------------------------------------------------------------- 23 | # @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | # @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | # @link https://github.com/pluginsGLPI/fields 26 | # ------------------------------------------------------------------------- 27 | #} 28 | 29 | {% import 'components/form/fields_macros.html.twig' as fields %} 30 | 31 | {% set rand = random() %} 32 | 33 | {{ fields.dropdownArrayField( 34 | 'condition', 35 | condition, 36 | list_conditions, 37 | __('Condition'), 38 | {'rand': rand, 'display_emptychoice': false} 39 | ) }} 40 | 41 | {% if is_dropdown %} 42 | 43 | {{ fields.dropdownField( 44 | dropdown_itemtype, 45 | 'value', 46 | value, 47 | __('Value'), 48 | dropdown_option 49 | ) }} 50 | 51 | {% elseif is_specific %} 52 | 53 | {% if is_list_values %} 54 | {{ fields.dropdownArrayField('value', value, list_values, __('Value'), {'rand': rand, 'display_emptychoice': false}) }} 55 | {% else %} 56 | 57 | {% if itemtype_field == 'urgency' %} 58 | {{ fields.field( 59 | 'value', 60 | item.dropdownUrgency({ 61 | 'value': value, 62 | 'name': 'value', 63 | 'width': '100%', 64 | 'display': false, 65 | }), 66 | __('Value'), 67 | {} 68 | ) }} 69 | {% elseif itemtype_field == 'impact' %} 70 | {{ fields.field( 71 | 'value', 72 | item.dropdownImpact({ 73 | 'value': value, 74 | 'name': 'value', 75 | 'width': '100%', 76 | 'display': false, 77 | }), 78 | __('Value'), 79 | {} 80 | ) }} 81 | 82 | {% else %} 83 | {{ fields.field( 84 | 'value', 85 | item.dropdownPriority({ 86 | 'value': value, 87 | 'name': 'value', 88 | 'width': '100%', 89 | 'display': false, 90 | }), 91 | __('Value'), 92 | {} 93 | ) }} 94 | {% endif %} 95 | {% endif %} 96 | 97 | {% else %} 98 | 99 | {{ fields.textField('value', value, __('Value'), {}) }} 100 | 101 | {% endif %} 102 | -------------------------------------------------------------------------------- /templates/forms/status_override.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # ------------------------------------------------------------------------- 3 | # Fields plugin for GLPI 4 | # ------------------------------------------------------------------------- 5 | # 6 | # LICENSE 7 | # 8 | # This file is part of Fields. 9 | # 10 | # Fields is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # Fields is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with Fields. If not, see . 22 | # ------------------------------------------------------------------------- 23 | # @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | # @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | # @link https://github.com/pluginsGLPI/fields 26 | # ------------------------------------------------------------------------- 27 | #} 28 | 29 | {% import 'components/form/fields_macros.html.twig' as fields %} 30 | {% set rand = random() %} 31 | 32 |
33 | 34 |
35 |
36 |
37 |
38 |
39 | {% set itemtype = override.fields['itemtype']|default(container_itemtypes|keys|first) %} 40 | 41 | {{ fields.dropdownArrayField('itemtype', itemtype, container_itemtypes, __('Item type')) }} 42 | {{ fields.dropdownArrayField('plugin_fields_fields_id', override.fields['plugin_fields_fields_id'], container_fields, __('Field', 'fields')) }} 43 | 44 | {% set status_field_html %} 45 |
46 | {{ call('PluginFieldsStatusOverride::getStatusDropdownForItemtype', [itemtype, override.fields['states']|default([])])|raw }} 47 |
48 | {% endset %} 49 | {{ fields.field('status_inner_container', status_field_html, __('Status')) }} 50 | 51 | {{ fields.dropdownYesNo('mandatory', override.fields['mandatory']|default(null), __('Mandatory field')) }} 52 | {{ fields.dropdownYesNo('is_readonly', override.fields['is_readonly']|default(null), __("Read only", "fields")) }} 53 |
{# .row #} 54 |
55 | {% if override.isNewItem() %} 56 | 60 | {% else %} 61 | 62 | 66 | {% endif %} 67 | 68 |
69 |
{# .row #} 70 |
{# .flex-row #} 71 |
72 |
{# .card-body #} 73 |
74 | 95 | -------------------------------------------------------------------------------- /templates/injection.class.tpl: -------------------------------------------------------------------------------- 1 | $data) { 51 | $searchoptions[$id]['injectable'] = PluginDatainjectionCommonInjectionLib::FIELD_INJECTABLE; 52 | if (!isset($searchoptions[$id]['displaytype'])) { 53 | if (isset($searchoptions[$id]['datatype'])) { 54 | $searchoptions[$id]['displaytype'] = $searchoptions[$id]['datatype']; 55 | } else { 56 | $searchoptions[$id]['displaytype'] = 'text'; 57 | } 58 | } 59 | } 60 | 61 | return $searchoptions; 62 | } 63 | 64 | /** 65 | * Standard method to add an object into glpi 66 | * 67 | * @param $values array fields to add into glpi 68 | * @param $options array options used during creation 69 | * 70 | * @return array of IDs of newly created objects: 71 | * for example array(Computer=>1, Networkport=>10) 72 | **/ 73 | function addOrUpdateObject($values=array(), $options=array()) { 74 | $lib = new PluginDatainjectionCommonInjectionLib($this, $values, $options); 75 | $lib->processAddOrUpdate(); 76 | return $lib->getInjectionResults(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /templates/status_overrides.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | # ------------------------------------------------------------------------- 3 | # Fields plugin for GLPI 4 | # ------------------------------------------------------------------------- 5 | # 6 | # LICENSE 7 | # 8 | # This file is part of Fields. 9 | # 10 | # Fields is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # Fields is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with Fields. If not, see . 22 | # ------------------------------------------------------------------------- 23 | # @copyright Copyright (C) 2013-2023 by Fields plugin team. 24 | # @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 25 | # @link https://github.com/pluginsGLPI/fields 26 | # ------------------------------------------------------------------------- 27 | #} 28 | 29 | {% import 'components/form/fields_macros.html.twig' as fields %} 30 | {% set rand = random() %} 31 | 32 |
33 | 34 | 45 | 46 | {% if has_fields %} 47 |
48 | 55 |
56 | {% endif %} 57 | 58 | {{ fields.largeTitle(__('Status overrides', 'fields'), '', false) }} 59 |
60 |
61 |
62 |
63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | {% if overrides|length > 0 %} 77 | {% for override in overrides %} 78 | 79 | 80 | 81 | 82 | 83 | 84 | 101 | 102 | {% endfor %} 103 | {% else %} 104 | 105 | 106 | 107 | {% endif %} 108 | 109 |
{{ __('Item type') }}{{ __('Field') }}{{ __('Status') }}{{ __('Mandatory') }}{{ __('Read only') }}
{{ override.itemtype }}{{ override.field_name }}{{ override.status_names|join(', ') }}{{ override.mandatory ? __('Yes') : __('No') }}{{ override.is_readonly ? __('Yes') : __('No') }} 85 |
86 | 87 | 88 | 93 | 98 | 99 |
100 |
{{ __('No item found', 'fields') }}
110 |
{# .row #} 111 |
{# .row #} 112 |
{# .flex-row #} 113 |
114 |
{# .card-body #} 115 | 157 |
158 | -------------------------------------------------------------------------------- /tools/HEADER: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------- 2 | Fields plugin for GLPI 3 | ------------------------------------------------------------------------- 4 | 5 | LICENSE 6 | 7 | This file is part of Fields. 8 | 9 | Fields is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | Fields is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with Fields. If not, see . 21 | ------------------------------------------------------------------------- 22 | @copyright Copyright (C) 2013-2023 by Fields plugin team. 23 | @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html 24 | @link https://github.com/pluginsGLPI/fields 25 | ------------------------------------------------------------------------- 26 | --------------------------------------------------------------------------------