Merge branch 'master' into turbo
3
.env
|
@ -9,6 +9,7 @@
|
|||
# Real environment variables win over .env files.
|
||||
#
|
||||
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||
# https://symfony.com/doc/current/configuration/secrets.html
|
||||
#
|
||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||
# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
|
||||
|
@ -82,5 +83,5 @@ HISTORY_SAVE_REMOVED_DATA=0
|
|||
|
||||
|
||||
###> symfony/mailer ###
|
||||
# MAILER_DSN=smtp://localhost
|
||||
# MAILER_DSN=null://null
|
||||
###< symfony/mailer ###
|
||||
|
|
18
.github/workflows/docker_build.yml
vendored
|
@ -18,32 +18,38 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Docker meta
|
||||
id: docker_meta
|
||||
uses: crazy-max/ghaction-docker-meta@v1
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: |
|
||||
jbtronics/part-db1
|
||||
# Mark the image build from master as latest (as we dont have really releases yet)
|
||||
tags: |
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
type=ref,event=branch,
|
||||
type=ref,event=tag,
|
||||
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
-
|
||||
name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
|
|
4
.github/workflows/static_analysis.yml
vendored
|
@ -12,14 +12,14 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get Composer Cache Directory
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
|
||||
- uses: actions/cache@v1
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
|
|
49
.github/workflows/tests.yml
vendored
|
@ -12,23 +12,34 @@ on:
|
|||
|
||||
jobs:
|
||||
phpunit:
|
||||
name: PHPUnit and coverage Test (${{ matrix.php-versions }})
|
||||
name: PHPUnit and coverage Test (PHP ${{ matrix.php-versions }}, ${{ matrix.db-type }})
|
||||
# Ubuntu 20.04 ships MySQL 8.0 which causes problems with login, so we just use ubuntu 18.04 for now...
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
env:
|
||||
APP_ENV: test
|
||||
SYMFONY_DEPRECATIONS_HELPER: disabled
|
||||
DATABASE_URL: 'mysql://root:root@127.0.0.1:3306/test'
|
||||
PHP_VERSION: ${{ matrix.php-versions }}
|
||||
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['7.3', '7.4', '8.0', '8.1']
|
||||
php-versions: [ '7.3', '7.4', '8.0', '8.1' ]
|
||||
db-type: [ 'mysql', 'sqlite' ]
|
||||
|
||||
env:
|
||||
# Note that we set DATABASE URL later based on our db-type matrix value
|
||||
APP_ENV: test
|
||||
SYMFONY_DEPRECATIONS_HELPER: disabled
|
||||
PHP_VERSION: ${{ matrix.php-versions }}
|
||||
DB_TYPE: ${{ matrix.db-type }}
|
||||
|
||||
steps:
|
||||
- name: Set Database env for MySQL
|
||||
run: echo "DATABASE_URL=mysql://root:root@127.0.0.1:3306/test" >> $GITHUB_ENV
|
||||
if: matrix.db-type == 'mysql'
|
||||
|
||||
- name: Set Database env for SQLite
|
||||
run: echo "DATABASE_URL="sqlite:///%kernel.project_dir%/var/app_test.db"" >> $GITHUB_ENV
|
||||
if: matrix.db-type == 'sqlite'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
|
@ -63,7 +74,7 @@ jobs:
|
|||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- uses: actions/cache@v1
|
||||
- uses: actions/cache@v3
|
||||
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
|
@ -75,9 +86,9 @@ jobs:
|
|||
run: composer install --prefer-dist --no-progress
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '12'
|
||||
node-version: '16'
|
||||
|
||||
- name: Install yarn dependencies
|
||||
run: yarn install
|
||||
|
@ -87,6 +98,12 @@ jobs:
|
|||
|
||||
- name: Create DB
|
||||
run: php bin/console --env test doctrine:database:create --if-not-exists -n
|
||||
if: matrix.db-type == 'mysql'
|
||||
|
||||
# Checkinf for existance is not supported for sqlite, so do it without it
|
||||
- name: Create DB
|
||||
run: php bin/console --env test doctrine:database:create -n
|
||||
if: matrix.db-type == 'sqlite'
|
||||
|
||||
- name: Do migrations
|
||||
run: php bin/console --env test doctrine:migrations:migrate -n
|
||||
|
@ -98,9 +115,9 @@ jobs:
|
|||
run: ./bin/phpunit --coverage-clover=coverage.xml
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
env_vars: PHP_VERSION
|
||||
env_vars: PHP_VERSION,DB_TYPE
|
||||
|
||||
- name: Test app:clean-attachments
|
||||
run: php bin/console app:clean-attachments -n
|
||||
|
|
26
Dockerfile
|
@ -1,14 +1,30 @@
|
|||
FROM php:7-apache
|
||||
FROM php:8.1-apache
|
||||
|
||||
# Install needed dependencies for PHP build
|
||||
RUN apt-get update && apt-get install -y pkg-config curl libcurl4-openssl-dev libicu-dev \
|
||||
libpng-dev libjpeg-dev libfreetype6-dev gnupg zip libzip-dev libonig-dev libxslt-dev vim \
|
||||
libpng-dev libjpeg-dev libfreetype6-dev gnupg zip libzip-dev libjpeg62-turbo-dev libonig-dev libxslt-dev libwebp-dev vim \
|
||||
&& apt-get -y autoremove && apt-get clean autoclean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install GD (we have to configure GD first before installing it, see issue #115)
|
||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg && docker-php-ext-install gd
|
||||
# Install GD with support for multiple formats
|
||||
RUN docker-php-ext-configure gd \
|
||||
--with-webp \
|
||||
--with-jpeg \
|
||||
--with-freetype \
|
||||
&& docker-php-ext-install gd
|
||||
|
||||
# Install other needed PHP extensions
|
||||
RUN docker-php-ext-install pdo_mysql curl intl mbstring bcmath gd zip xml xsl
|
||||
RUN docker-php-ext-install pdo_mysql curl intl mbstring bcmath zip xml xsl
|
||||
|
||||
# Enable opcache and configure it recommended for symfony (see https://symfony.com/doc/current/performance.html)
|
||||
RUN docker-php-ext-enable opcache; \
|
||||
{ \
|
||||
echo 'opcache.memory_consumption=256'; \
|
||||
echo 'opcache.max_accelerated_files=20000'; \
|
||||
echo 'opcache.validate_timestamp=0'; \
|
||||
# Configure Realpath cache for performance
|
||||
echo 'realpath_cache_size=4096K'; \
|
||||
echo 'realpath_cache_ttl=600'; \
|
||||
} > /usr/local/etc/php/conf.d/symfony-recommended.ini
|
||||
|
||||
# Install yarn
|
||||
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||

|
||||

|
||||
[](https://part-db.crowdin.com/part-db)
|
||||
|
||||
# Part-DB
|
||||
Part-DB is an Open-Source inventory managment system for your electronic components.
|
||||
|
@ -67,6 +68,8 @@ See [UPGRADE](UPGRADE.md) for more infos.
|
|||
|
||||
*Hint:* A docker image is available under [jbtronics/part-db1](https://hub.docker.com/r/jbtronics/part-db1). How to setup Part-DB via docker is described [here](https://github.com/Part-DB/Part-DB-symfony/blob/master/docs/docker/docker-install.md).
|
||||
|
||||
**Below you find some general hints for installtion, see [here](docs/installation/installation_guide-debian.md) for a detailed guide how to install Part-DB on Debian/Ubuntu.**
|
||||
|
||||
1. Copy or clone this repository into a folder on your server.
|
||||
2. Configure your webserver to serve from the `public/` folder. See [here](https://symfony.com/doc/current/setup/web_server_configuration.html)
|
||||
for additional informations.
|
||||
|
@ -74,7 +77,7 @@ for additional informations.
|
|||
* Change the line `APP_ENV=dev` to `APP_ENV=prod`
|
||||
* If you do not want to use SQLite, change the value of `DATABASE_URL=` to your needs (see [here](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url)) for the format.
|
||||
In bigger instances with concurrent accesses, MySQL is more performant. This can not be changed easily later, so choose wisely.
|
||||
4. Install composer dependencies and generate autoload files: `composer install --no-dev`
|
||||
4. Install composer dependencies and generate autoload files: `composer install -o --no-dev`
|
||||
5. If you have put Part-DB into a sub-directory on your server (like `part-db/`), you have to edit the file
|
||||
`webpack.config.js` and uncomment the lines (remove the `//` before the lines) `.setPublicPath('/part-db/build')` (line 43) and
|
||||
`.setManifestKeyPrefix('build/')` (line 44). You have to replace `/part-db` with your own path on line 44.
|
||||
|
@ -89,6 +92,10 @@ for additional informations.
|
|||
When you want to upgrade to a newer version, then just copy the new files into the folder
|
||||
and repeat the steps 4. to 7.
|
||||
|
||||
### Reverse proxy
|
||||
If you are using a reverse proxy, you have to ensure that the proxies sets the `X-Forwarded-*` headers correctly, or you will get HTTP/HTTPS mixup and wrong hostnames.
|
||||
If the reverse proxy is on a different server (or it cannot access Part-DB via localhost) you have to set the `TRUSTED_PROXIES` env variable to match your reverse proxies IP-address (or IP block). You can do this in your `.env.local` or (when using docker) in your `docker-compose.yml` file.
|
||||
|
||||
## Useful console commands
|
||||
Part-DB provides some command consoles which can be invoked by `php bin/console [command]`. You can get help for every command with the parameter `--help`.
|
||||
Useful commands are:
|
||||
|
|
|
@ -300,7 +300,7 @@ $(document).on("ajaxUI:start ajaxUI:reload", function() {
|
|||
}
|
||||
|
||||
//@ts-ignore
|
||||
var clipboard = new ClipboardJS('.btn');
|
||||
var clipboard = new ClipboardJS('.btn[data-clipboard-target], .btn[data-clipboard-text], .btn[data-clipboard-action]');
|
||||
clipboard.on('success', function(e) {
|
||||
setTooltip(e.trigger, 'Copied!');
|
||||
hideTooltip(e.trigger);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"type": "project",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"require": {
|
||||
"php": "^7.3",
|
||||
"php": "^7.3 || ^8.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-iconv": "*",
|
||||
|
@ -16,7 +16,7 @@
|
|||
"doctrine/doctrine-bundle": "^2.0",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||
"doctrine/orm": "^2.9",
|
||||
"dompdf/dompdf": "^1.0.1",
|
||||
"dompdf/dompdf": "^2.0.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"florianv/swap": "^4.0",
|
||||
"florianv/swap-bundle": "dev-master",
|
||||
|
@ -71,7 +71,7 @@
|
|||
"webmozart/assert": "^1.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"dama/doctrine-test-bundle": "^6.0",
|
||||
"dama/doctrine-test-bundle": "^7.0",
|
||||
"doctrine/doctrine-fixtures-bundle": "^3.2",
|
||||
"ekino/phpstan-banned-code": "^v1.0.0",
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
|
@ -87,7 +87,7 @@
|
|||
"symfony/phpunit-bridge": "5.4.*",
|
||||
"symfony/stopwatch": "^5.2",
|
||||
"symfony/web-profiler-bundle": "^5.2",
|
||||
"symplify/easy-coding-standard": "^10.1.1",
|
||||
"symplify/easy-coding-standard": "^11.0",
|
||||
"vimeo/psalm": "^4.3.2"
|
||||
},
|
||||
"suggest": {
|
||||
|
|
1903
composer.lock
generated
|
@ -2,7 +2,19 @@
|
|||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
csrf_protection: true
|
||||
http_method_override: false
|
||||
|
||||
# Must be set to true, to enable the change of HTTP methhod via _method parameter, otherwise our delete routines does not work anymore
|
||||
# TODO: Rework delete routines to work without _method parameter as it is not recommended anymore (see https://github.com/symfony/symfony/issues/45278)
|
||||
http_method_override: true
|
||||
|
||||
# Allow users to configure trusted hosts via .env variables
|
||||
# see https://symfony.com/doc/current/reference/configuration/framework.html#trusted-hosts
|
||||
trusted_hosts: '%env(TRUSTED_HOSTS)%'
|
||||
|
||||
# Allow users to configure reverse proxies via .env variables. Default values are defined in parameters.yaml.
|
||||
trusted_proxies: '%env(TRUSTED_PROXIES)%'
|
||||
# Trust all headers by default. X-Forwared-Host can be a security risk if your reverse proxy doesn't set it.
|
||||
trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix']
|
||||
|
||||
# Enables session support. Note that the session will ONLY be started if you read or write from it.
|
||||
# Remove or comment this section to explicitly disable session support.
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
framework:
|
||||
default_locale: '%partdb.locale%'
|
||||
# Just enable the locales we need for performance reasons.
|
||||
enabled_locale: '%partdb.locale_menu%'
|
||||
translator:
|
||||
default_path: '%kernel.project_dir%/translations'
|
||||
fallbacks:
|
||||
|
|
|
@ -50,4 +50,5 @@ parameters:
|
|||
env(DEMO_MODE): 0
|
||||
env(ALLOW_ATTACHMENT_DOWNLOADS): 0
|
||||
|
||||
|
||||
env(TRUSTED_PROXIES): '127.0.0.1' #By default trust only our own server
|
||||
env(TRUSTED_HOSTS): '' # Trust all host names by default
|
||||
|
|
3
docs/docker/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
db/
|
||||
public_media/
|
||||
uploads/
|
|
@ -9,5 +9,11 @@ services:
|
|||
# By default
|
||||
- ./uploads:/var/www/html/uploads
|
||||
- ./public_media:/var/www/html/public/media
|
||||
- ./db:/var/www/html/var/db
|
||||
restart: unless-stopped
|
||||
image: jbtronics/part-db1:master
|
||||
image: jbtronics/part-db1:latest
|
||||
environment:
|
||||
# Put SQLite database in our mapped folder. You can configure some other kind of database here too.
|
||||
- DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db
|
||||
# In demo env logs will be redirected to stderr
|
||||
- APP_ENV=demo
|
|
@ -19,6 +19,9 @@ The docker image uses a SQLite database and all data (database, uploads and othe
|
|||
## Direct use of docker image
|
||||
You can use the `jbtronics/part-db1:master` image directly. You have to expose the port 80 to a host port and configure volumes for `/var/www/html/uploads` and `/var/www/html/public/media`.
|
||||
|
||||
If you want to use SQLite database (which is default), you have to configure Part-DB to put the database file in a mapped volume via the `DATABASE_URL` environment variable.
|
||||
For example if you set `DATABASE_URL=sqlite:///%kernel.project_dir%/var/db/app.db` then you will have to map the `/var/www/html/var/db/` folder to the docker container (see docker-compose.yaml for example).
|
||||
|
||||
You also have to create the database like described above in step 4.
|
||||
|
||||
## Running console commands
|
||||
|
|
178
docs/installation/installation_guide-debian.md
Normal file
|
@ -0,0 +1,178 @@
|
|||
# Part-DB installation guide for Debian 11 (Bullseye)
|
||||
This guide shows you how to install Part-DB directly on Debian 11 using apache2 and SQLite. This guide should work with recent Ubuntu and other Debian based distributions with little to no changes.
|
||||
Depending on what you want to do, using the prebuilt docker images may be a better choice, as you dont need to install this much dependencies. See **TODO** for more information of the docker installation.
|
||||
|
||||
**Caution: This guide shows you how to install Part-DB for use in a trusted local network. If you want to use Part-DB on the internet, you HAVE TO setup a SSL certificate for your connection!**
|
||||
|
||||
## Install prerequisites
|
||||
For the installation of Part-DB, we need some prerequisites. They can be installed by running the following command:
|
||||
```bash
|
||||
sudo apt install git curl zip ca-certificates software-properties-common apt-transport-https lsb-release nano wget
|
||||
```
|
||||
|
||||
## Install PHP and apache2
|
||||
Part-DB is written in [PHP](https://php.net) and therefore needs an PHP interpreter to run. Part-DB needs PHP 7.3 or higher, however it is recommended to use the most recent version of PHP for performance reasons and future compatibility.
|
||||
|
||||
As Debian 11 does not ship PHP 8.1 in it's default repositories, we have to add a repository for it. You can skip this step if your distribution is shipping a recent version of PHP or you want to use the built-in PHP version.
|
||||
```bash
|
||||
# Add sury repository for PHP 8.1
|
||||
sudo curl -sSL https://packages.sury.org/php/README.txt | sudo bash -x
|
||||
|
||||
# Update package list
|
||||
sudo apt update && sudo apt upgrade
|
||||
```
|
||||
Now you can install PHP 8.1 and required packages (change the 8.1 in the package version according to the version you want to use):
|
||||
```bash
|
||||
sudo apt install php8.1 libapache2-mod-php8.1 php8.1-opcache php8.1-curl php8.1-gd php8.1-mbstring php8.1-xml php8.1-bcmath php8.1-intl php8.1-zip php8.1-xsl php8.1-sqlite3 php8.1-mysql
|
||||
```
|
||||
The apache2 webserver should be already installed with this command and configured basically.
|
||||
|
||||
## Install composer
|
||||
Part-DB uses [composer](https://getcomposer.org/) to install required PHP libraries. As the versions shipped in the repositories is pretty old we install it manually:
|
||||
```bash
|
||||
# Download composer installer script
|
||||
wget -O /tmp/composer-setup.php https://getcomposer.org/installer
|
||||
# Install composer globally
|
||||
php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer
|
||||
# Make composer executable
|
||||
chmod +x /usr/local/bin/composer
|
||||
```
|
||||
|
||||
## Install yarn and nodejs
|
||||
To build the frontend (the user interface) Part-DB uses [yarn](https://yarnpkg.com/). As it dependens on nodejs and the shipped versions are pretty old, we install new versions from offical nodejs repository:
|
||||
```bash
|
||||
# Add recent node repository (nodejs 18 is supported until 2025)
|
||||
curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
||||
# Install nodejs
|
||||
sudo apt install nodejs
|
||||
```
|
||||
|
||||
We can install yarn with the following commands:
|
||||
```bash
|
||||
# Add yarn repository
|
||||
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null
|
||||
echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
|
||||
# Install yarn
|
||||
sudo apt update && sudo apt install yarn
|
||||
```
|
||||
|
||||
## Create a folder for Part-DB and download it
|
||||
We now have all prerequisites installed and can start to install Part-DB. We will create a folder for Part-DB in a webfolder of apache2 and download it to this folder. The downloading is done via git, which allows you to update easily later.
|
||||
```bash
|
||||
# Download Part-DB into the new folder /var/www/partdb
|
||||
git clone https://github.com/Part-DB/Part-DB-symfony.git /var/www/partdb
|
||||
```
|
||||
|
||||
Change ownership of the files to the apache user:
|
||||
```bash
|
||||
chown -R www-data:www-data /var/www/partdb
|
||||
```
|
||||
|
||||
For the next steps we should be in the Part-DB folder, so move into it:
|
||||
```bash
|
||||
cd /var/www/partdb
|
||||
```
|
||||
|
||||
## Create configuration for Part-DB
|
||||
The basic configuration of Part-DB is done by a `.env.local` file in the main directory. Create on by from the default configuration:
|
||||
```bash
|
||||
cp .env .env.local
|
||||
```
|
||||
|
||||
In your `.env.local` you can configure Part-DB according to your wishes. A full list of configuration options can be found **TODO**.
|
||||
Other configuration options like the default language or default currency can be found in `config/parameters.yaml`.
|
||||
|
||||
Please check that the `partdb.default_currency` value in `config/parameters.yaml` matches your mainly used currency, as this can not be changed after creating price informations.
|
||||
|
||||
## Install dependencies for Part-DB and build frontend
|
||||
Part-DB depends on several other libraries and components. Install them by running the following commands:
|
||||
```bash
|
||||
# Install composer dependencies (please note the sudo command, to run it under the web server user)
|
||||
sudo -u www-data composer install --no-dev -o
|
||||
|
||||
# Install yarn dependencies
|
||||
sudo yarn install
|
||||
# Build frontend
|
||||
sudo yarn build
|
||||
```
|
||||
|
||||
## Create a database for Part-DB
|
||||
Part-DB by default uses a file based sqlite database to store the data. Use the following command to create the database. The database will normally created at `/var/www/partdb/var/app.db`.
|
||||
```bash
|
||||
sudo -u www-data php bin/console doctrine:migrations:migrate
|
||||
```
|
||||
The command will warn you about schema changes and potential data loss. Continue with typing `yes`.
|
||||
|
||||
The command will output several lines of informations. Somewhere should be a a yellow background message like `The initial password for the "admin" user is: f502481134`. Write down this password as you will need it later for inital login.
|
||||
|
||||
## Configure apache2 to show Part-DB
|
||||
Part-DB is now configured, but we have to say apache2 to serve Part-DB as web application. This is done by creating a new apache site:
|
||||
```bash
|
||||
sudo nano /etc/apache2/sites-available/partdb.conf
|
||||
```
|
||||
and add the following content (change ServerName and ServerAlias to your needs):
|
||||
```
|
||||
<VirtualHost *:80>
|
||||
ServerName partdb.lan
|
||||
ServerAlias www.partdb.lan
|
||||
|
||||
DocumentRoot /var/www/partdb/public
|
||||
<Directory /var/www/partdb/public>
|
||||
AllowOverride All
|
||||
Order Allow,Deny
|
||||
Allow from All
|
||||
</Directory>
|
||||
|
||||
ErrorLog /var/log/apache2/partdb_error.log
|
||||
CustomLog /var/log/apache2/partdb_access.log combined
|
||||
</VirtualHost>
|
||||
```
|
||||
Activate the new site by:
|
||||
```bash
|
||||
sudo ln -s /etc/apache2/sites-available/partdb.conf /etc/apache2/sites-enabled/partdb.conf
|
||||
```
|
||||
|
||||
Configure apache to show pretty URL pathes for Part-DB (`/label/dialog` instead of `/index.php/label/dialog`):
|
||||
```bash
|
||||
sudo a2enmod rewrite
|
||||
```
|
||||
|
||||
If you want to access Part-DB via the IP-Address of the server, instead of the domain name, you have to remove the apache2 default configuration with:
|
||||
```bash
|
||||
sudo rm /etc/apache2/sites-enabled/000-default.conf
|
||||
```
|
||||
|
||||
Restart the apache2 webserver with:
|
||||
```bash
|
||||
sudo service apache2 restart
|
||||
```
|
||||
|
||||
and Part-DB should now be available under `http://YourServerIP` (or `http://partdb.lan` if you configured DNS in your network to point on the server).
|
||||
|
||||
## Login to Part-DB
|
||||
Navigate to the Part-DB web interface and login via the user icon in the top right corner. You can login using the username `admin` and the password you have written down earlier.
|
||||
|
||||
## Update Part-DB
|
||||
If you want to update your existing Part-DB installation, you just have to run the following commands:
|
||||
```bash
|
||||
# Move into Part-DB folder
|
||||
cd /var/www/partdb
|
||||
# Pull latest Part-DB version from GitHub
|
||||
git pull
|
||||
# Apply correct permission
|
||||
chown -R www-data:www-data .
|
||||
# Install new composer dependencies
|
||||
sudo -u www-data composer install --no-dev -o
|
||||
# Install yarn dependencies and build new frontend
|
||||
sudo yarn install
|
||||
sudo yarn build
|
||||
|
||||
# Check if all your configurations in .env.local and /var/www/partdb/config/parameters.yaml are correct.
|
||||
sudo nano config/parameters.yaml
|
||||
|
||||
# Apply new database schemas (you should do a backup of your database file /var/www/partdb/var/app.db before)
|
||||
sudo -u www-data php bin/console doctrine:migrations:migrate
|
||||
|
||||
# Clear Part-DB cache
|
||||
sudo u www-data php bin/console cache:clear
|
||||
```
|
|
@ -1,39 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="bin/.phpunit/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<server name="APP_ENV" value="test" force="true" />
|
||||
<server name="SHELL_VERBOSITY" value="-1" />
|
||||
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
|
||||
<server name="SYMFONY_PHPUNIT_VERSION" value="8.5" />
|
||||
<ini name="memory_limit" value="512M" />
|
||||
<ini name="display_errors" value="1" />
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Project Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<extensions>
|
||||
<extension class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension"/>
|
||||
</extensions>
|
||||
|
||||
<listeners>
|
||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
|
||||
</listeners>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="tests/bootstrap.php">
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1"/>
|
||||
<server name="APP_ENV" value="test" force="true"/>
|
||||
<server name="SHELL_VERBOSITY" value="-1"/>
|
||||
<server name="SYMFONY_PHPUNIT_REMOVE" value=""/>
|
||||
<server name="SYMFONY_PHPUNIT_VERSION" value="9"/>
|
||||
<ini name="memory_limit" value="512M"/>
|
||||
<ini name="display_errors" value="1"/>
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Project Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<extensions>
|
||||
<extension class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension"/>
|
||||
</extensions>
|
||||
<listeners>
|
||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
|
||||
</listeners>
|
||||
</phpunit>
|
||||
|
|
Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 652 B After Width: | Height: | Size: 652 B |
Before Width: | Height: | Size: 645 B After Width: | Height: | Size: 645 B |
Before Width: | Height: | Size: 735 B After Width: | Height: | Size: 735 B |
Before Width: | Height: | Size: 713 B After Width: | Height: | Size: 713 B |
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 768 B |
Before Width: | Height: | Size: 511 B After Width: | Height: | Size: 511 B |
Before Width: | Height: | Size: 474 B After Width: | Height: | Size: 474 B |
Before Width: | Height: | Size: 467 B After Width: | Height: | Size: 467 B |
Before Width: | Height: | Size: 505 B After Width: | Height: | Size: 505 B |
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 768 B |
|
@ -2,7 +2,7 @@
|
|||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/icons/mstile-150x150.png"/>
|
||||
<square150x150logo src="/icon/mstile-150x150.png"/>
|
||||
<TileColor>#00a300</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
Before Width: | Height: | Size: 338 B After Width: | Height: | Size: 338 B |
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 718 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
@ -8,11 +8,11 @@
|
|||
"theme_color": "#ffffff",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/android-chrome-192x192.png",
|
||||
"src": "/icon/android-chrome-192x192.png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "/icons/android-chrome-384x384.png",
|
||||
"src": "/icon/android-chrome-384x384.png",
|
||||
"sizes": "384x384"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -90,7 +90,7 @@ class ShowEventLogCommand extends Command
|
|||
$total_count = $this->repo->count([]);
|
||||
$max_page = (int) ceil($total_count / $limit);
|
||||
|
||||
if ($page > $max_page) {
|
||||
if ($page > $max_page && $max_page > 0) {
|
||||
$io->error("There is no page ${page}! The maximum page is ${max_page}.");
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace App\Entity\Attachments;
|
|||
use App\Entity\Base\AbstractNamedDBElement;
|
||||
use App\Validator\Constraints\Selectable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
|
@ -105,6 +106,7 @@ abstract class Attachment extends AbstractNamedDBElement
|
|||
* @ORM\ManyToOne(targetEntity="AttachmentType", inversedBy="attachments_with_type")
|
||||
* @ORM\JoinColumn(name="type_id", referencedColumnName="id")
|
||||
* @Selectable()
|
||||
* @Assert\NotNull(message="validator.attachment.must_not_be_null")
|
||||
*/
|
||||
protected $attachment_type;
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ abstract class AbstractDBElement implements \JsonSerializable
|
|||
return $this->id;
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return ['@id' => $this->getID()];
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ class Orderdetail extends AbstractDBElement implements TimeStampableInterface, N
|
|||
* @var Supplier
|
||||
* @ORM\ManyToOne(targetEntity="App\Entity\Parts\Supplier", inversedBy="orderdetails")
|
||||
* @ORM\JoinColumn(name="id_supplier", referencedColumnName="id")
|
||||
* @Assert\NotNull(message="validator.orderdetail.supplier_must_not_be_null")
|
||||
*/
|
||||
protected $supplier;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ final class StructuralDBElementIterator extends ArrayIterator implements Recursi
|
|||
return !empty($element->getSubelements());
|
||||
}
|
||||
|
||||
public function getChildren()
|
||||
public function getChildren(): StructuralDBElementIterator
|
||||
{
|
||||
/** @var AbstractStructuralDBElement $element */
|
||||
$element = $this->current();
|
||||
|
|
|
@ -233,7 +233,7 @@ final class TreeViewNode implements JsonSerializable
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$ret = [
|
||||
'text' => $this->text,
|
||||
|
|
|
@ -63,7 +63,7 @@ final class TreeViewNodeIterator extends ArrayIterator implements RecursiveItera
|
|||
return !empty($element->getNodes());
|
||||
}
|
||||
|
||||
public function getChildren()
|
||||
public function getChildren(): TreeViewNodeIterator
|
||||
{
|
||||
/** @var TreeViewNode $element */
|
||||
$element = $this->current();
|
||||
|
|
|
@ -8,6 +8,9 @@ use Doctrine\DBAL\Driver\AbstractMySQLDriver;
|
|||
use Doctrine\DBAL\Driver\AbstractSQLiteDriver;
|
||||
use Doctrine\DBAL\Exception;
|
||||
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
|
||||
use Doctrine\DBAL\Platforms\MariaDBPlatform;
|
||||
use Doctrine\DBAL\Platforms\MySQLPlatform;
|
||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
@ -124,11 +127,11 @@ abstract class AbstractMultiPlatformMigration extends AbstractMigration
|
|||
*/
|
||||
public function getDatabaseType(): ?string
|
||||
{
|
||||
if ($this->connection->getDriver() instanceof AbstractMySQLDriver) {
|
||||
if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) {
|
||||
return 'mysql';
|
||||
}
|
||||
|
||||
if ($this->connection->getDriver() instanceof AbstractSQLiteDriver) {
|
||||
if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
|
||||
return 'sqlite';
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace App\Services\Attachments;
|
|||
use App\Entity\Attachments\Attachment;
|
||||
use InvalidArgumentException;
|
||||
use Liip\ImagineBundle\Service\FilterService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use function strlen;
|
||||
use Symfony\Component\Asset\Packages;
|
||||
|
@ -59,15 +60,18 @@ class AttachmentURLGenerator
|
|||
protected $attachmentHelper;
|
||||
protected $filterService;
|
||||
|
||||
protected $logger;
|
||||
|
||||
public function __construct(Packages $assets, AttachmentPathResolver $pathResolver,
|
||||
UrlGeneratorInterface $urlGenerator, AttachmentManager $attachmentHelper,
|
||||
FilterService $filterService)
|
||||
FilterService $filterService, LoggerInterface $logger)
|
||||
{
|
||||
$this->assets = $assets;
|
||||
$this->pathResolver = $pathResolver;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->attachmentHelper = $attachmentHelper;
|
||||
$this->filterService = $filterService;
|
||||
$this->logger = $logger;
|
||||
|
||||
//Determine a normalized path to the public folder (assets are relative to this folder)
|
||||
$this->public_path = $this->pathResolver->parameterToAbsolutePath('public');
|
||||
|
@ -168,8 +172,14 @@ class AttachmentURLGenerator
|
|||
return $this->assets->getUrl($asset_path);
|
||||
}
|
||||
|
||||
//Otherwise we can serve the relative path via Asset component
|
||||
return $this->filterService->getUrlOfFilteredImage($asset_path, $filter_name);
|
||||
try {
|
||||
//Otherwise we can serve the relative path via Asset component
|
||||
return $this->filterService->getUrlOfFilteredImage($asset_path, $filter_name);
|
||||
} catch (\Imagine\Exception\RuntimeException $e) {
|
||||
//If the filter fails, we can not serve the thumbnail and fall back to the original image and log an warning
|
||||
$this->logger->warning('Could not open thumbnail for attachment with ID ' . $attachment->getID() . ': ' . $e->getMessage());
|
||||
return $this->assets->getUrl($asset_path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
16
symfony.lock
|
@ -512,15 +512,15 @@
|
|||
"version": "v4.2.3"
|
||||
},
|
||||
"symfony/flex": {
|
||||
"version": "1.0",
|
||||
"version": "1.19",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "master",
|
||||
"branch": "main",
|
||||
"version": "1.0",
|
||||
"ref": "c0eeb50665f0f77226616b6038a9b06c03752d8e"
|
||||
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
|
||||
},
|
||||
"files": [
|
||||
"./.env"
|
||||
".env"
|
||||
]
|
||||
},
|
||||
"symfony/form": {
|
||||
|
@ -561,15 +561,15 @@
|
|||
"version": "v4.2.3"
|
||||
},
|
||||
"symfony/mailer": {
|
||||
"version": "4.3",
|
||||
"version": "5.4",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "master",
|
||||
"branch": "main",
|
||||
"version": "4.3",
|
||||
"ref": "bbfc7e27257d3a3f12a6fb0a42540a42d9623a37"
|
||||
"ref": "97a61eabb351d7f6cb7702039bcfe07fe9d7e03c"
|
||||
},
|
||||
"files": [
|
||||
"./config/packages/mailer.yaml"
|
||||
"config/packages/mailer.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/maker-bundle": {
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
{# <img src="..." class="rounded mr-2" alt="...">#}
|
||||
<i class="fas fa-fw {{ flash_symbol }} mr-2"></i>
|
||||
<strong class="mr-auto">{{ flash_title|trans }}</strong>
|
||||
<small class="text-muted">{{ "now" | format_datetime("short", "short") }}</small>
|
||||
<small class="{% if "text-white" in flash_bg %}text-white{% else %}text-muted{% endif %}">{{ "now" | format_datetime("short", "short") }}</small>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body {{ flash_bg }}">
|
||||
{{ message | trans}}
|
||||
{{ message | trans }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="application-name" content="Part-DB">
|
||||
<meta name="apple-mobile-web-app-title" content="Part-DB">
|
||||
<meta name="msapplication-config" content="{{ asset('icons/browserconfig.xml') }}">
|
||||
<meta name="msapplication-config" content="{{ asset('icon/browserconfig.xml') }}">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="msapplication-navbutton-color" content="#ffffff">
|
||||
|
@ -18,11 +18,11 @@
|
|||
<meta name="msapplication-starturl" content="/en/">
|
||||
|
||||
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{{ asset('icons/favicon.ico') }}">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ asset('icons/apple-touch-icon.png') }}">
|
||||
<link rel="icon" type="image/png" href="{{ asset('icons/favicon-32x32.png') }}" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="{{ asset('icons/favicon-16x16.png') }}" sizes="16x16">
|
||||
<link rel="mask-icon" href="{{ asset('icons/safari-pinned-tab.svg') }}" color="#5bbad5">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="{{ asset('icon/favicon.ico') }}">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ asset('icon/apple-touch-icon.png') }}">
|
||||
<link rel="icon" type="image/png" href="{{ asset('icon/favicon-32x32.png') }}" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="{{ asset('icon/favicon-16x16.png') }}" sizes="16x16">
|
||||
<link rel="mask-icon" href="{{ asset('icon/safari-pinned-tab.svg') }}" color="#5bbad5">
|
||||
|
||||
|
||||
<title>{% apply trim %}{% block title %}{{ partdb_title}}{% endblock %}{% endapply %}</title>
|
||||
|
|
|
@ -19,9 +19,10 @@
|
|||
<li>Run <kbd>yarn install</kbd> and <kbd>yarn build</kbd> in Part-DB folder.</li>
|
||||
<li>Run <kbd>php bin/console cache:clear</kbd></li>
|
||||
</ul>
|
||||
{% elseif exception.class == "Doctrine\\DBAL\\Exception\\InvalidFieldNameException" %}
|
||||
<i>Invalid database schema.</i> Try following things:
|
||||
{% elseif exception.class == "Doctrine\\DBAL\\Exception\\InvalidFieldNameException" or exception.class == "Doctrine\\DBAL\\Exception\\TableNotFoundException" %}
|
||||
<i>Invalid or not existing database schema.</i> Try following things:
|
||||
<ul>
|
||||
<li>Check if the <code>DATABASE_URL</code> in <code>.env.local</code> is correct</li>
|
||||
<li>Run <kbd>php bin/console doctrine:migrations:migrate</kbd> to upgrade database schema</li>
|
||||
<li>Run <kbd>php bin/console cache:clear</kbd></li>
|
||||
</ul>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<h4><i class="fa fa-book fa-fw" aria-hidden="true"></i> {% trans %}homepage.license{% endtrans %}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Part-DB, Copyright © 2019 - 2020 of <strong>
|
||||
<p>Part-DB, Copyright © 2019 - 2022 of <strong>
|
||||
<a class="link-external" rel="noopener" target="_blank" href="https://github.com/jbtronics/">Jan Böhmer</a>
|
||||
</strong>. <br> Part-DB is published under the <strong>GNU Affero General Public License v3.0 (or later)</strong>, so it comes with <strong>ABSOLUTELY NO WARRANTY</strong>.
|
||||
This is free software, and you are welcome to redistribute it under certain conditions.
|
||||
|
|
|
@ -88,10 +88,12 @@ class UserTest extends TestCase
|
|||
public function testSetBackupCodes(): void
|
||||
{
|
||||
$user = new User();
|
||||
$this->assertNull($user->getBackupCodesGenerationDate());
|
||||
|
||||
$codes = ['test', 'invalid', 'test'];
|
||||
$user->setBackupCodes($codes);
|
||||
// Backup Codes generation date must be changed!
|
||||
$this->assertEqualsWithDelta(new DateTime(), $user->getBackupCodesGenerationDate(), 0.1);
|
||||
$this->assertInstanceOf(\DateTime::class, $user->getBackupCodesGenerationDate());
|
||||
$this->assertSame($codes, $user->getBackupCodes());
|
||||
|
||||
//Test what happens if we delete the backup keys
|
||||
|
|
|
@ -77,7 +77,7 @@ class BackupCodeGeneratorTest extends TestCase
|
|||
public function testGenerateSingleCode(int $code_length): void
|
||||
{
|
||||
$generator = new BackupCodeGenerator($code_length, 10);
|
||||
$this->assertRegExp("/^([a-f0-9]){{$code_length}}\$/", $generator->generateSingleCode());
|
||||
$this->assertMatchesRegularExpression("/^([a-f0-9]){{$code_length}}\$/", $generator->generateSingleCode());
|
||||
}
|
||||
|
||||
public function codeCountDataProvider(): array
|
||||
|
|
|
@ -215,5 +215,17 @@
|
|||
<target>This location can only contain a single part and it is already full!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4gPskOG" name="validator.attachment.must_not_be_null">
|
||||
<segment>
|
||||
<source>validator.attachment.must_not_be_null</source>
|
||||
<target>You must select an attachment type!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="cDDVrWT" name="validator.orderdetail.supplier_must_not_be_null">
|
||||
<segment>
|
||||
<source>validator.orderdetail.supplier_must_not_be_null</source>
|
||||
<target>You must select an supplier!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|