mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-02-24 10:42:35 +01:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c4e9066f9 | ||
|
|
b4d1af2bce | ||
|
|
5ec676c40c | ||
|
|
5096aea5bb | ||
|
|
feedd190dc | ||
|
|
3423fffaca | ||
|
|
1624fd2e28 | ||
|
|
10b3094d5e | ||
|
|
580e638f67 | ||
|
|
e44428f87c | ||
|
|
379f7ef865 | ||
|
|
427f6e4d55 | ||
|
|
07a1e9fc3c | ||
|
|
78d64e8f1b | ||
|
|
559a9a9f3e | ||
|
|
ac6dd23fd6 | ||
|
|
1e515df0b5 | ||
|
|
35490762a6 | ||
|
|
c25e23d3d9 | ||
|
|
8bb8257e62 | ||
|
|
5f096927bd | ||
|
|
434826c125 | ||
|
|
89595cd5dc | ||
|
|
d991e15a94 | ||
|
|
6a1aefa5a5 | ||
|
|
272684e7eb | ||
|
|
9be3eba694 | ||
|
|
5a3fc0fb43 | ||
|
|
47ef8e9568 | ||
|
|
e4285bbc78 | ||
|
|
49b6a42791 | ||
|
|
b62fd602f2 | ||
|
|
923e40ed8f | ||
|
|
3c724a227a | ||
|
|
90d26eb16a | ||
|
|
b629744e1a | ||
|
|
b0ab43c39a | ||
|
|
2c33b381c1 | ||
|
|
c50a80e8df | ||
|
|
bafbd63610 | ||
|
|
557347d42d | ||
|
|
c828aa3bc0 | ||
|
|
376d29e829 | ||
|
|
97ee4f36e3 | ||
|
|
d766f255ef | ||
|
|
19ae9e7456 | ||
|
|
61ea312403 | ||
|
|
13193c9368 | ||
|
|
31e0ce4c64 | ||
|
|
43238aff0a | ||
|
|
d598bfc35b | ||
|
|
1c836918ca | ||
|
|
4a6a3b9269 | ||
|
|
1534f780aa | ||
|
|
4c6ceab8e8 | ||
|
|
f3fc01b740 | ||
|
|
a201be5a01 | ||
|
|
ebf2035351 | ||
|
|
69fc28d5d6 | ||
|
|
4107535b19 |
3
.env
3
.env
@@ -71,6 +71,9 @@ HISTORY_SAVE_CHANGED_FIELDS=1
|
||||
HISTORY_SAVE_CHANGED_DATA=1
|
||||
# Save the data of an element that gets removed into log entry. This allows to undelete an element
|
||||
HISTORY_SAVE_REMOVED_DATA=1
|
||||
# Save the new data of an element that gets changed or added. This allows an easy comparison of the old and new data on the detail page
|
||||
# This option only becomes active when HISTORY_SAVE_CHANGED_DATA is set to 1
|
||||
HISTORY_SAVE_NEW_DATA=1
|
||||
|
||||
###################################################################################
|
||||
# Error pages settings
|
||||
|
||||
752
.github/assets/legacy_import/db_jbtronics.sql
vendored
Normal file
752
.github/assets/legacy_import/db_jbtronics.sql
vendored
Normal file
@@ -0,0 +1,752 @@
|
||||
-- phpMyAdmin SQL Dump
|
||||
-- version 5.1.3
|
||||
-- https://www.phpmyadmin.net/
|
||||
--
|
||||
-- Host: 127.0.0.1
|
||||
-- Erstellungszeit: 07. Mai 2023 um 01:58
|
||||
-- Server-Version: 10.6.5-MariaDB-log
|
||||
-- PHP-Version: 8.1.2
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
START TRANSACTION;
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
|
||||
--
|
||||
-- Datenbank: `partdb_demo`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `attachements`
|
||||
--
|
||||
|
||||
CREATE TABLE `attachements` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`class_name` varchar(255) COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`element_id` int(11) NOT NULL,
|
||||
`type_id` int(11) NOT NULL,
|
||||
`filename` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`show_in_table` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `attachements`
|
||||
--
|
||||
|
||||
INSERT INTO `attachements` (`id`, `name`, `class_name`, `element_id`, `type_id`, `filename`, `show_in_table`, `last_modified`) VALUES
|
||||
(1, 'BC547', 'Part', 2, 2, '%BASE%/data/media/bc547.pdf', 1, '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `attachement_types`
|
||||
--
|
||||
|
||||
CREATE TABLE `attachement_types` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `attachement_types`
|
||||
--
|
||||
|
||||
INSERT INTO `attachement_types` (`id`, `name`, `parent_id`, `comment`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'Bilder', NULL, NULL, '2017-10-21 17:58:48', '0000-00-00 00:00:00'),
|
||||
(2, 'Datenblätter', NULL, NULL, '2017-10-21 17:58:48', '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `categories`
|
||||
--
|
||||
|
||||
CREATE TABLE `categories` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`disable_footprints` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`disable_manufacturers` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`disable_autodatasheets` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`disable_properties` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`partname_regex` text COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`partname_hint` text COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`default_description` text COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`default_comment` text COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `categories`
|
||||
--
|
||||
|
||||
INSERT INTO `categories` (`id`, `name`, `parent_id`, `disable_footprints`, `disable_manufacturers`, `disable_autodatasheets`, `disable_properties`, `partname_regex`, `partname_hint`, `default_description`, `default_comment`, `comment`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'aktive Bauteile', NULL, 0, 0, 0, 0, '', '', '', '', NULL, '2017-10-21 17:58:49', '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `devices`
|
||||
--
|
||||
|
||||
CREATE TABLE `devices` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`order_quantity` int(11) NOT NULL DEFAULT 0,
|
||||
`order_only_missing_parts` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `devices`
|
||||
--
|
||||
|
||||
INSERT INTO `devices` (`id`, `name`, `parent_id`, `order_quantity`, `order_only_missing_parts`, `datetime_added`, `last_modified`, `comment`) VALUES
|
||||
(1, 'Test', NULL, 0, 0, '2015-04-16 15:08:56', '0000-00-00 00:00:00', NULL);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `device_parts`
|
||||
--
|
||||
|
||||
CREATE TABLE `device_parts` (
|
||||
`id` int(11) NOT NULL,
|
||||
`id_part` int(11) NOT NULL DEFAULT 0,
|
||||
`id_device` int(11) NOT NULL DEFAULT 0,
|
||||
`quantity` int(11) NOT NULL DEFAULT 0,
|
||||
`mountnames` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `device_parts`
|
||||
--
|
||||
|
||||
INSERT INTO `device_parts` (`id`, `id_part`, `id_device`, `quantity`, `mountnames`) VALUES
|
||||
(1, 2, 1, 1, '');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `footprints`
|
||||
--
|
||||
|
||||
CREATE TABLE `footprints` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`filename` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`filename_3d` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `footprints`
|
||||
--
|
||||
|
||||
INSERT INTO `footprints` (`id`, `name`, `filename`, `filename_3d`, `parent_id`, `comment`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'LEDs', '%BASE%/img/footprints/Optik/LEDs/Bedrahtet/LED-GELB_3MM.png', '', NULL, NULL, '2017-10-21 17:58:49', '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `groups`
|
||||
--
|
||||
|
||||
CREATE TABLE `groups` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(32) NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`comment` mediumtext DEFAULT NULL,
|
||||
`perms_system` int(11) NOT NULL,
|
||||
`perms_groups` int(11) NOT NULL,
|
||||
`perms_users` int(11) NOT NULL,
|
||||
`perms_self` int(11) NOT NULL,
|
||||
`perms_system_config` int(11) NOT NULL,
|
||||
`perms_system_database` int(11) NOT NULL,
|
||||
`perms_parts` bigint(11) NOT NULL,
|
||||
`perms_parts_name` smallint(6) NOT NULL,
|
||||
`perms_parts_description` smallint(6) NOT NULL,
|
||||
`perms_parts_instock` smallint(6) NOT NULL,
|
||||
`perms_parts_mininstock` smallint(6) NOT NULL,
|
||||
`perms_parts_footprint` smallint(6) NOT NULL,
|
||||
`perms_parts_storelocation` smallint(6) NOT NULL,
|
||||
`perms_parts_manufacturer` smallint(6) NOT NULL,
|
||||
`perms_parts_comment` smallint(6) NOT NULL,
|
||||
`perms_parts_order` smallint(6) NOT NULL,
|
||||
`perms_parts_orderdetails` smallint(6) NOT NULL,
|
||||
`perms_parts_prices` smallint(6) NOT NULL,
|
||||
`perms_parts_attachements` smallint(6) NOT NULL,
|
||||
`perms_devices` int(11) NOT NULL,
|
||||
`perms_devices_parts` int(11) NOT NULL,
|
||||
`perms_storelocations` int(11) NOT NULL,
|
||||
`perms_footprints` int(11) NOT NULL,
|
||||
`perms_categories` int(11) NOT NULL,
|
||||
`perms_suppliers` int(11) NOT NULL,
|
||||
`perms_manufacturers` int(11) NOT NULL,
|
||||
`perms_attachement_types` int(11) NOT NULL,
|
||||
`perms_tools` int(11) NOT NULL,
|
||||
`perms_labels` smallint(6) NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `groups`
|
||||
--
|
||||
|
||||
INSERT INTO `groups` (`id`, `name`, `parent_id`, `comment`, `perms_system`, `perms_groups`, `perms_users`, `perms_self`, `perms_system_config`, `perms_system_database`, `perms_parts`, `perms_parts_name`, `perms_parts_description`, `perms_parts_instock`, `perms_parts_mininstock`, `perms_parts_footprint`, `perms_parts_storelocation`, `perms_parts_manufacturer`, `perms_parts_comment`, `perms_parts_order`, `perms_parts_orderdetails`, `perms_parts_prices`, `perms_parts_attachements`, `perms_devices`, `perms_devices_parts`, `perms_storelocations`, `perms_footprints`, `perms_categories`, `perms_suppliers`, `perms_manufacturers`, `perms_attachement_types`, `perms_tools`, `perms_labels`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'admins', NULL, 'Users of this group can do everything: Read, Write and Administrative actions.', 21, 1365, 87381, 85, 85, 21, 1431655765, 5, 5, 5, 5, 5, 5, 5, 5, 5, 325, 325, 325, 5461, 325, 5461, 5461, 5461, 5461, 5461, 1365, 1365, 85, '2017-10-21 17:58:46', '2018-10-08 17:27:41'),
|
||||
(2, 'readonly', NULL, 'Users of this group can only read informations, use tools, and don\'t have access to administrative tools.', 2, 2730, 43690, 25, 170, 42, 2778027689, 9, 9, 9, 9, 9, 9, 9, 9, 9, 649, 649, 649, 1705, 649, 1705, 1705, 1705, 1705, 1705, 681, 1366, 165, '2017-10-21 17:58:46', '2018-10-08 17:28:35'),
|
||||
(3, 'users', NULL, 'Users of this group, can edit part informations, create new ones, etc. but are not allowed to use administrative tools. (But can read current configuration, and see Server status)', 42, 2730, 43689, 89, 105, 41, 1431655765, 5, 5, 5, 5, 5, 5, 5, 5, 5, 325, 325, 325, 5461, 325, 5461, 5461, 5461, 5461, 5461, 1365, 1365, 85, '2017-10-21 17:58:46', '2018-10-08 17:28:17');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `internal`
|
||||
--
|
||||
|
||||
CREATE TABLE `internal` (
|
||||
`keyName` char(30) CHARACTER SET ascii NOT NULL,
|
||||
`keyValue` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `internal`
|
||||
--
|
||||
|
||||
INSERT INTO `internal` (`keyName`, `keyValue`) VALUES
|
||||
('dbVersion', '26');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `log`
|
||||
--
|
||||
|
||||
CREATE TABLE `log` (
|
||||
`id` int(11) NOT NULL,
|
||||
`datetime` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`id_user` int(11) NOT NULL,
|
||||
`level` tinyint(4) NOT NULL,
|
||||
`type` smallint(6) NOT NULL,
|
||||
`target_id` int(11) NOT NULL,
|
||||
`target_type` smallint(6) NOT NULL,
|
||||
`extra` mediumtext NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `manufacturers`
|
||||
--
|
||||
|
||||
CREATE TABLE `manufacturers` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`address` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`phone_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`fax_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`email_address` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`website` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`auto_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `manufacturers`
|
||||
--
|
||||
|
||||
INSERT INTO `manufacturers` (`id`, `name`, `parent_id`, `address`, `phone_number`, `fax_number`, `email_address`, `website`, `auto_product_url`, `datetime_added`, `comment`, `last_modified`) VALUES
|
||||
(1, 'Atmel', NULL, '', '', '', '', '', '', '2015-03-01 11:27:10', NULL, '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `orderdetails`
|
||||
--
|
||||
|
||||
CREATE TABLE `orderdetails` (
|
||||
`id` int(11) NOT NULL,
|
||||
`part_id` int(11) NOT NULL,
|
||||
`id_supplier` int(11) NOT NULL DEFAULT 0,
|
||||
`supplierpartnr` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`obsolete` tinyint(1) DEFAULT 0,
|
||||
`supplier_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp()
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `parts`
|
||||
--
|
||||
|
||||
CREATE TABLE `parts` (
|
||||
`id` int(11) NOT NULL,
|
||||
`id_category` int(11) NOT NULL DEFAULT 0,
|
||||
`name` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`description` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`instock` int(11) NOT NULL DEFAULT 0,
|
||||
`mininstock` int(11) NOT NULL DEFAULT 0,
|
||||
`comment` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`visible` tinyint(1) NOT NULL,
|
||||
`id_footprint` int(11) DEFAULT NULL,
|
||||
`id_storelocation` int(11) DEFAULT NULL,
|
||||
`order_orderdetails_id` int(11) DEFAULT NULL,
|
||||
`order_quantity` int(11) NOT NULL DEFAULT 1,
|
||||
`manual_order` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`id_manufacturer` int(11) DEFAULT NULL,
|
||||
`id_master_picture_attachement` int(11) DEFAULT NULL,
|
||||
`manufacturer_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`favorite` tinyint(1) NOT NULL DEFAULT 0
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `parts`
|
||||
--
|
||||
|
||||
INSERT INTO `parts` (`id`, `id_category`, `name`, `description`, `instock`, `mininstock`, `comment`, `visible`, `id_footprint`, `id_storelocation`, `order_orderdetails_id`, `order_quantity`, `manual_order`, `id_manufacturer`, `id_master_picture_attachement`, `manufacturer_product_url`, `datetime_added`, `last_modified`, `favorite`) VALUES
|
||||
(2, 1, 'BC547C', 'NPN 45V 0,1A 0,5W', 59, 0, '', 0, 1, 1, NULL, 1, 0, NULL, NULL, '', '2015-03-01 10:40:31', '2016-12-26 10:48:49', 0);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `pricedetails`
|
||||
--
|
||||
|
||||
CREATE TABLE `pricedetails` (
|
||||
`id` int(11) NOT NULL,
|
||||
`orderdetails_id` int(11) NOT NULL,
|
||||
`price` decimal(11,5) DEFAULT NULL,
|
||||
`price_related_quantity` int(11) NOT NULL DEFAULT 1,
|
||||
`min_discount_quantity` int(11) NOT NULL DEFAULT 1,
|
||||
`manual_input` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`last_modified` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `storelocations`
|
||||
--
|
||||
|
||||
CREATE TABLE `storelocations` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`is_full` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `storelocations`
|
||||
--
|
||||
|
||||
INSERT INTO `storelocations` (`id`, `name`, `parent_id`, `is_full`, `datetime_added`, `comment`, `last_modified`) VALUES
|
||||
(1, 'Halbleiter I', NULL, 0, '2015-03-01 11:26:37', NULL, '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `suppliers`
|
||||
--
|
||||
|
||||
CREATE TABLE `suppliers` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`address` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`phone_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`fax_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`email_address` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`website` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`auto_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `suppliers`
|
||||
--
|
||||
|
||||
INSERT INTO `suppliers` (`id`, `name`, `parent_id`, `address`, `phone_number`, `fax_number`, `email_address`, `website`, `auto_product_url`, `datetime_added`, `comment`, `last_modified`) VALUES
|
||||
(1, 'Test', NULL, '', '', '', '', '', 'Test', '2015-03-01 10:37:23', NULL, '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `users`
|
||||
--
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(32) NOT NULL,
|
||||
`password` varchar(255) DEFAULT NULL,
|
||||
`first_name` tinytext DEFAULT NULL,
|
||||
`last_name` tinytext DEFAULT NULL,
|
||||
`department` tinytext DEFAULT NULL,
|
||||
`email` tinytext DEFAULT NULL,
|
||||
`need_pw_change` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`group_id` int(11) DEFAULT NULL,
|
||||
`config_language` tinytext DEFAULT NULL,
|
||||
`config_timezone` tinytext DEFAULT NULL,
|
||||
`config_theme` tinytext DEFAULT NULL,
|
||||
`config_currency` tinytext DEFAULT NULL,
|
||||
`config_image_path` text NOT NULL,
|
||||
`config_instock_comment_w` text NOT NULL,
|
||||
`config_instock_comment_a` text NOT NULL,
|
||||
`perms_system` int(11) NOT NULL,
|
||||
`perms_groups` int(11) NOT NULL,
|
||||
`perms_users` int(11) NOT NULL,
|
||||
`perms_self` int(11) NOT NULL,
|
||||
`perms_system_config` int(11) NOT NULL,
|
||||
`perms_system_database` int(11) NOT NULL,
|
||||
`perms_parts` bigint(11) NOT NULL,
|
||||
`perms_parts_name` smallint(6) NOT NULL,
|
||||
`perms_parts_description` smallint(6) NOT NULL,
|
||||
`perms_parts_instock` smallint(6) NOT NULL,
|
||||
`perms_parts_mininstock` smallint(6) NOT NULL,
|
||||
`perms_parts_footprint` smallint(6) NOT NULL,
|
||||
`perms_parts_storelocation` smallint(6) NOT NULL,
|
||||
`perms_parts_manufacturer` smallint(6) NOT NULL,
|
||||
`perms_parts_comment` smallint(6) NOT NULL,
|
||||
`perms_parts_order` smallint(6) NOT NULL,
|
||||
`perms_parts_orderdetails` smallint(6) NOT NULL,
|
||||
`perms_parts_prices` smallint(6) NOT NULL,
|
||||
`perms_parts_attachements` smallint(6) NOT NULL,
|
||||
`perms_devices` int(11) NOT NULL,
|
||||
`perms_devices_parts` int(11) NOT NULL,
|
||||
`perms_storelocations` int(11) NOT NULL,
|
||||
`perms_footprints` int(11) NOT NULL,
|
||||
`perms_categories` int(11) NOT NULL,
|
||||
`perms_suppliers` int(11) NOT NULL,
|
||||
`perms_manufacturers` int(11) NOT NULL,
|
||||
`perms_attachement_types` int(11) NOT NULL,
|
||||
`perms_tools` int(11) NOT NULL,
|
||||
`perms_labels` smallint(6) NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `users`
|
||||
--
|
||||
|
||||
INSERT INTO `users` (`id`, `name`, `password`, `first_name`, `last_name`, `department`, `email`, `need_pw_change`, `group_id`, `config_language`, `config_timezone`, `config_theme`, `config_currency`, `config_image_path`, `config_instock_comment_w`, `config_instock_comment_a`, `perms_system`, `perms_groups`, `perms_users`, `perms_self`, `perms_system_config`, `perms_system_database`, `perms_parts`, `perms_parts_name`, `perms_parts_description`, `perms_parts_instock`, `perms_parts_mininstock`, `perms_parts_footprint`, `perms_parts_storelocation`, `perms_parts_manufacturer`, `perms_parts_comment`, `perms_parts_order`, `perms_parts_orderdetails`, `perms_parts_prices`, `perms_parts_attachements`, `perms_devices`, `perms_devices_parts`, `perms_storelocations`, `perms_footprints`, `perms_categories`, `perms_suppliers`, `perms_manufacturers`, `perms_attachement_types`, `perms_tools`, `perms_labels`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'anonymous', '', '', '', '', '', 0, 2, '', '', '', NULL, '', '', '', 21848, 20480, 0, 0, 0, 0, 0, 21840, 21840, 21840, 21840, 21840, 21840, 21840, 21840, 21840, 21520, 21520, 21520, 20480, 21520, 20480, 20480, 20480, 20480, 20480, 21504, 20480, 0, '2017-10-21 17:58:46', '2018-02-18 12:46:58'),
|
||||
(2, 'admin', '$2a$12$j0RKrKlx60bzX1DWMyXwjeaW.pe3bFjAK8ByIGnvjrRnET2JtsFoe', 'Admin', 'Ad', NULL, 'admin@ras.pi', 0, 1, '', '', '', NULL, '', '', '', 21845, 21845, 21845, 21, 85, 21, 349525, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 0, '2017-10-21 17:58:46', '2017-12-23 11:04:48');
|
||||
|
||||
--
|
||||
-- Indizes der exportierten Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `attachements`
|
||||
--
|
||||
ALTER TABLE `attachements`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `attachements_class_name_k` (`class_name`),
|
||||
ADD KEY `attachements_element_id_k` (`element_id`),
|
||||
ADD KEY `attachements_type_id_fk` (`type_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `attachement_types`
|
||||
--
|
||||
ALTER TABLE `attachement_types`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `attachement_types_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `categories`
|
||||
--
|
||||
ALTER TABLE `categories`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `categories_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `devices`
|
||||
--
|
||||
ALTER TABLE `devices`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `devices_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `device_parts`
|
||||
--
|
||||
ALTER TABLE `device_parts`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `device_parts_combination_uk` (`id_part`,`id_device`),
|
||||
ADD KEY `device_parts_id_part_k` (`id_part`),
|
||||
ADD KEY `device_parts_id_device_k` (`id_device`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `footprints`
|
||||
--
|
||||
ALTER TABLE `footprints`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `footprints_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `groups`
|
||||
--
|
||||
ALTER TABLE `groups`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `name` (`name`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `internal`
|
||||
--
|
||||
ALTER TABLE `internal`
|
||||
ADD UNIQUE KEY `keyName` (`keyName`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `log`
|
||||
--
|
||||
ALTER TABLE `log`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `id_user` (`id_user`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `manufacturers`
|
||||
--
|
||||
ALTER TABLE `manufacturers`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `manufacturers_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `orderdetails`
|
||||
--
|
||||
ALTER TABLE `orderdetails`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `orderdetails_part_id_k` (`part_id`),
|
||||
ADD KEY `orderdetails_id_supplier_k` (`id_supplier`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `parts`
|
||||
--
|
||||
ALTER TABLE `parts`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `parts_id_category_k` (`id_category`),
|
||||
ADD KEY `parts_id_footprint_k` (`id_footprint`),
|
||||
ADD KEY `parts_id_storelocation_k` (`id_storelocation`),
|
||||
ADD KEY `parts_order_orderdetails_id_k` (`order_orderdetails_id`),
|
||||
ADD KEY `parts_id_manufacturer_k` (`id_manufacturer`),
|
||||
ADD KEY `favorite` (`favorite`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `pricedetails`
|
||||
--
|
||||
ALTER TABLE `pricedetails`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `pricedetails_combination_uk` (`orderdetails_id`,`min_discount_quantity`),
|
||||
ADD KEY `pricedetails_orderdetails_id_k` (`orderdetails_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `storelocations`
|
||||
--
|
||||
ALTER TABLE `storelocations`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `storelocations_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `suppliers`
|
||||
--
|
||||
ALTER TABLE `suppliers`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `suppliers_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `users`
|
||||
--
|
||||
ALTER TABLE `users`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `name` (`name`);
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für exportierte Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `attachements`
|
||||
--
|
||||
ALTER TABLE `attachements`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=201;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `attachement_types`
|
||||
--
|
||||
ALTER TABLE `attachement_types`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `categories`
|
||||
--
|
||||
ALTER TABLE `categories`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=123;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `devices`
|
||||
--
|
||||
ALTER TABLE `devices`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `device_parts`
|
||||
--
|
||||
ALTER TABLE `device_parts`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `footprints`
|
||||
--
|
||||
ALTER TABLE `footprints`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=82;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `groups`
|
||||
--
|
||||
ALTER TABLE `groups`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `log`
|
||||
--
|
||||
ALTER TABLE `log`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=218;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `manufacturers`
|
||||
--
|
||||
ALTER TABLE `manufacturers`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `orderdetails`
|
||||
--
|
||||
ALTER TABLE `orderdetails`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=650;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `parts`
|
||||
--
|
||||
ALTER TABLE `parts`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1171;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `pricedetails`
|
||||
--
|
||||
ALTER TABLE `pricedetails`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=437;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `storelocations`
|
||||
--
|
||||
ALTER TABLE `storelocations`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=340;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `suppliers`
|
||||
--
|
||||
ALTER TABLE `suppliers`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `users`
|
||||
--
|
||||
ALTER TABLE `users`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
|
||||
|
||||
--
|
||||
-- Constraints der exportierten Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `attachements`
|
||||
--
|
||||
ALTER TABLE `attachements`
|
||||
ADD CONSTRAINT `attachements_type_id_fk` FOREIGN KEY (`type_id`) REFERENCES `attachement_types` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `attachement_types`
|
||||
--
|
||||
ALTER TABLE `attachement_types`
|
||||
ADD CONSTRAINT `attachement_types_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `attachement_types` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `categories`
|
||||
--
|
||||
ALTER TABLE `categories`
|
||||
ADD CONSTRAINT `categories_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `categories` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `devices`
|
||||
--
|
||||
ALTER TABLE `devices`
|
||||
ADD CONSTRAINT `devices_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `devices` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `footprints`
|
||||
--
|
||||
ALTER TABLE `footprints`
|
||||
ADD CONSTRAINT `footprints_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `footprints` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `manufacturers`
|
||||
--
|
||||
ALTER TABLE `manufacturers`
|
||||
ADD CONSTRAINT `manufacturers_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `manufacturers` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `parts`
|
||||
--
|
||||
ALTER TABLE `parts`
|
||||
ADD CONSTRAINT `parts_id_footprint_fk` FOREIGN KEY (`id_footprint`) REFERENCES `footprints` (`id`),
|
||||
ADD CONSTRAINT `parts_id_manufacturer_fk` FOREIGN KEY (`id_manufacturer`) REFERENCES `manufacturers` (`id`),
|
||||
ADD CONSTRAINT `parts_id_storelocation_fk` FOREIGN KEY (`id_storelocation`) REFERENCES `storelocations` (`id`),
|
||||
ADD CONSTRAINT `parts_order_orderdetails_id_fk` FOREIGN KEY (`order_orderdetails_id`) REFERENCES `orderdetails` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `storelocations`
|
||||
--
|
||||
ALTER TABLE `storelocations`
|
||||
ADD CONSTRAINT `storelocations_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `storelocations` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `suppliers`
|
||||
--
|
||||
ALTER TABLE `suppliers`
|
||||
ADD CONSTRAINT `suppliers_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `suppliers` (`id`);
|
||||
COMMIT;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
736
.github/assets/legacy_import/db_minimal.sql
vendored
Normal file
736
.github/assets/legacy_import/db_minimal.sql
vendored
Normal file
@@ -0,0 +1,736 @@
|
||||
-- phpMyAdmin SQL Dump
|
||||
-- version 5.1.3
|
||||
-- https://www.phpmyadmin.net/
|
||||
--
|
||||
-- Host: 127.0.0.1
|
||||
-- Erstellungszeit: 07. Mai 2023 um 01:48
|
||||
-- Server-Version: 10.6.5-MariaDB-log
|
||||
-- PHP-Version: 8.1.2
|
||||
|
||||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||
START TRANSACTION;
|
||||
SET time_zone = "+00:00";
|
||||
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
|
||||
--
|
||||
-- Datenbank: `partdb-legacy`
|
||||
--
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `attachements`
|
||||
--
|
||||
|
||||
CREATE TABLE `attachements` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`class_name` varchar(255) COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`element_id` int(11) NOT NULL,
|
||||
`type_id` int(11) NOT NULL,
|
||||
`filename` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`show_in_table` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `attachement_types`
|
||||
--
|
||||
|
||||
CREATE TABLE `attachement_types` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `attachement_types`
|
||||
--
|
||||
|
||||
INSERT INTO `attachement_types` (`id`, `name`, `parent_id`, `comment`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'Bilder', NULL, NULL, '2023-01-07 18:31:48', '0000-00-00 00:00:00'),
|
||||
(2, 'Datenblätter', NULL, NULL, '2023-01-07 18:31:48', '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `categories`
|
||||
--
|
||||
|
||||
CREATE TABLE `categories` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`disable_footprints` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`disable_manufacturers` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`disable_autodatasheets` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`disable_properties` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`partname_regex` text COLLATE utf8mb3_unicode_ci NOT NULL DEFAULT '',
|
||||
`partname_hint` text COLLATE utf8mb3_unicode_ci NOT NULL DEFAULT '',
|
||||
`default_description` text COLLATE utf8mb3_unicode_ci NOT NULL DEFAULT '',
|
||||
`default_comment` text COLLATE utf8mb3_unicode_ci NOT NULL DEFAULT '',
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `categories`
|
||||
--
|
||||
|
||||
INSERT INTO `categories` (`id`, `name`, `parent_id`, `disable_footprints`, `disable_manufacturers`, `disable_autodatasheets`, `disable_properties`, `partname_regex`, `partname_hint`, `default_description`, `default_comment`, `comment`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'Test', NULL, 0, 0, 0, 0, '', '', '', '', '', '2023-01-07 18:32:29', '2023-01-07 18:32:29');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `devices`
|
||||
--
|
||||
|
||||
CREATE TABLE `devices` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`order_quantity` int(11) NOT NULL DEFAULT 0,
|
||||
`order_only_missing_parts` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `device_parts`
|
||||
--
|
||||
|
||||
CREATE TABLE `device_parts` (
|
||||
`id` int(11) NOT NULL,
|
||||
`id_part` int(11) NOT NULL DEFAULT 0,
|
||||
`id_device` int(11) NOT NULL DEFAULT 0,
|
||||
`quantity` int(11) NOT NULL DEFAULT 0,
|
||||
`mountnames` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `footprints`
|
||||
--
|
||||
|
||||
CREATE TABLE `footprints` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`filename` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`filename_3d` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `groups`
|
||||
--
|
||||
|
||||
CREATE TABLE `groups` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(32) NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`comment` mediumtext DEFAULT NULL,
|
||||
`perms_system` int(11) NOT NULL,
|
||||
`perms_groups` int(11) NOT NULL,
|
||||
`perms_users` int(11) NOT NULL,
|
||||
`perms_self` int(11) NOT NULL,
|
||||
`perms_system_config` int(11) NOT NULL,
|
||||
`perms_system_database` int(11) NOT NULL,
|
||||
`perms_parts` bigint(11) NOT NULL,
|
||||
`perms_parts_name` smallint(6) NOT NULL,
|
||||
`perms_parts_description` smallint(6) NOT NULL,
|
||||
`perms_parts_instock` smallint(6) NOT NULL,
|
||||
`perms_parts_mininstock` smallint(6) NOT NULL,
|
||||
`perms_parts_footprint` smallint(6) NOT NULL,
|
||||
`perms_parts_storelocation` smallint(6) NOT NULL,
|
||||
`perms_parts_manufacturer` smallint(6) NOT NULL,
|
||||
`perms_parts_comment` smallint(6) NOT NULL,
|
||||
`perms_parts_order` smallint(6) NOT NULL,
|
||||
`perms_parts_orderdetails` smallint(6) NOT NULL,
|
||||
`perms_parts_prices` smallint(6) NOT NULL,
|
||||
`perms_parts_attachements` smallint(6) NOT NULL,
|
||||
`perms_devices` int(11) NOT NULL,
|
||||
`perms_devices_parts` int(11) NOT NULL,
|
||||
`perms_storelocations` int(11) NOT NULL,
|
||||
`perms_footprints` int(11) NOT NULL,
|
||||
`perms_categories` int(11) NOT NULL,
|
||||
`perms_suppliers` int(11) NOT NULL,
|
||||
`perms_manufacturers` int(11) NOT NULL,
|
||||
`perms_attachement_types` int(11) NOT NULL,
|
||||
`perms_tools` int(11) NOT NULL,
|
||||
`perms_labels` smallint(6) NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `groups`
|
||||
--
|
||||
|
||||
INSERT INTO `groups` (`id`, `name`, `parent_id`, `comment`, `perms_system`, `perms_groups`, `perms_users`, `perms_self`, `perms_system_config`, `perms_system_database`, `perms_parts`, `perms_parts_name`, `perms_parts_description`, `perms_parts_instock`, `perms_parts_mininstock`, `perms_parts_footprint`, `perms_parts_storelocation`, `perms_parts_manufacturer`, `perms_parts_comment`, `perms_parts_order`, `perms_parts_orderdetails`, `perms_parts_prices`, `perms_parts_attachements`, `perms_devices`, `perms_devices_parts`, `perms_storelocations`, `perms_footprints`, `perms_categories`, `perms_suppliers`, `perms_manufacturers`, `perms_attachement_types`, `perms_tools`, `perms_labels`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'admins', NULL, 'Users of this group can do everything: Read, Write and Administrative actions.', 21, 1365, 87381, 85, 85, 21, 1431655765, 5, 5, 5, 5, 5, 5, 5, 5, 5, 325, 325, 325, 5461, 325, 5461, 5461, 5461, 5461, 5461, 1365, 1365, 85, '2023-01-07 18:31:48', '0000-00-00 00:00:00'),
|
||||
(2, 'readonly', NULL, 'Users of this group can only read informations, use tools, and don\'t have access to administrative tools.', 42, 2730, 174762, 154, 170, 42, -1516939607, 9, 9, 9, 9, 9, 9, 9, 9, 9, 649, 649, 649, 1705, 649, 1705, 1705, 1705, 1705, 1705, 681, 1366, 165, '2023-01-07 18:31:48', '0000-00-00 00:00:00'),
|
||||
(3, 'users', NULL, 'Users of this group, can edit part informations, create new ones, etc. but are not allowed to use administrative tools. (But can read current configuration, and see Server status)', 42, 2730, 109226, 89, 105, 41, 1431655765, 5, 5, 5, 5, 5, 5, 5, 5, 5, 325, 325, 325, 5461, 325, 5461, 5461, 5461, 5461, 5461, 1365, 1365, 85, '2023-01-07 18:31:48', '0000-00-00 00:00:00');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `internal`
|
||||
--
|
||||
|
||||
CREATE TABLE `internal` (
|
||||
`keyName` char(30) CHARACTER SET ascii NOT NULL,
|
||||
`keyValue` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `internal`
|
||||
--
|
||||
|
||||
INSERT INTO `internal` (`keyName`, `keyValue`) VALUES
|
||||
('dbVersion', '26');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `log`
|
||||
--
|
||||
|
||||
CREATE TABLE `log` (
|
||||
`id` int(11) NOT NULL,
|
||||
`datetime` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`id_user` int(11) NOT NULL,
|
||||
`level` tinyint(4) NOT NULL,
|
||||
`type` smallint(6) NOT NULL,
|
||||
`target_id` int(11) NOT NULL,
|
||||
`target_type` smallint(6) NOT NULL,
|
||||
`extra` mediumtext NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `log`
|
||||
--
|
||||
|
||||
INSERT INTO `log` (`id`, `datetime`, `id_user`, `level`, `type`, `target_id`, `target_type`, `extra`) VALUES
|
||||
(1, '2023-01-07 18:31:48', 1, 4, 10, 0, 0, '{\"o\":0,\"n\":26,\"s\":true}'),
|
||||
(2, '2023-01-07 18:32:13', 2, 6, 1, 2, 1, '{\"i\":\"::\"}'),
|
||||
(3, '2023-01-07 18:32:29', 2, 6, 6, 1, 4, '[]'),
|
||||
(4, '2023-01-07 18:32:53', 2, 6, 6, 1, 12, '[]'),
|
||||
(5, '2023-01-07 18:33:26', 2, 6, 6, 1, 10, '{\"i\":0}');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `manufacturers`
|
||||
--
|
||||
|
||||
CREATE TABLE `manufacturers` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`address` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`phone_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`fax_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`email_address` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`website` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`auto_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `orderdetails`
|
||||
--
|
||||
|
||||
CREATE TABLE `orderdetails` (
|
||||
`id` int(11) NOT NULL,
|
||||
`part_id` int(11) NOT NULL,
|
||||
`id_supplier` int(11) NOT NULL DEFAULT 0,
|
||||
`supplierpartnr` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`obsolete` tinyint(1) DEFAULT 0,
|
||||
`supplier_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp()
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `orderdetails`
|
||||
--
|
||||
|
||||
INSERT INTO `orderdetails` (`id`, `part_id`, `id_supplier`, `supplierpartnr`, `obsolete`, `supplier_product_url`, `datetime_added`) VALUES
|
||||
(1, 1, 1, 'BC547', 0, '', '2023-01-07 18:45:59'),
|
||||
(2, 1, 1, 'Test', 0, '', '2023-01-07 18:46:09');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `parts`
|
||||
--
|
||||
|
||||
CREATE TABLE `parts` (
|
||||
`id` int(11) NOT NULL,
|
||||
`id_category` int(11) NOT NULL DEFAULT 0,
|
||||
`name` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`description` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`instock` int(11) NOT NULL DEFAULT 0,
|
||||
`mininstock` int(11) NOT NULL DEFAULT 0,
|
||||
`comment` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`visible` tinyint(1) NOT NULL,
|
||||
`id_footprint` int(11) DEFAULT NULL,
|
||||
`id_storelocation` int(11) DEFAULT NULL,
|
||||
`order_orderdetails_id` int(11) DEFAULT NULL,
|
||||
`order_quantity` int(11) NOT NULL DEFAULT 1,
|
||||
`manual_order` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`id_manufacturer` int(11) DEFAULT NULL,
|
||||
`id_master_picture_attachement` int(11) DEFAULT NULL,
|
||||
`manufacturer_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
|
||||
`favorite` tinyint(1) NOT NULL DEFAULT 0
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `parts`
|
||||
--
|
||||
|
||||
INSERT INTO `parts` (`id`, `id_category`, `name`, `description`, `instock`, `mininstock`, `comment`, `visible`, `id_footprint`, `id_storelocation`, `order_orderdetails_id`, `order_quantity`, `manual_order`, `id_manufacturer`, `id_master_picture_attachement`, `manufacturer_product_url`, `datetime_added`, `last_modified`, `favorite`) VALUES
|
||||
(1, 1, 'BC547', '', 0, 0, '', 0, NULL, NULL, NULL, 1, 0, NULL, NULL, '', '2023-01-07 18:33:26', '2023-01-07 18:33:26', 0);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `pricedetails`
|
||||
--
|
||||
|
||||
CREATE TABLE `pricedetails` (
|
||||
`id` int(11) NOT NULL,
|
||||
`orderdetails_id` int(11) NOT NULL,
|
||||
`price` decimal(11,5) DEFAULT NULL,
|
||||
`price_related_quantity` int(11) NOT NULL DEFAULT 1,
|
||||
`min_discount_quantity` int(11) NOT NULL DEFAULT 1,
|
||||
`manual_input` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`last_modified` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `pricedetails`
|
||||
--
|
||||
|
||||
INSERT INTO `pricedetails` (`id`, `orderdetails_id`, `price`, `price_related_quantity`, `min_discount_quantity`, `manual_input`, `last_modified`) VALUES
|
||||
(1, 2, '3.55000', 1, 1, 1, '2023-01-07 18:46:19');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `storelocations`
|
||||
--
|
||||
|
||||
CREATE TABLE `storelocations` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`is_full` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `suppliers`
|
||||
--
|
||||
|
||||
CREATE TABLE `suppliers` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`parent_id` int(11) DEFAULT NULL,
|
||||
`address` mediumtext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`phone_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`fax_number` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`email_address` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`website` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`auto_product_url` tinytext COLLATE utf8mb3_unicode_ci NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`comment` text COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `suppliers`
|
||||
--
|
||||
|
||||
INSERT INTO `suppliers` (`id`, `name`, `parent_id`, `address`, `phone_number`, `fax_number`, `email_address`, `website`, `auto_product_url`, `datetime_added`, `comment`, `last_modified`) VALUES
|
||||
(1, 'Reichelt', NULL, '', '', '', '', '', '', '2023-01-07 18:32:53', '', '2023-01-07 18:32:53');
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Tabellenstruktur für Tabelle `users`
|
||||
--
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` int(11) NOT NULL,
|
||||
`name` varchar(32) NOT NULL,
|
||||
`password` varchar(255) DEFAULT NULL,
|
||||
`first_name` tinytext DEFAULT NULL,
|
||||
`last_name` tinytext DEFAULT NULL,
|
||||
`department` tinytext DEFAULT NULL,
|
||||
`email` tinytext DEFAULT NULL,
|
||||
`need_pw_change` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`group_id` int(11) DEFAULT NULL,
|
||||
`config_language` tinytext DEFAULT NULL,
|
||||
`config_timezone` tinytext DEFAULT NULL,
|
||||
`config_theme` tinytext DEFAULT NULL,
|
||||
`config_currency` tinytext DEFAULT NULL,
|
||||
`config_image_path` text NOT NULL,
|
||||
`config_instock_comment_w` text NOT NULL,
|
||||
`config_instock_comment_a` text NOT NULL,
|
||||
`perms_system` int(11) NOT NULL,
|
||||
`perms_groups` int(11) NOT NULL,
|
||||
`perms_users` int(11) NOT NULL,
|
||||
`perms_self` int(11) NOT NULL,
|
||||
`perms_system_config` int(11) NOT NULL,
|
||||
`perms_system_database` int(11) NOT NULL,
|
||||
`perms_parts` bigint(11) NOT NULL,
|
||||
`perms_parts_name` smallint(6) NOT NULL,
|
||||
`perms_parts_description` smallint(6) NOT NULL,
|
||||
`perms_parts_instock` smallint(6) NOT NULL,
|
||||
`perms_parts_mininstock` smallint(6) NOT NULL,
|
||||
`perms_parts_footprint` smallint(6) NOT NULL,
|
||||
`perms_parts_storelocation` smallint(6) NOT NULL,
|
||||
`perms_parts_manufacturer` smallint(6) NOT NULL,
|
||||
`perms_parts_comment` smallint(6) NOT NULL,
|
||||
`perms_parts_order` smallint(6) NOT NULL,
|
||||
`perms_parts_orderdetails` smallint(6) NOT NULL,
|
||||
`perms_parts_prices` smallint(6) NOT NULL,
|
||||
`perms_parts_attachements` smallint(6) NOT NULL,
|
||||
`perms_devices` int(11) NOT NULL,
|
||||
`perms_devices_parts` int(11) NOT NULL,
|
||||
`perms_storelocations` int(11) NOT NULL,
|
||||
`perms_footprints` int(11) NOT NULL,
|
||||
`perms_categories` int(11) NOT NULL,
|
||||
`perms_suppliers` int(11) NOT NULL,
|
||||
`perms_manufacturers` int(11) NOT NULL,
|
||||
`perms_attachement_types` int(11) NOT NULL,
|
||||
`perms_tools` int(11) NOT NULL,
|
||||
`perms_labels` smallint(6) NOT NULL,
|
||||
`datetime_added` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`last_modified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
--
|
||||
-- Daten für Tabelle `users`
|
||||
--
|
||||
|
||||
INSERT INTO `users` (`id`, `name`, `password`, `first_name`, `last_name`, `department`, `email`, `need_pw_change`, `group_id`, `config_language`, `config_timezone`, `config_theme`, `config_currency`, `config_image_path`, `config_instock_comment_w`, `config_instock_comment_a`, `perms_system`, `perms_groups`, `perms_users`, `perms_self`, `perms_system_config`, `perms_system_database`, `perms_parts`, `perms_parts_name`, `perms_parts_description`, `perms_parts_instock`, `perms_parts_mininstock`, `perms_parts_footprint`, `perms_parts_storelocation`, `perms_parts_manufacturer`, `perms_parts_comment`, `perms_parts_order`, `perms_parts_orderdetails`, `perms_parts_prices`, `perms_parts_attachements`, `perms_devices`, `perms_devices_parts`, `perms_storelocations`, `perms_footprints`, `perms_categories`, `perms_suppliers`, `perms_manufacturers`, `perms_attachement_types`, `perms_tools`, `perms_labels`, `datetime_added`, `last_modified`) VALUES
|
||||
(1, 'anonymous', '', '', '', '', '', 0, 2, NULL, NULL, NULL, NULL, '', '', '', 21844, 20480, 0, 0, 0, 0, 0, 21840, 21840, 21840, 21840, 21840, 21840, 21840, 21840, 21840, 21520, 21520, 21520, 20480, 21520, 20480, 20480, 20480, 20480, 20480, 21504, 20480, 0, '2023-01-07 18:31:48', '0000-00-00 00:00:00'),
|
||||
(2, 'admin', '$2a$12$j0RKrKlx60bzX1DWMyXwjeaW.pe3bFjAK8ByIGnvjrRnET2JtsFoe$2a$12$j0RKrKlx60bzX1DWMyXwjeaW.pe3bFjAK8ByIGnvjrRnET2JtsFoe', '', '', '', '', 1, 1, NULL, NULL, NULL, NULL, '', '', '', 21845, 21845, 21845, 21, 85, 21, 349525, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 0, '2023-01-07 18:31:48', '0000-00-00 00:00:00');
|
||||
|
||||
--
|
||||
-- Indizes der exportierten Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `attachements`
|
||||
--
|
||||
ALTER TABLE `attachements`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `attachements_class_name_k` (`class_name`),
|
||||
ADD KEY `attachements_element_id_k` (`element_id`),
|
||||
ADD KEY `attachements_type_id_fk` (`type_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `attachement_types`
|
||||
--
|
||||
ALTER TABLE `attachement_types`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `attachement_types_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `categories`
|
||||
--
|
||||
ALTER TABLE `categories`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `categories_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `devices`
|
||||
--
|
||||
ALTER TABLE `devices`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `devices_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `device_parts`
|
||||
--
|
||||
ALTER TABLE `device_parts`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `device_parts_combination_uk` (`id_part`,`id_device`),
|
||||
ADD KEY `device_parts_id_part_k` (`id_part`),
|
||||
ADD KEY `device_parts_id_device_k` (`id_device`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `footprints`
|
||||
--
|
||||
ALTER TABLE `footprints`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `footprints_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `groups`
|
||||
--
|
||||
ALTER TABLE `groups`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `name` (`name`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `internal`
|
||||
--
|
||||
ALTER TABLE `internal`
|
||||
ADD UNIQUE KEY `keyName` (`keyName`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `log`
|
||||
--
|
||||
ALTER TABLE `log`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `id_user` (`id_user`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `manufacturers`
|
||||
--
|
||||
ALTER TABLE `manufacturers`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `manufacturers_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `orderdetails`
|
||||
--
|
||||
ALTER TABLE `orderdetails`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `orderdetails_part_id_k` (`part_id`),
|
||||
ADD KEY `orderdetails_id_supplier_k` (`id_supplier`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `parts`
|
||||
--
|
||||
ALTER TABLE `parts`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `parts_id_category_k` (`id_category`),
|
||||
ADD KEY `parts_id_footprint_k` (`id_footprint`),
|
||||
ADD KEY `parts_id_storelocation_k` (`id_storelocation`),
|
||||
ADD KEY `parts_order_orderdetails_id_k` (`order_orderdetails_id`),
|
||||
ADD KEY `parts_id_manufacturer_k` (`id_manufacturer`),
|
||||
ADD KEY `favorite` (`favorite`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `pricedetails`
|
||||
--
|
||||
ALTER TABLE `pricedetails`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `pricedetails_combination_uk` (`orderdetails_id`,`min_discount_quantity`),
|
||||
ADD KEY `pricedetails_orderdetails_id_k` (`orderdetails_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `storelocations`
|
||||
--
|
||||
ALTER TABLE `storelocations`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `storelocations_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `suppliers`
|
||||
--
|
||||
ALTER TABLE `suppliers`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD KEY `suppliers_parent_id_k` (`parent_id`);
|
||||
|
||||
--
|
||||
-- Indizes für die Tabelle `users`
|
||||
--
|
||||
ALTER TABLE `users`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `name` (`name`);
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für exportierte Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `attachements`
|
||||
--
|
||||
ALTER TABLE `attachements`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `attachement_types`
|
||||
--
|
||||
ALTER TABLE `attachement_types`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `categories`
|
||||
--
|
||||
ALTER TABLE `categories`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `devices`
|
||||
--
|
||||
ALTER TABLE `devices`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `device_parts`
|
||||
--
|
||||
ALTER TABLE `device_parts`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `footprints`
|
||||
--
|
||||
ALTER TABLE `footprints`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `groups`
|
||||
--
|
||||
ALTER TABLE `groups`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `log`
|
||||
--
|
||||
ALTER TABLE `log`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `manufacturers`
|
||||
--
|
||||
ALTER TABLE `manufacturers`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `orderdetails`
|
||||
--
|
||||
ALTER TABLE `orderdetails`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `parts`
|
||||
--
|
||||
ALTER TABLE `parts`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `pricedetails`
|
||||
--
|
||||
ALTER TABLE `pricedetails`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `storelocations`
|
||||
--
|
||||
ALTER TABLE `storelocations`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `suppliers`
|
||||
--
|
||||
ALTER TABLE `suppliers`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2;
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT für Tabelle `users`
|
||||
--
|
||||
ALTER TABLE `users`
|
||||
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
|
||||
|
||||
--
|
||||
-- Constraints der exportierten Tabellen
|
||||
--
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `attachements`
|
||||
--
|
||||
ALTER TABLE `attachements`
|
||||
ADD CONSTRAINT `attachements_type_id_fk` FOREIGN KEY (`type_id`) REFERENCES `attachement_types` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `attachement_types`
|
||||
--
|
||||
ALTER TABLE `attachement_types`
|
||||
ADD CONSTRAINT `attachement_types_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `attachement_types` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `categories`
|
||||
--
|
||||
ALTER TABLE `categories`
|
||||
ADD CONSTRAINT `categories_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `categories` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `devices`
|
||||
--
|
||||
ALTER TABLE `devices`
|
||||
ADD CONSTRAINT `devices_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `devices` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `footprints`
|
||||
--
|
||||
ALTER TABLE `footprints`
|
||||
ADD CONSTRAINT `footprints_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `footprints` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `manufacturers`
|
||||
--
|
||||
ALTER TABLE `manufacturers`
|
||||
ADD CONSTRAINT `manufacturers_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `manufacturers` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `parts`
|
||||
--
|
||||
ALTER TABLE `parts`
|
||||
ADD CONSTRAINT `parts_id_footprint_fk` FOREIGN KEY (`id_footprint`) REFERENCES `footprints` (`id`),
|
||||
ADD CONSTRAINT `parts_id_manufacturer_fk` FOREIGN KEY (`id_manufacturer`) REFERENCES `manufacturers` (`id`),
|
||||
ADD CONSTRAINT `parts_id_storelocation_fk` FOREIGN KEY (`id_storelocation`) REFERENCES `storelocations` (`id`),
|
||||
ADD CONSTRAINT `parts_order_orderdetails_id_fk` FOREIGN KEY (`order_orderdetails_id`) REFERENCES `orderdetails` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `storelocations`
|
||||
--
|
||||
ALTER TABLE `storelocations`
|
||||
ADD CONSTRAINT `storelocations_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `storelocations` (`id`);
|
||||
|
||||
--
|
||||
-- Constraints der Tabelle `suppliers`
|
||||
--
|
||||
ALTER TABLE `suppliers`
|
||||
ADD CONSTRAINT `suppliers_parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `suppliers` (`id`);
|
||||
COMMIT;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
54
.github/assets/legacy_import/test_legacy_import.sh
vendored
Normal file
54
.github/assets/legacy_import/test_legacy_import.sh
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
#
|
||||
# This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
#
|
||||
# Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# This script is used to test the legacy import of Part-DB
|
||||
|
||||
SQL_FILES_TO_TEST=("db_minimal.sql" "db_jbtronics.sql")
|
||||
|
||||
DB_NAME="legacy_db_test"
|
||||
DB_USER="root"
|
||||
DB_PASSWORD="root"
|
||||
|
||||
# Iterate over all given SQL files and import them into the mysql database with the given name, drop the database if it already exists before
|
||||
for SQL_FILE in "${SQL_FILES_TO_TEST[@]}"
|
||||
do
|
||||
echo "Testing for $SQL_FILE"
|
||||
mysql -u $DB_USER --password=$DB_PASSWORD -e "DROP DATABASE IF EXISTS $DB_NAME; CREATE DATABASE $DB_NAME;"
|
||||
# If the last command failed, exit the script
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to create database $DB_NAME"
|
||||
exit 1
|
||||
fi
|
||||
# Import the SQL file into the database. The file pathes are relative to the current script location
|
||||
mysql -u $DB_USER --password=$DB_PASSWORD $DB_NAME < .github/assets/legacy_import/$SQL_FILE
|
||||
# If the last command failed, exit the script
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to import $SQL_FILE into database $DB_NAME"
|
||||
exit 1
|
||||
fi
|
||||
# Run doctrine migrations, this will migrate the database to the current version. This process should not fail
|
||||
php bin/console doctrine:migrations:migrate -n
|
||||
# If the last command failed, exit the script
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to migrate database $DB_NAME"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
54
.github/workflows/codeql-analysis.yml
vendored
54
.github/workflows/codeql-analysis.yml
vendored
@@ -1,54 +0,0 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 14 * * 3'
|
||||
|
||||
jobs:
|
||||
analyse:
|
||||
name: Analyse
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
8
.github/workflows/tests.yml
vendored
8
.github/workflows/tests.yml
vendored
@@ -130,4 +130,12 @@ jobs:
|
||||
|
||||
- name: Test check-requirements command
|
||||
run: php bin/console partdb:check-requirements -n
|
||||
|
||||
- name: Test legacy Part-DB import
|
||||
run: bash .github/assets/legacy_import/test_legacy_import.sh
|
||||
if: matrix.db-type == 'mysql' && matrix.php-versions == '8.2'
|
||||
env:
|
||||
DATABASE_URL: mysql://root:root@localhost:3306/legacy_db
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ export default class extends Controller
|
||||
const title = this.element.dataset.deleteTitle;
|
||||
|
||||
const form = this.element;
|
||||
const submitter = event.submitter;
|
||||
const that = this;
|
||||
|
||||
const confirm = bootbox.confirm({
|
||||
@@ -58,6 +59,14 @@ export default class extends Controller
|
||||
const submit_btn = document.createElement('button');
|
||||
submit_btn.type = 'submit';
|
||||
submit_btn.style.display = 'none';
|
||||
|
||||
//If the clicked button has a value, set it on the submit button
|
||||
if (submitter.value) {
|
||||
submit_btn.value = submitter.value;
|
||||
}
|
||||
if (submitter.name) {
|
||||
submit_btn.name = submitter.name;
|
||||
}
|
||||
form.appendChild(submit_btn);
|
||||
submit_btn.click();
|
||||
} else {
|
||||
|
||||
40
assets/controllers/elements/json_formatter_controller.js
Normal file
40
assets/controllers/elements/json_formatter_controller.js
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import {Controller} from "@hotwired/stimulus";
|
||||
|
||||
import JSONFormatter from 'json-formatter-js';
|
||||
|
||||
/**
|
||||
* This controller implements an element that renders a JSON object as a collapsible tree.
|
||||
* The JSON object is passed as a data attribute.
|
||||
* You have to apply the controller to a div element or similar block element which can contain other elements.
|
||||
*/
|
||||
export default class extends Controller {
|
||||
connect() {
|
||||
const depth_to_open = this.element.dataset.depthToOpen ?? 0;
|
||||
const json_string = this.element.dataset.json;
|
||||
const json_object = JSON.parse(json_string);
|
||||
|
||||
const formatter = new JSONFormatter(json_object, depth_to_open);
|
||||
|
||||
this.element.appendChild(formatter.render());
|
||||
}
|
||||
}
|
||||
@@ -105,4 +105,19 @@ form .col-form-label.required:after, form label.required:after {
|
||||
position: relative;
|
||||
right: -2px;
|
||||
z-index: 700;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* HTML diff styling
|
||||
****************************************/
|
||||
|
||||
/* Insertations are marked with green background and bold */
|
||||
ins {
|
||||
background-color: #95f095;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
del {
|
||||
background-color: #f09595;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -4,16 +4,17 @@
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-intl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-dom": "*",
|
||||
"beberlei/doctrineextensions": "^1.2",
|
||||
"brick/math": "^0.8.15",
|
||||
"composer/package-versions-deprecated": "1.11.99.4",
|
||||
"doctrine/annotations": "^1.6",
|
||||
"doctrine/data-fixtures": "^1.6.6",
|
||||
"doctrine/dbal": "^3.4.6",
|
||||
"doctrine/doctrine-bundle": "^2.0",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||
@@ -25,6 +26,7 @@
|
||||
"gregwar/captcha-bundle": "^2.1.0",
|
||||
"hslavich/oneloginsaml-bundle": "^2.10",
|
||||
"jbtronics/2fa-webauthn": "^1.0.0",
|
||||
"jfcherng/php-diff": "^6.14",
|
||||
"league/csv": "^9.8.0",
|
||||
"league/html-to-markdown": "^5.0.1",
|
||||
"liip/imagine-bundle": "^2.2",
|
||||
@@ -33,7 +35,7 @@
|
||||
"nyholm/psr7": "^1.1",
|
||||
"ocramius/proxy-manager": "2.2.*",
|
||||
"omines/datatables-bundle": "^0.5.0",
|
||||
"php-translation/symfony-bundle": "^0.12.0",
|
||||
"php-translation/symfony-bundle": "^0.13.0",
|
||||
"phpdocumentor/reflection-docblock": "^5.2",
|
||||
"s9e/text-formatter": "^2.1",
|
||||
"scheb/2fa-backup-code": "^5.13",
|
||||
@@ -82,7 +84,6 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"dama/doctrine-test-bundle": "^7.0",
|
||||
"doctrine/doctrine-fixtures-bundle": "^3.2",
|
||||
"ekino/phpstan-banned-code": "^v1.0.0",
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "^1.4.7",
|
||||
@@ -98,7 +99,8 @@
|
||||
"symfony/stopwatch": "^5.2",
|
||||
"symfony/web-profiler-bundle": "^5.2",
|
||||
"symplify/easy-coding-standard": "^11.0",
|
||||
"vimeo/psalm": "^5.6.0"
|
||||
"vimeo/psalm": "^5.6.0",
|
||||
"doctrine/doctrine-fixtures-bundle": "^3.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Used to improve price calculation performance",
|
||||
|
||||
934
composer.lock
generated
934
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -125,3 +125,9 @@ parameters:
|
||||
env(DEFAULT_URI): 'https://partdb.changeme.invalid/'
|
||||
|
||||
env(SAML_ROLE_MAPPING): '{}'
|
||||
|
||||
env(HISTORY_SAVE_CHANGED_DATA): 1
|
||||
env(HISTORY_SAVE_CHANGED_FIELDS): 1
|
||||
env(HISTORY_SAVE_REMOVED_DATA): 1
|
||||
env(HISTORY_SAVE_NEW_DATA): 1
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ services:
|
||||
$save_changed_fields: '%env(bool:HISTORY_SAVE_CHANGED_FIELDS)%'
|
||||
$save_changed_data: '%env(bool:HISTORY_SAVE_CHANGED_DATA)%'
|
||||
$save_removed_data: '%env(bool:HISTORY_SAVE_REMOVED_DATA)%'
|
||||
$save_new_data: '%env(bool:HISTORY_SAVE_NEW_DATA)%'
|
||||
tags:
|
||||
- { name: 'doctrine.event_subscriber' }
|
||||
|
||||
|
||||
@@ -46,8 +46,9 @@ The following configuration options can only be changed by the server administra
|
||||
### History/Eventlog related settings
|
||||
The following options are used to configure, which (and how much) data is written to the system log:
|
||||
* `HISTORY_SAVE_CHANGED_FIELDS`: When this option is set to true, the name of the fields which are changed, are saved to the DB (so for example it is logged that a user has changed, that the user has changed the name and description of the field, but not the data/content of these changes)
|
||||
* `HISTORY_SAVE_CHANGED_DATA`: When this option is set to true, the changed data is saved to log (so it is logged, that a user has changed the name of a part and what the name was before). This can increase database size, when you have a lot of changes to enties.
|
||||
* `HISTORY_SAVE_CHANGED_DATA`: When this option is set to true, the changed data is saved to log (so it is logged, that a user has changed the name of a part and what the name was before). This can increase database size, when you have a lot of changes to entities.
|
||||
* `HISTORY_SAVE_REMOVED_DATA`: When this option is set to true, removed data is saved to log, meaning that you can easily undelete an entity, when it was removed accidentally.
|
||||
* `HISTORY_SAVE_NEW_DATA`: When this option is set to true, the new data (the data after a change) is saved to element changed log entries. This allows you to easily see the changes between two revisions of an entity. This can increase database size, when you have a lot of changes to entities.
|
||||
|
||||
If you wanna use want to revert changes or view older revisions of entities, then `HISTORY_SAVE_CHANGED_FIELDS`, `HISTORY_SAVE_CHANGED_DATA` and `HISTORY_SAVE_REMOVED_DATA` all have to be true.
|
||||
|
||||
|
||||
@@ -125,7 +125,8 @@ final class Version20190902140506 extends AbstractMultiPlatformMigration
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON parts (id_manufacturer)');
|
||||
$this->addSql('ALTER TABLE parts ADD CONSTRAINT parts_id_footprint_fk FOREIGN KEY (id_footprint) REFERENCES footprints (id)');
|
||||
$this->addSql('ALTER TABLE parts ADD CONSTRAINT parts_id_manufacturer_fk FOREIGN KEY (id_manufacturer) REFERENCES manufacturers (id)');
|
||||
if ($this->doesFKExists('attachment_types', 'attachement_types_parent_id_fk')) {
|
||||
//We have to use the old table name here, because the if is executed before any sql command added by addSQL is executed (and thus the table name is not changed yet)
|
||||
if ($this->doesFKExists('attachement_types', 'attachement_types_parent_id_fk')) {
|
||||
$this->addSql('ALTER TABLE attachment_types DROP FOREIGN KEY attachement_types_parent_id_fk');
|
||||
}
|
||||
$this->addSql('ALTER TABLE attachment_types ADD filetype_filter LONGTEXT NOT NULL, ADD not_selectable TINYINT(1) NOT NULL, CHANGE name name VARCHAR(255) NOT NULL, CHANGE comment comment LONGTEXT NOT NULL, CHANGE last_modified last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL');
|
||||
@@ -179,7 +180,8 @@ final class Version20190902140506 extends AbstractMultiPlatformMigration
|
||||
$this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON suppliers (parent_id)');
|
||||
$this->addSql('ALTER TABLE suppliers ADD CONSTRAINT suppliers_parent_id_fk FOREIGN KEY (parent_id) REFERENCES suppliers (id)');
|
||||
$this->addSql('DROP INDEX attachements_class_name_k ON attachments');
|
||||
if ($this->doesFKExists('attachments', 'attachements_type_id_fk')) {
|
||||
//We have to use the old table name here, because the if is executed before any sql command added by addSQL is executed (and thus the table name is not changed yet)
|
||||
if ($this->doesFKExists('attachements', 'attachements_type_id_fk')) {
|
||||
$this->addSql('ALTER TABLE attachments DROP FOREIGN KEY attachements_type_id_fk');
|
||||
}
|
||||
$this->addSql('ALTER TABLE attachments ADD datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CHANGE type_id type_id INT DEFAULT NULL, CHANGE name name VARCHAR(255) NOT NULL, CHANGE filename filename VARCHAR(255) NOT NULL, CHANGE show_in_table show_in_table TINYINT(1) NOT NULL, CHANGE last_modified last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL');
|
||||
|
||||
@@ -71,7 +71,10 @@ final class Version20220925162725 extends AbstractMultiPlatformMigration
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE INDEX attachment_types_idx_name ON attachment_types (name)');
|
||||
$this->addSql('CREATE INDEX attachment_types_idx_parent_name ON attachment_types (parent_id, name)');
|
||||
//We have to disable foreign key checks here, or we get a error on MySQL for legacy database migration. On MariaDB this works fine (with enabled foreign key checks), so I guess this is not so bad...
|
||||
$this->addSql('SET foreign_key_checks = 0');
|
||||
$this->addSql('ALTER TABLE attachments CHANGE type_id type_id INT NOT NULL');
|
||||
$this->addSql('SET foreign_key_checks = 1');
|
||||
$this->addSql('CREATE INDEX attachments_idx_id_element_id_class_name ON attachments (id, element_id, class_name)');
|
||||
$this->addSql('CREATE INDEX attachments_idx_class_name_id ON attachments (class_name, id)');
|
||||
$this->addSql('CREATE INDEX attachment_name_idx ON attachments (name)');
|
||||
|
||||
69
package.json
69
package.json
@@ -28,38 +28,38 @@
|
||||
"build": "encore production --progress"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ckeditor/ckeditor5-alignment": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-autoformat": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-basic-styles": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-block-quote": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-code-block": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-dev-utils": "^33.0.0",
|
||||
"@ckeditor/ckeditor5-alignment": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-autoformat": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-basic-styles": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-block-quote": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-code-block": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-dev-utils": "^37.0.0",
|
||||
"@ckeditor/ckeditor5-dev-webpack-plugin": "^31.1.13",
|
||||
"@ckeditor/ckeditor5-editor-classic": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-essentials": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-find-and-replace": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-font": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-heading": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-highlight": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-horizontal-line": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-html-embed": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-html-support": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-image": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-indent": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-link": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-list": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-markdown-gfm": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-media-embed": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-paragraph": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-paste-from-office": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-remove-format": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-source-editing": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-special-characters": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-table": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-theme-lark": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-upload": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-watchdog": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-word-count": "^36.0.0",
|
||||
"@ckeditor/ckeditor5-editor-classic": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-essentials": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-find-and-replace": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-font": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-heading": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-highlight": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-horizontal-line": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-html-embed": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-html-support": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-image": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-indent": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-link": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-list": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-markdown-gfm": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-media-embed": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-paragraph": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-paste-from-office": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-remove-format": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-source-editing": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-special-characters": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-table": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-theme-lark": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-upload": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-watchdog": "^37.1.0",
|
||||
"@ckeditor/ckeditor5-word-count": "^37.1.0",
|
||||
"@jbtronics/bs-treeview": "^1.0.1",
|
||||
"bootbox": "^6.0.0",
|
||||
"bootswatch": "^5.1.3",
|
||||
@@ -73,15 +73,16 @@
|
||||
"datatables.net-fixedheader-bs5": "^3.1.5",
|
||||
"datatables.net-responsive-bs5": "^2.2.3",
|
||||
"datatables.net-select-bs5": "^1.2.7",
|
||||
"dompurify": "^2.0.6",
|
||||
"dompurify": "^3.0.3",
|
||||
"emoji.json": "^14.0.0",
|
||||
"exports-loader": "^3.0.0",
|
||||
"html5-qrcode": "^2.2.1",
|
||||
"json-formatter-js": "^2.3.4",
|
||||
"jszip": "^3.2.0",
|
||||
"katex": "^0.16.0",
|
||||
"marked": "^4.0.3",
|
||||
"marked": "^4.3.0",
|
||||
"pdfmake": "^0.2.2",
|
||||
"stimulus-use": "^0.51.1",
|
||||
"stimulus-use": "^0.52.0",
|
||||
"tom-select": "^2.1.0",
|
||||
"ts-loader": "^9.2.6",
|
||||
"typescript": "^4.0.2"
|
||||
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\DataTables\Column\LogEntryTargetColumn;
|
||||
use App\DataTables\Filters\LogFilter;
|
||||
use App\DataTables\LogDataTable;
|
||||
use App\Entity\Base\AbstractDBElement;
|
||||
@@ -33,6 +34,9 @@ use App\Entity\LogSystem\ElementEditedLogEntry;
|
||||
use App\Form\Filters\LogFilterType;
|
||||
use App\Repository\DBElementRepository;
|
||||
use App\Services\LogSystem\EventUndoHelper;
|
||||
use App\Services\LogSystem\LogEntryExtraFormatter;
|
||||
use App\Services\LogSystem\LogLevelHelper;
|
||||
use App\Services\LogSystem\LogTargetHelper;
|
||||
use App\Services\LogSystem\TimeTravel;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@@ -93,6 +97,51 @@ class LogController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/details", name="log_details")
|
||||
* @param Request $request
|
||||
* @param AbstractLogEntry $logEntry
|
||||
* @return Response
|
||||
*/
|
||||
public function logDetails(Request $request, AbstractLogEntry $logEntry, LogEntryExtraFormatter $logEntryExtraFormatter,
|
||||
LogLevelHelper $logLevelHelper, LogTargetHelper $logTargetHelper, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('show_details', $logEntry);
|
||||
|
||||
$extra_html = $logEntryExtraFormatter->format($logEntry);
|
||||
$target_html = $logTargetHelper->formatTarget($logEntry);
|
||||
|
||||
$repo = $entityManager->getRepository(AbstractLogEntry::class);
|
||||
$target_element = $repo->getTargetElement($logEntry);
|
||||
|
||||
return $this->render('log_system/details/log_details.html.twig', [
|
||||
'log_entry' => $logEntry,
|
||||
'target_element' => $target_element,
|
||||
'extra_html' => $extra_html,
|
||||
'target_html' => $target_html,
|
||||
'log_level_helper' => $logLevelHelper,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/delete", name="log_delete", methods={"DELETE"})
|
||||
*/
|
||||
public function deleteLogEntry(Request $request, AbstractLogEntry $logEntry, EntityManagerInterface $entityManager): RedirectResponse
|
||||
{
|
||||
$this->denyAccessUnlessGranted('delete', $logEntry);
|
||||
|
||||
if ($this->isCsrfTokenValid('delete'.$logEntry->getId(), $request->request->get('_token'))) {
|
||||
//Remove part
|
||||
$entityManager->remove($logEntry);
|
||||
//Flush changes
|
||||
$entityManager->flush();
|
||||
$this->addFlash('success', 'log.delete.success');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('homepage');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Route("/undo", name="log_undo", methods={"POST"})
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\DataTables\ErrorDataTable;
|
||||
use App\DataTables\Filters\PartFilter;
|
||||
use App\DataTables\Filters\PartSearchFilter;
|
||||
use App\DataTables\PartsDataTable;
|
||||
@@ -30,9 +31,11 @@ use App\Entity\Parts\Footprint;
|
||||
use App\Entity\Parts\Manufacturer;
|
||||
use App\Entity\Parts\Storelocation;
|
||||
use App\Entity\Parts\Supplier;
|
||||
use App\Exceptions\InvalidRegexException;
|
||||
use App\Form\Filters\PartFilterType;
|
||||
use App\Services\Parts\PartsTableActionHandler;
|
||||
use App\Services\Trees\NodesListBuilder;
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Omines\DataTablesBundle\DataTableFactory;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@@ -41,6 +44,7 @@ use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class PartListsController extends AbstractController
|
||||
{
|
||||
@@ -48,11 +52,14 @@ class PartListsController extends AbstractController
|
||||
private NodesListBuilder $nodesListBuilder;
|
||||
private DataTableFactory $dataTableFactory;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, NodesListBuilder $nodesListBuilder, DataTableFactory $dataTableFactory)
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, NodesListBuilder $nodesListBuilder, DataTableFactory $dataTableFactory, TranslatorInterface $translator)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->nodesListBuilder = $nodesListBuilder;
|
||||
$this->dataTableFactory = $dataTableFactory;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +151,21 @@ class PartListsController extends AbstractController
|
||||
->handleRequest($request);
|
||||
|
||||
if ($table->isCallback()) {
|
||||
return $table->getResponse();
|
||||
try {
|
||||
try {
|
||||
return $table->getResponse();
|
||||
} catch (DriverException $driverException) {
|
||||
if ($driverException->getCode() === 1139) {
|
||||
//Convert the driver exception to InvalidRegexException so it has the same hanlder as for SQLite
|
||||
throw InvalidRegexException::fromDriverException($driverException);
|
||||
} else {
|
||||
throw $driverException;
|
||||
}
|
||||
}
|
||||
} catch (InvalidRegexException $exception) {
|
||||
$errors = $this->translator->trans('part.table.invalid_regex').': '.$exception->getReason();
|
||||
return ErrorDataTable::errorTable($this->dataTableFactory, $request, $errors);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render($template, array_merge([
|
||||
@@ -288,21 +309,22 @@ class PartListsController extends AbstractController
|
||||
{
|
||||
$filter = new PartSearchFilter($request->query->get('keyword', ''));
|
||||
|
||||
$filter->setName($request->query->getBoolean('name', true));
|
||||
$filter->setCategory($request->query->getBoolean('category', true));
|
||||
$filter->setDescription($request->query->getBoolean('description', true));
|
||||
$filter->setMpn($request->query->getBoolean('mpn', true));
|
||||
$filter->setTags($request->query->getBoolean('tags', true));
|
||||
$filter->setStorelocation($request->query->getBoolean('storelocation', true));
|
||||
$filter->setComment($request->query->getBoolean('comment', true));
|
||||
$filter->setIPN($request->query->getBoolean('ipn', true));
|
||||
$filter->setOrdernr($request->query->getBoolean('ordernr', true));
|
||||
$filter->setSupplier($request->query->getBoolean('supplier', false));
|
||||
$filter->setManufacturer($request->query->getBoolean('manufacturer', false));
|
||||
$filter->setFootprint($request->query->getBoolean('footprint', false));
|
||||
//As an unchecked checkbox is not set in the query, the default value for all bools have to be false (which is the default argument value)!
|
||||
$filter->setName($request->query->getBoolean('name'));
|
||||
$filter->setCategory($request->query->getBoolean('category'));
|
||||
$filter->setDescription($request->query->getBoolean('description'));
|
||||
$filter->setMpn($request->query->getBoolean('mpn'));
|
||||
$filter->setTags($request->query->getBoolean('tags'));
|
||||
$filter->setStorelocation($request->query->getBoolean('storelocation'));
|
||||
$filter->setComment($request->query->getBoolean('comment'));
|
||||
$filter->setIPN($request->query->getBoolean('ipn'));
|
||||
$filter->setOrdernr($request->query->getBoolean('ordernr'));
|
||||
$filter->setSupplier($request->query->getBoolean('supplier'));
|
||||
$filter->setManufacturer($request->query->getBoolean('manufacturer'));
|
||||
$filter->setFootprint($request->query->getBoolean('footprint'));
|
||||
|
||||
|
||||
$filter->setRegex($request->query->getBoolean('regex', false));
|
||||
$filter->setRegex($request->query->getBoolean('regex'));
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ use App\Exceptions\EntityNotSupportedException;
|
||||
use App\Repository\LogEntryRepository;
|
||||
use App\Services\ElementTypeNameGenerator;
|
||||
use App\Services\EntityURLGenerator;
|
||||
use App\Services\LogSystem\LogTargetHelper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Omines\DataTablesBundle\Column\AbstractColumn;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
@@ -43,21 +44,11 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class LogEntryTargetColumn extends AbstractColumn
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
protected LogEntryRepository $entryRepository;
|
||||
protected EntityURLGenerator $entityURLGenerator;
|
||||
protected ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
protected TranslatorInterface $translator;
|
||||
private LogTargetHelper $logTargetHelper;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, EntityURLGenerator $entityURLGenerator,
|
||||
ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator)
|
||||
public function __construct(LogTargetHelper $logTargetHelper)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->entryRepository = $entityManager->getRepository(AbstractLogEntry::class);
|
||||
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->translator = $translator;
|
||||
$this->logTargetHelper = $logTargetHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,71 +71,9 @@ class LogEntryTargetColumn extends AbstractColumn
|
||||
|
||||
public function render($value, $context): string
|
||||
{
|
||||
if ($context instanceof UserNotAllowedLogEntry && $this->options['showAccessDeniedPath']) {
|
||||
return htmlspecialchars($context->getPath());
|
||||
}
|
||||
|
||||
/** @var AbstractLogEntry $context */
|
||||
$target = $this->entryRepository->getTargetElement($context);
|
||||
|
||||
$tmp = '';
|
||||
|
||||
//The element is existing
|
||||
if ($target instanceof NamedElementInterface && !empty($target->getName())) {
|
||||
try {
|
||||
$tmp = sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->infoURL($target),
|
||||
$this->elementTypeNameGenerator->getTypeNameCombination($target, true)
|
||||
);
|
||||
} catch (EntityNotSupportedException $exception) {
|
||||
$tmp = $this->elementTypeNameGenerator->getTypeNameCombination($target, true);
|
||||
}
|
||||
} elseif ($target instanceof AbstractDBElement) { //Target does not have a name
|
||||
$tmp = sprintf(
|
||||
'<i>%s</i>: %s',
|
||||
$this->elementTypeNameGenerator->getLocalizedTypeLabel($target),
|
||||
$target->getID()
|
||||
);
|
||||
} elseif (null === $target && $context->hasTarget()) { //Element was deleted
|
||||
$tmp = sprintf(
|
||||
'<i>%s</i>: %s [%s]',
|
||||
$this->elementTypeNameGenerator->getLocalizedTypeLabel($context->getTargetClass()),
|
||||
$context->getTargetID(),
|
||||
$this->translator->trans('log.target_deleted')
|
||||
);
|
||||
}
|
||||
|
||||
//Add a hint to the associated element if possible
|
||||
if (null !== $target && $this->options['show_associated']) {
|
||||
if ($target instanceof Attachment && null !== $target->getElement()) {
|
||||
$on = $target->getElement();
|
||||
} elseif ($target instanceof AbstractParameter && null !== $target->getElement()) {
|
||||
$on = $target->getElement();
|
||||
} elseif ($target instanceof PartLot && null !== $target->getPart()) {
|
||||
$on = $target->getPart();
|
||||
} elseif ($target instanceof Orderdetail && null !== $target->getPart()) {
|
||||
$on = $target->getPart();
|
||||
} elseif ($target instanceof Pricedetail && null !== $target->getOrderdetail() && null !== $target->getOrderdetail()->getPart()) {
|
||||
$on = $target->getOrderdetail()->getPart();
|
||||
} elseif ($target instanceof ProjectBOMEntry && null !== $target->getProject()) {
|
||||
$on = $target->getProject();
|
||||
}
|
||||
|
||||
if (isset($on) && is_object($on)) {
|
||||
try {
|
||||
$tmp .= sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
$this->entityURLGenerator->infoURL($on),
|
||||
$this->elementTypeNameGenerator->getTypeNameCombination($on, true)
|
||||
);
|
||||
} catch (EntityNotSupportedException $exception) {
|
||||
$tmp .= ' ('.$this->elementTypeNameGenerator->getTypeNameCombination($target, true).')';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Log is not associated with an element
|
||||
return $tmp;
|
||||
return $this->logTargetHelper->formatTarget($context, [
|
||||
'showAccessDeniedPath' => $this->options['showAccessDeniedPath'],
|
||||
'show_associated' => $this->options['show_associated'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,13 +73,13 @@ class RevertLogColumn extends AbstractColumn
|
||||
{
|
||||
if (
|
||||
$context instanceof CollectionElementDeleted
|
||||
|| ($context instanceof ElementDeletedLogEntry && $context->hasOldDataInformations())
|
||||
|| ($context instanceof ElementDeletedLogEntry && $context->hasOldDataInformation())
|
||||
) {
|
||||
$icon = 'fa-trash-restore';
|
||||
$title = $this->translator->trans('log.undo.undelete');
|
||||
} elseif (
|
||||
$context instanceof ElementCreatedLogEntry
|
||||
|| ($context instanceof ElementEditedLogEntry && $context->hasOldDataInformations())
|
||||
|| ($context instanceof ElementEditedLogEntry && $context->hasOldDataInformation())
|
||||
) {
|
||||
$icon = 'fa-undo';
|
||||
$title = $this->translator->trans('log.undo.undo');
|
||||
|
||||
85
src/DataTables/ErrorDataTable.php
Normal file
85
src/DataTables/ErrorDataTable.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\DataTables;
|
||||
|
||||
use App\DataTables\Column\RowClassColumn;
|
||||
use App\Entity\Parts\Part;
|
||||
use Omines\DataTablesBundle\Adapter\ArrayAdapter;
|
||||
use Omines\DataTablesBundle\Column\TextColumn;
|
||||
use Omines\DataTablesBundle\DataTable;
|
||||
use Omines\DataTablesBundle\DataTableFactory;
|
||||
use Omines\DataTablesBundle\DataTableTypeInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class ErrorDataTable implements DataTableTypeInterface
|
||||
{
|
||||
public function configureOptions(OptionsResolver $optionsResolver): void
|
||||
{
|
||||
$optionsResolver->setRequired('errors');
|
||||
$optionsResolver->setAllowedTypes('errors', ['array', 'string']);
|
||||
$optionsResolver->setNormalizer('errors', function (OptionsResolver $optionsResolver, $errors) {
|
||||
if (is_string($errors)) {
|
||||
$errors = [$errors];
|
||||
}
|
||||
|
||||
return $errors;
|
||||
});
|
||||
}
|
||||
|
||||
public function configure(DataTable $dataTable, array $options)
|
||||
{
|
||||
$optionsResolver = new OptionsResolver();
|
||||
$this->configureOptions($optionsResolver);
|
||||
$options = $optionsResolver->resolve($options);
|
||||
|
||||
$dataTable
|
||||
->add('dont_matter_we_only_set_color', RowClassColumn::class, [
|
||||
'render' => function ($value, $context) {
|
||||
return 'table-warning';
|
||||
},
|
||||
])
|
||||
|
||||
->add('error', TextColumn::class, [
|
||||
'label' => 'error_table.error',
|
||||
'render' => function ($value, $context) {
|
||||
return '<i class="fa-solid fa-triangle-exclamation fa-fw"></i> ' . $value;
|
||||
},
|
||||
])
|
||||
;
|
||||
|
||||
//Build the array containing data
|
||||
$data = [];
|
||||
foreach ($options['errors'] as $error) {
|
||||
$data[] = ['error' => $error];
|
||||
}
|
||||
|
||||
$dataTable->createAdapter(ArrayAdapter::class, $data);
|
||||
}
|
||||
|
||||
public static function errorTable(DataTableFactory $dataTableFactory, Request $request, $errors): Response
|
||||
{
|
||||
$error_table = $dataTableFactory->createFromType(self::class, ['errors' => $errors]);
|
||||
$error_table->handleRequest($request);
|
||||
return $error_table->getResponse();
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,9 @@ class PartSearchFilter implements FilterInterface
|
||||
if($this->description) {
|
||||
$fields_to_search[] = 'part.description';
|
||||
}
|
||||
if ($this->comment) {
|
||||
$fields_to_search[] = 'part.comment';
|
||||
}
|
||||
if($this->tags) {
|
||||
$fields_to_search[] = 'part.tags';
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ use App\Exceptions\EntityNotSupportedException;
|
||||
use App\Repository\LogEntryRepository;
|
||||
use App\Services\ElementTypeNameGenerator;
|
||||
use App\Services\EntityURLGenerator;
|
||||
use App\Services\LogSystem\LogLevelHelper;
|
||||
use App\Services\UserSystem\UserAvatarHelper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
@@ -67,10 +68,11 @@ class LogDataTable implements DataTableTypeInterface
|
||||
protected LogEntryRepository $logRepo;
|
||||
protected Security $security;
|
||||
protected UserAvatarHelper $userAvatarHelper;
|
||||
protected LogLevelHelper $logLevelHelper;
|
||||
|
||||
public function __construct(ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator,
|
||||
UrlGeneratorInterface $urlGenerator, EntityURLGenerator $entityURLGenerator, EntityManagerInterface $entityManager,
|
||||
Security $security, UserAvatarHelper $userAvatarHelper)
|
||||
Security $security, UserAvatarHelper $userAvatarHelper, LogLevelHelper $logLevelHelper)
|
||||
{
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->translator = $translator;
|
||||
@@ -79,6 +81,7 @@ class LogDataTable implements DataTableTypeInterface
|
||||
$this->logRepo = $entityManager->getRepository(AbstractLogEntry::class);
|
||||
$this->security = $security;
|
||||
$this->userAvatarHelper = $userAvatarHelper;
|
||||
$this->logLevelHelper = $logLevelHelper;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $optionsResolver): void
|
||||
@@ -112,69 +115,18 @@ class LogDataTable implements DataTableTypeInterface
|
||||
|
||||
//This special $$rowClass column is used to set the row class depending on the log level. The class gets set by the frontend controller
|
||||
$dataTable->add('dont_matter', RowClassColumn::class, [
|
||||
'render' => static function ($value, AbstractLogEntry $context) {
|
||||
switch ($context->getLevel()) {
|
||||
case AbstractLogEntry::LEVEL_EMERGENCY:
|
||||
case AbstractLogEntry::LEVEL_ALERT:
|
||||
case AbstractLogEntry::LEVEL_CRITICAL:
|
||||
case AbstractLogEntry::LEVEL_ERROR:
|
||||
return 'table-danger';
|
||||
case AbstractLogEntry::LEVEL_WARNING:
|
||||
return 'table-warning';
|
||||
case AbstractLogEntry::LEVEL_NOTICE:
|
||||
return 'table-info';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
return $this->logLevelHelper->logLevelToTableColorClass($context->getLevelString());
|
||||
},
|
||||
]);
|
||||
|
||||
$dataTable->add('symbol', TextColumn::class, [
|
||||
'label' => '',
|
||||
'className' => 'no-colvis',
|
||||
'render' => static function ($value, AbstractLogEntry $context) {
|
||||
switch ($context->getLevelString()) {
|
||||
case LogLevel::DEBUG:
|
||||
$symbol = 'fa-bug';
|
||||
|
||||
break;
|
||||
case LogLevel::INFO:
|
||||
$symbol = 'fa-info';
|
||||
|
||||
break;
|
||||
case LogLevel::NOTICE:
|
||||
$symbol = 'fa-flag';
|
||||
|
||||
break;
|
||||
case LogLevel::WARNING:
|
||||
$symbol = 'fa-exclamation-circle';
|
||||
|
||||
break;
|
||||
case LogLevel::ERROR:
|
||||
$symbol = 'fa-exclamation-triangle';
|
||||
|
||||
break;
|
||||
case LogLevel::CRITICAL:
|
||||
$symbol = 'fa-bolt';
|
||||
|
||||
break;
|
||||
case LogLevel::ALERT:
|
||||
$symbol = 'fa-radiation';
|
||||
|
||||
break;
|
||||
case LogLevel::EMERGENCY:
|
||||
$symbol = 'fa-skull-crossbones';
|
||||
|
||||
break;
|
||||
default:
|
||||
$symbol = 'fa-question-circle';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
'render' => function ($value, AbstractLogEntry $context) {
|
||||
return sprintf(
|
||||
'<i class="fas fa-fw %s" title="%s"></i>',
|
||||
$symbol,
|
||||
$this->logLevelHelper->logLevelToIconClass($context->getLevelString()),
|
||||
$context->getLevelString()
|
||||
);
|
||||
},
|
||||
@@ -188,6 +140,12 @@ class LogDataTable implements DataTableTypeInterface
|
||||
$dataTable->add('timestamp', LocaleDateTimeColumn::class, [
|
||||
'label' => 'log.timestamp',
|
||||
'timeFormat' => 'medium',
|
||||
'render' => function (string $value, AbstractLogEntry $context) {
|
||||
return sprintf('<a href="%s">%s</a>',
|
||||
$this->urlGenerator->generate('log_details', ['id' => $context->getId()]),
|
||||
$value
|
||||
);
|
||||
}
|
||||
]);
|
||||
|
||||
$dataTable->add('type', TextColumn::class, [
|
||||
@@ -278,7 +236,7 @@ class LogDataTable implements DataTableTypeInterface
|
||||
'href' => function ($value, AbstractLogEntry $context) {
|
||||
if (
|
||||
($context instanceof TimeTravelInterface
|
||||
&& $context->hasOldDataInformations())
|
||||
&& $context->hasOldDataInformation())
|
||||
|| $context instanceof CollectionElementDeleted
|
||||
) {
|
||||
try {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
namespace App\Doctrine;
|
||||
|
||||
use App\Exceptions\InvalidRegexException;
|
||||
use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
|
||||
use Doctrine\DBAL\Event\ConnectionEventArgs;
|
||||
use Doctrine\DBAL\Events;
|
||||
@@ -43,7 +44,11 @@ class SQLiteRegexExtension implements EventSubscriberInterface
|
||||
//Ensure that the function really exists on the connection, as it is marked as experimental according to PHP documentation
|
||||
if($native_connection instanceof \PDO && method_exists($native_connection, 'sqliteCreateFunction' )) {
|
||||
$native_connection->sqliteCreateFunction('REGEXP', function ($pattern, $value) {
|
||||
return (false !== mb_ereg($pattern, $value)) ? 1 : 0;
|
||||
try {
|
||||
return (false !== mb_ereg($pattern, $value)) ? 1 : 0;
|
||||
} catch (\ErrorException $e) {
|
||||
throw InvalidRegexException::fromMBRegexError($e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
41
src/Entity/Contracts/LogWithNewDataInterface.php
Normal file
41
src/Entity/Contracts/LogWithNewDataInterface.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Entity\Contracts;
|
||||
|
||||
interface LogWithNewDataInterface
|
||||
{
|
||||
/**
|
||||
* Checks if this entry has information about the new data.
|
||||
* @return bool
|
||||
*/
|
||||
public function hasNewDataInformation(): bool;
|
||||
|
||||
/**
|
||||
* Returns the new data for this entry.
|
||||
*/
|
||||
public function getNewData(): array;
|
||||
|
||||
/**
|
||||
* Sets the new data for this entry.
|
||||
* @return $this
|
||||
*/
|
||||
public function setNewData(array $new_data): self;
|
||||
}
|
||||
@@ -31,7 +31,7 @@ interface TimeTravelInterface
|
||||
*
|
||||
* @return bool true if this entry has information about the changed data
|
||||
*/
|
||||
public function hasOldDataInformations(): bool;
|
||||
public function hasOldDataInformation(): bool;
|
||||
|
||||
/**
|
||||
* Returns the data the entity had before this log entry.
|
||||
|
||||
@@ -88,7 +88,7 @@ class ElementDeletedLogEntry extends AbstractLogEntry implements TimeTravelInter
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasOldDataInformations(): bool
|
||||
public function hasOldDataInformation(): bool
|
||||
{
|
||||
return !empty($this->extra['o']);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace App\Entity\LogSystem;
|
||||
use App\Entity\Base\AbstractDBElement;
|
||||
use App\Entity\Contracts\LogWithCommentInterface;
|
||||
use App\Entity\Contracts\LogWithEventUndoInterface;
|
||||
use App\Entity\Contracts\LogWithNewDataInterface;
|
||||
use App\Entity\Contracts\TimeTravelInterface;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use InvalidArgumentException;
|
||||
@@ -32,7 +33,7 @@ use InvalidArgumentException;
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
*/
|
||||
class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface, LogWithEventUndoInterface
|
||||
class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterface, LogWithCommentInterface, LogWithEventUndoInterface, LogWithNewDataInterface
|
||||
{
|
||||
protected string $typeString = 'element_edited';
|
||||
|
||||
@@ -49,7 +50,7 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
|
||||
*/
|
||||
public function hasChangedFieldsInfo(): bool
|
||||
{
|
||||
return isset($this->extra['f']) || $this->hasOldDataInformations();
|
||||
return isset($this->extra['f']) || $this->hasOldDataInformation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,7 +60,7 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
|
||||
*/
|
||||
public function getChangedFields(): array
|
||||
{
|
||||
if ($this->hasOldDataInformations()) {
|
||||
if ($this->hasOldDataInformation()) {
|
||||
return array_keys($this->getOldData());
|
||||
}
|
||||
|
||||
@@ -92,7 +93,29 @@ class ElementEditedLogEntry extends AbstractLogEntry implements TimeTravelInterf
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasOldDataInformations(): bool
|
||||
public function hasNewDataInformation(): bool
|
||||
{
|
||||
return !empty($this->extra['n']);
|
||||
}
|
||||
|
||||
public function getNewData(): array
|
||||
{
|
||||
return $this->extra['n'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the old data for this entry.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setNewData(array $new_data): self
|
||||
{
|
||||
$this->extra['n'] = $new_data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasOldDataInformation(): bool
|
||||
{
|
||||
return !empty($this->extra['d']);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ class SecurityEventLogEntry extends AbstractLogEntry
|
||||
{
|
||||
$key = $this->extra['e'];
|
||||
|
||||
return static::SECURITY_TYPE_MAPPING[$key] ?? 'unkown';
|
||||
return static::SECURITY_TYPE_MAPPING[$key] ?? 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,11 +78,12 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||
protected bool $save_changed_fields;
|
||||
protected bool $save_changed_data;
|
||||
protected bool $save_removed_data;
|
||||
protected bool $save_new_data;
|
||||
protected PropertyAccessorInterface $propertyAccessor;
|
||||
|
||||
public function __construct(EventLogger $logger, SerializerInterface $serializer, EventCommentHelper $commentHelper,
|
||||
bool $save_changed_fields, bool $save_changed_data, bool $save_removed_data, PropertyAccessorInterface $propertyAccessor,
|
||||
EventUndoHelper $eventUndoHelper)
|
||||
bool $save_changed_fields, bool $save_changed_data, bool $save_removed_data, bool $save_new_data,
|
||||
PropertyAccessorInterface $propertyAccessor, EventUndoHelper $eventUndoHelper)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->serializer = $serializer;
|
||||
@@ -93,6 +94,8 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||
$this->save_changed_fields = $save_changed_fields;
|
||||
$this->save_changed_data = $save_changed_data;
|
||||
$this->save_removed_data = $save_removed_data;
|
||||
//This option only makes sense if save_changed_data is true
|
||||
$this->save_new_data = $save_new_data && $save_changed_data;
|
||||
}
|
||||
|
||||
public function onFlush(OnFlushEventArgs $eventArgs): void
|
||||
@@ -150,6 +153,7 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||
$log->setTargetElementID($undoEvent->getDeletedElementID());
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->log($log);
|
||||
}
|
||||
}
|
||||
@@ -301,6 +305,24 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||
}, ARRAY_FILTER_USE_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restrict the length of every string in the given array to MAX_STRING_LENGTH, to save memory in the case of very
|
||||
* long strings (e.g. images in notes)
|
||||
* @param array $fields
|
||||
* @return array
|
||||
*/
|
||||
protected function fieldLengthRestrict(array $fields): array
|
||||
{
|
||||
return array_map(
|
||||
static function ($value) {
|
||||
if (is_string($value)) {
|
||||
return mb_strimwidth($value, 0, self::MAX_STRING_LENGTH, '...');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}, $fields);
|
||||
}
|
||||
|
||||
protected function saveChangeSet(AbstractDBElement $entity, AbstractLogEntry $logEntry, EntityManagerInterface $em, bool $element_deleted = false): void
|
||||
{
|
||||
$uow = $em->getUnitOfWork();
|
||||
@@ -314,20 +336,24 @@ class EventLoggerSubscriber implements EventSubscriber
|
||||
} else { //Otherwise we have to get it from entity changeset
|
||||
$changeSet = $uow->getEntityChangeSet($entity);
|
||||
$old_data = array_combine(array_keys($changeSet), array_column($changeSet, 0));
|
||||
//If save_new_data is enabled, we extract it from the change set
|
||||
if ($this->save_new_data) {
|
||||
$new_data = array_combine(array_keys($changeSet), array_column($changeSet, 1));
|
||||
}
|
||||
}
|
||||
$old_data = $this->filterFieldRestrictions($entity, $old_data);
|
||||
|
||||
//Restrict length of string fields, to save memory...
|
||||
$old_data = array_map(
|
||||
static function ($value) {
|
||||
if (is_string($value)) {
|
||||
return mb_strimwidth($value, 0, self::MAX_STRING_LENGTH, '...');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}, $old_data);
|
||||
$old_data = $this->fieldLengthRestrict($old_data);
|
||||
|
||||
$logEntry->setOldData($old_data);
|
||||
|
||||
if (!empty($new_data)) {
|
||||
$new_data = $this->filterFieldRestrictions($entity, $new_data);
|
||||
$new_data = $this->fieldLengthRestrict($new_data);
|
||||
|
||||
$logEntry->setNewData($new_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
80
src/Exceptions/InvalidRegexException.php
Normal file
80
src/Exceptions/InvalidRegexException.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Doctrine\DBAL\Exception\DriverException;
|
||||
use ErrorException;
|
||||
|
||||
class InvalidRegexException extends \RuntimeException
|
||||
{
|
||||
private ?string $reason;
|
||||
|
||||
public function __construct(string $reason = null)
|
||||
{
|
||||
$this->reason = $reason;
|
||||
parent::__construct('Invalid regular expression');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reason for the exception (what the regex driver deemed invalid)
|
||||
* @return string|null
|
||||
*/
|
||||
public function getReason(): ?string
|
||||
{
|
||||
return $this->reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new exception from a driver exception happening, when MySQL encounters an invalid regex
|
||||
* @param DriverException $exception
|
||||
* @return self
|
||||
*/
|
||||
public static function fromDriverException(DriverException $exception): self
|
||||
{
|
||||
//1139 means invalid regex error
|
||||
if ($exception->getCode() !== 1139) {
|
||||
throw new \InvalidArgumentException('The given exception is not a driver exception', 0, $exception);
|
||||
}
|
||||
|
||||
//Reason is the part after the erorr code
|
||||
$reason = preg_replace('/^.*1139 /', '', $exception->getMessage());
|
||||
|
||||
return new self($reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new exception from the errorException thrown by mb_ereg
|
||||
* @param ErrorException $ex
|
||||
* @return self
|
||||
*/
|
||||
public static function fromMBRegexError(ErrorException $ex): self
|
||||
{
|
||||
//Ensure that the error is really a mb_ereg error
|
||||
if ($ex->getSeverity() !== E_WARNING || !strpos($ex->getMessage(), 'mb_ereg()') !== false) {
|
||||
throw new \InvalidArgumentException('The given exception is not a mb_ereg error', 0, $ex);
|
||||
}
|
||||
|
||||
//Reason is the part after the erorr code
|
||||
$reason = preg_replace('/^.*mb_ereg\(\): /', '', $ex->getMessage());
|
||||
|
||||
return new self($reason);
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,22 @@ declare(strict_types=1);
|
||||
namespace App\Security\Voter;
|
||||
|
||||
use App\Entity\Attachments\Attachment;
|
||||
use App\Entity\Attachments\AttachmentTypeAttachment;
|
||||
use App\Entity\Attachments\CategoryAttachment;
|
||||
use App\Entity\Attachments\CurrencyAttachment;
|
||||
use App\Entity\Attachments\FootprintAttachment;
|
||||
use App\Entity\Attachments\GroupAttachment;
|
||||
use App\Entity\Attachments\ManufacturerAttachment;
|
||||
use App\Entity\Attachments\MeasurementUnitAttachment;
|
||||
use App\Entity\Attachments\PartAttachment;
|
||||
use App\Entity\Attachments\ProjectAttachment;
|
||||
use App\Entity\Attachments\StorelocationAttachment;
|
||||
use App\Entity\Attachments\SupplierAttachment;
|
||||
use App\Entity\Attachments\UserAttachment;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Services\UserSystem\PermissionManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
use function in_array;
|
||||
@@ -50,26 +63,78 @@ class AttachmentVoter extends ExtendedVoter
|
||||
{
|
||||
//return $this->resolver->inherit($user, 'attachments', $attribute) ?? false;
|
||||
|
||||
//If the attachment has no element (which should not happen), we deny access, as we can not determine if the user is allowed to access the associated element
|
||||
$target_element = $subject->getElement();
|
||||
if (! $subject instanceof Attachment || null === $target_element) {
|
||||
//This voter only works for attachments
|
||||
if (!is_a($subject, Attachment::class, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Depending on the operation delegate either to the attachments element or to the attachment permission
|
||||
if ($attribute === 'show_private') {
|
||||
return $this->resolver->inherit($user, 'attachments', 'show_private') ?? false;
|
||||
}
|
||||
|
||||
|
||||
if (is_object($subject)) {
|
||||
//If the attachment has no element (which should not happen), we deny access, as we can not determine if the user is allowed to access the associated element
|
||||
$target_element = $subject->getElement();
|
||||
if ($target_element) {
|
||||
return $this->security->isGranted($this->mapOperation($attribute), $target_element);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_string($subject)) {
|
||||
//If we do not have a concrete element (or we just got a string as value), we delegate to the different categories
|
||||
if (is_a($subject, AttachmentTypeAttachment::class, true)) {
|
||||
$param = 'attachment_types';
|
||||
} elseif (is_a($subject, CategoryAttachment::class, true)) {
|
||||
$param = 'categories';
|
||||
} elseif (is_a($subject, CurrencyAttachment::class, true)) {
|
||||
$param = 'currencies';
|
||||
} elseif (is_a($subject, ProjectAttachment::class, true)) {
|
||||
$param = 'projects';
|
||||
} elseif (is_a($subject, FootprintAttachment::class, true)) {
|
||||
$param = 'footprints';
|
||||
} elseif (is_a($subject, GroupAttachment::class, true)) {
|
||||
$param = 'groups';
|
||||
} elseif (is_a($subject, ManufacturerAttachment::class, true)) {
|
||||
$param = 'manufacturers';
|
||||
} elseif (is_a($subject, MeasurementUnitAttachment::class, true)) {
|
||||
$param = 'measurement_units';
|
||||
} elseif (is_a($subject, PartAttachment::class, true)) {
|
||||
$param = 'parts';
|
||||
} elseif (is_a($subject, StorelocationAttachment::class, true)) {
|
||||
$param = 'storelocations';
|
||||
} elseif (is_a($subject, SupplierAttachment::class, true)) {
|
||||
$param = 'suppliers';
|
||||
} elseif (is_a($subject, UserAttachment::class, true)) {
|
||||
$param = 'users';
|
||||
} elseif ($subject === Attachment::class) {
|
||||
//If the subject was deleted, we can not determine the type properly, so we just use the parts permission
|
||||
$param = 'parts';
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException('Encountered unknown Parameter type: ' . (is_object($subject) ? get_class($subject) : $subject));
|
||||
}
|
||||
|
||||
return $this->resolver->inherit($user, $param, $this->mapOperation($attribute)) ?? false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function mapOperation(string $attribute): string
|
||||
{
|
||||
switch ($attribute) {
|
||||
//We can view the attachment if we can view the element
|
||||
case 'read':
|
||||
case 'view':
|
||||
return $this->security->isGranted('read', $target_element);
|
||||
return 'read';
|
||||
//We can edit/create/delete the attachment if we can edit the element
|
||||
case 'edit':
|
||||
case 'create':
|
||||
case 'delete':
|
||||
return $this->security->isGranted('edit', $target_element);
|
||||
|
||||
case 'show_private':
|
||||
return $this->resolver->inherit($user, 'attachments', 'show_private') ?? false;
|
||||
return 'edit';
|
||||
case 'show_history':
|
||||
return 'show_history';
|
||||
}
|
||||
|
||||
throw new \RuntimeException('Encountered unknown attribute "'.$attribute.'" in AttachmentVoter!');
|
||||
@@ -87,7 +152,7 @@ class AttachmentVoter extends ExtendedVoter
|
||||
{
|
||||
if (is_a($subject, Attachment::class, true)) {
|
||||
//These are the allowed attributes
|
||||
return in_array($attribute, ['read', 'view', 'edit', 'delete', 'create', 'show_private'], true);
|
||||
return in_array($attribute, ['read', 'view', 'edit', 'delete', 'create', 'show_private', 'show_history'], true);
|
||||
}
|
||||
|
||||
//Allow class name as subject
|
||||
|
||||
@@ -24,13 +24,28 @@ namespace App\Security\Voter;
|
||||
|
||||
use App\Entity\LogSystem\AbstractLogEntry;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Services\UserSystem\PermissionManager;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
||||
class LogEntryVoter extends ExtendedVoter
|
||||
{
|
||||
public const ALLOWED_OPS = ['read', 'delete'];
|
||||
public const ALLOWED_OPS = ['read', 'show_details', 'delete'];
|
||||
|
||||
private Security $security;
|
||||
|
||||
public function __construct(PermissionManager $resolver, EntityManagerInterface $entityManager, Security $security)
|
||||
{
|
||||
parent::__construct($resolver, $entityManager);
|
||||
$this->security = $security;
|
||||
}
|
||||
|
||||
protected function voteOnUser(string $attribute, $subject, User $user): bool
|
||||
{
|
||||
if (!$subject instanceof AbstractLogEntry) {
|
||||
throw new \InvalidArgumentException('The subject must be an instance of '.AbstractLogEntry::class);
|
||||
}
|
||||
|
||||
if ('delete' === $attribute) {
|
||||
return $this->resolver->inherit($user, 'system', 'delete_logs') ?? false;
|
||||
}
|
||||
@@ -47,13 +62,24 @@ class LogEntryVoter extends ExtendedVoter
|
||||
return $this->resolver->inherit($user, 'system', 'show_logs') ?? false;
|
||||
}
|
||||
|
||||
if ('show_details' === $attribute) {
|
||||
//To view details of a element related log entry, the user needs to be able to view the history of this entity type
|
||||
$targetClass = $subject->getTargetClass();
|
||||
if (null !== $targetClass) {
|
||||
return $this->security->isGranted('show_history', $targetClass) ?? false;
|
||||
}
|
||||
|
||||
//In other cases, this behaves like the read permission
|
||||
return $this->voteOnUser('read', $subject, $user);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function supports($attribute, $subject): bool
|
||||
{
|
||||
if ($subject instanceof AbstractLogEntry) {
|
||||
return in_array($subject, static::ALLOWED_OPS, true);
|
||||
return in_array($attribute, static::ALLOWED_OPS, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -53,66 +53,72 @@ class ParameterVoter extends ExtendedVoter
|
||||
{
|
||||
//return $this->resolver->inherit($user, 'attachments', $attribute) ?? false;
|
||||
|
||||
if (!$subject instanceof AbstractParameter) {
|
||||
if (!is_a($subject, AbstractParameter::class, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//If the attachment has no element (which should not happen), we deny access, as we can not determine if the user is allowed to access the associated element
|
||||
$target_element = $subject->getElement();
|
||||
if ($target_element !== null) {
|
||||
//Depending on the operation delegate either to the attachments element or to the attachment permission
|
||||
if (is_object($subject)) {
|
||||
//If the attachment has no element (which should not happen), we deny access, as we can not determine if the user is allowed to access the associated element
|
||||
$target_element = $subject->getElement();
|
||||
if ($target_element !== null) {
|
||||
//Depending on the operation delegate either to the attachments element or to the attachment permission
|
||||
|
||||
|
||||
switch ($attribute) {
|
||||
//We can view the attachment if we can view the element
|
||||
case 'read':
|
||||
case 'view':
|
||||
$operation = 'read';
|
||||
break;
|
||||
//We can edit/create/delete the attachment if we can edit the element
|
||||
case 'edit':
|
||||
case 'create':
|
||||
case 'delete':
|
||||
$operation = 'edit';
|
||||
break;
|
||||
case 'show_history':
|
||||
$operation = 'show_history';
|
||||
break;
|
||||
case 'revert_element':
|
||||
$operation = 'revert_element';
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException('Unknown operation: '.$attribute);
|
||||
switch ($attribute) {
|
||||
//We can view the attachment if we can view the element
|
||||
case 'read':
|
||||
case 'view':
|
||||
$operation = 'read';
|
||||
break;
|
||||
//We can edit/create/delete the attachment if we can edit the element
|
||||
case 'edit':
|
||||
case 'create':
|
||||
case 'delete':
|
||||
$operation = 'edit';
|
||||
break;
|
||||
case 'show_history':
|
||||
$operation = 'show_history';
|
||||
break;
|
||||
case 'revert_element':
|
||||
$operation = 'revert_element';
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException('Unknown operation: '.$attribute);
|
||||
}
|
||||
|
||||
return $this->security->isGranted($operation, $target_element);
|
||||
}
|
||||
|
||||
return $this->security->isGranted($operation, $target_element);
|
||||
}
|
||||
|
||||
//If we do not have a concrete element, we delegate to the different categories
|
||||
if ($subject instanceof AttachmentTypeParameter) {
|
||||
//If we do not have a concrete element (or we just got a string as value), we delegate to the different categories
|
||||
if (is_a($subject, AttachmentTypeParameter::class, true)) {
|
||||
$param = 'attachment_types';
|
||||
} elseif ($subject instanceof CategoryParameter) {
|
||||
} elseif (is_a($subject, CategoryParameter::class, true)) {
|
||||
$param = 'categories';
|
||||
} elseif ($subject instanceof CurrencyParameter) {
|
||||
} elseif (is_a($subject, CurrencyParameter::class, true)) {
|
||||
$param = 'currencies';
|
||||
} elseif ($subject instanceof ProjectParameter) {
|
||||
} elseif (is_a($subject, ProjectParameter::class, true)) {
|
||||
$param = 'projects';
|
||||
} elseif ($subject instanceof FootprintParameter) {
|
||||
} elseif (is_a($subject, FootprintParameter::class, true)) {
|
||||
$param = 'footprints';
|
||||
} elseif ($subject instanceof GroupParameter) {
|
||||
} elseif (is_a($subject, GroupParameter::class, true)) {
|
||||
$param = 'groups';
|
||||
} elseif ($subject instanceof ManufacturerParameter) {
|
||||
} elseif (is_a($subject, ManufacturerParameter::class, true)) {
|
||||
$param = 'manufacturers';
|
||||
} elseif ($subject instanceof MeasurementUnitParameter) {
|
||||
} elseif (is_a($subject, MeasurementUnitParameter::class, true)) {
|
||||
$param = 'measurement_units';
|
||||
} elseif ($subject instanceof PartParameter) {
|
||||
} elseif (is_a($subject, PartParameter::class, true)) {
|
||||
$param = 'parts';
|
||||
} elseif ($subject instanceof StorelocationParameter) {
|
||||
} elseif (is_a($subject, StorelocationParameter::class, true)) {
|
||||
$param = 'storelocations';
|
||||
} elseif ($subject instanceof SupplierParameter) {
|
||||
} elseif (is_a($subject, SupplierParameter::class, true)) {
|
||||
$param = 'suppliers';
|
||||
} else {
|
||||
throw new RuntimeException('Encountered unknown Parameter type: ' . get_class($subject));
|
||||
} elseif ($subject === AbstractParameter::class) {
|
||||
//If the subject was deleted, we can not determine the type properly, so we just use the parts permission
|
||||
$param = 'parts';
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException('Encountered unknown Parameter type: ' . (is_object($subject) ? get_class($subject) : $subject));
|
||||
}
|
||||
|
||||
return $this->resolver->inherit($user, $param, $attribute) ?? false;
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace App\Services;
|
||||
|
||||
use App\Entity\Attachments\Attachment;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\Base\AbstractDBElement;
|
||||
use App\Entity\Contracts\NamedElementInterface;
|
||||
use App\Entity\ProjectSystem\Project;
|
||||
use App\Entity\LabelSystem\LabelProfile;
|
||||
@@ -43,17 +44,20 @@ use App\Entity\ProjectSystem\ProjectBOMEntry;
|
||||
use App\Entity\UserSystem\Group;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Exceptions\EntityNotSupportedException;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use function get_class;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class ElementTypeNameGenerator
|
||||
{
|
||||
protected TranslatorInterface $translator;
|
||||
private EntityURLGenerator $entityURLGenerator;
|
||||
protected array $mapping;
|
||||
|
||||
public function __construct(TranslatorInterface $translator)
|
||||
public function __construct(TranslatorInterface $translator, EntityURLGenerator $entityURLGenerator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
|
||||
//Child classes has to become before parent classes
|
||||
$this->mapping = [
|
||||
@@ -132,4 +136,81 @@ class ElementTypeNameGenerator
|
||||
|
||||
return $type.': '.$entity->getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a HTML formatted label for the given enitity in the format "Type: Name" (on elements with a name) and
|
||||
* "Type: ID" (on elements without a name). If possible the value is given as a link to the element.
|
||||
* @param AbstractDBElement $entity The entity for which the label should be generated
|
||||
* @param bool $include_associated If set to true, the associated entity (like the part belonging to a part lot) is included in the label to give further information
|
||||
* @return string
|
||||
*/
|
||||
public function formatLabelHTMLForEntity(AbstractDBElement $entity, bool $include_associated = false): string
|
||||
{
|
||||
//The element is existing
|
||||
if ($entity instanceof NamedElementInterface && !empty($entity->getName())) {
|
||||
try {
|
||||
$tmp = sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
$this->entityURLGenerator->infoURL($entity),
|
||||
$this->getTypeNameCombination($entity, true)
|
||||
);
|
||||
} catch (EntityNotSupportedException $exception) {
|
||||
$tmp = $this->getTypeNameCombination($entity, true);
|
||||
}
|
||||
} else { //Target does not have a name
|
||||
$tmp = sprintf(
|
||||
'<i>%s</i>: %s',
|
||||
$this->getLocalizedTypeLabel($entity),
|
||||
$entity->getID()
|
||||
);
|
||||
}
|
||||
|
||||
//Add a hint to the associated element if possible
|
||||
if ($include_associated) {
|
||||
if ($entity instanceof Attachment && null !== $entity->getElement()) {
|
||||
$on = $entity->getElement();
|
||||
} elseif ($entity instanceof AbstractParameter && null !== $entity->getElement()) {
|
||||
$on = $entity->getElement();
|
||||
} elseif ($entity instanceof PartLot && null !== $entity->getPart()) {
|
||||
$on = $entity->getPart();
|
||||
} elseif ($entity instanceof Orderdetail && null !== $entity->getPart()) {
|
||||
$on = $entity->getPart();
|
||||
} elseif ($entity instanceof Pricedetail && null !== $entity->getOrderdetail() && null !== $entity->getOrderdetail()->getPart()) {
|
||||
$on = $entity->getOrderdetail()->getPart();
|
||||
} elseif ($entity instanceof ProjectBOMEntry && null !== $entity->getProject()) {
|
||||
$on = $entity->getProject();
|
||||
}
|
||||
|
||||
if (isset($on) && is_object($on)) {
|
||||
try {
|
||||
$tmp .= sprintf(
|
||||
' (<a href="%s">%s</a>)',
|
||||
$this->entityURLGenerator->infoURL($on),
|
||||
$this->getTypeNameCombination($on, true)
|
||||
);
|
||||
} catch (EntityNotSupportedException $exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HTML formatted label for a deleted element of which we only know the class and the ID.
|
||||
* Please note that it is not checked if the element really not exists anymore, so you have to do this yourself.
|
||||
* @param string $class
|
||||
* @param int $id
|
||||
* @return string
|
||||
*/
|
||||
public function formatElementDeletedHTML(string $class, int $id): string
|
||||
{
|
||||
return sprintf(
|
||||
'<i>%s</i>: %s [%s]',
|
||||
$this->getLocalizedTypeLabel($class),
|
||||
$id,
|
||||
$this->translator->trans('log.target_deleted')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,10 @@ class MySQLDumpXMLConverter
|
||||
|
||||
//Iterate over all <table> nodes and convert them to arrays
|
||||
foreach ($tables as $table) {
|
||||
$table_data[$table->getAttribute('name')] = $this->convertTableToArray($table);
|
||||
//Normalize the table name to lowercase. On Linux filesystems the tables sometimes contain uppercase letters
|
||||
//However we expect the table names to be lowercase in the further steps
|
||||
$table_name = strtolower($table->getAttribute('name'));
|
||||
$table_data[$table_name] = $this->convertTableToArray($table);
|
||||
}
|
||||
|
||||
return $table_data;
|
||||
|
||||
@@ -84,7 +84,15 @@ trait PKImportHelperTrait
|
||||
|
||||
//Determine file extension (if the extension is empty, we use the original extension)
|
||||
if (empty($attachment_row['extension'])) {
|
||||
$attachment_row['extension'] = pathinfo($attachment_row['originalname'], PATHINFO_EXTENSION);
|
||||
//Use mime type to determine the extension like PartKeepr does in legacy implementation (just use the second part of the mime type)
|
||||
//See UploadedFile.php:291 in PartKeepr (https://github.com/partkeepr/PartKeepr/blob/f6176c3354b24fa39ac8bc4328ee0df91de3d5b6/src/PartKeepr/UploadedFileBundle/Entity/UploadedFile.php#L291)
|
||||
if (!empty ($attachment_row['mimetype'])) {
|
||||
$attachment_row['extension'] = explode('/', $attachment_row['mimetype'])[1];
|
||||
} else {
|
||||
//If the mime type is empty, we use the original extension
|
||||
$attachment_row['extension'] = pathinfo($attachment_row['originalname'], PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Determine file path
|
||||
|
||||
@@ -30,10 +30,12 @@ use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Entity\Parts\Storelocation;
|
||||
use App\Entity\Parts\Supplier;
|
||||
use App\Entity\PriceInformations\Currency;
|
||||
use App\Entity\PriceInformations\Orderdetail;
|
||||
use App\Entity\PriceInformations\Pricedetail;
|
||||
use Brick\Math\BigDecimal;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Intl\Currencies;
|
||||
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
|
||||
|
||||
/**
|
||||
@@ -43,10 +45,13 @@ class PKPartImporter
|
||||
{
|
||||
use PKImportHelperTrait;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, PropertyAccessorInterface $propertyAccessor)
|
||||
private string $base_currency;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, PropertyAccessorInterface $propertyAccessor, string $default_currency)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->propertyAccessor = $propertyAccessor;
|
||||
$this->base_currency = $default_currency;
|
||||
}
|
||||
|
||||
public function importParts(array $data): int
|
||||
@@ -168,11 +173,21 @@ class PKPartImporter
|
||||
$entity->setName($name);
|
||||
|
||||
$entity->setValueText($partparameter['stringValue'] ?? '');
|
||||
$entity->setUnit($this->getUnitSymbol($data, (int) $partparameter['unit_id']));
|
||||
if ($partparameter['unit_id'] === null) {
|
||||
$entity->setUnit($this->getUnitSymbol($data, (int)$partparameter['unit_id']));
|
||||
} else {
|
||||
$entity->setUnit("");
|
||||
}
|
||||
|
||||
$entity->setValueMin($partparameter['normalizedMinValue'] ?? null);
|
||||
$entity->setValueTypical($partparameter['normalizedValue'] ?? null);
|
||||
$entity->setValueMax($partparameter['normalizedMaxValue'] ?? null);
|
||||
if ($partparameter['normalizedMinValue'] !== null) {
|
||||
$entity->setValueMin((float) $partparameter['normalizedMinValue']);
|
||||
}
|
||||
if ($partparameter['normalizedValue'] !== null) {
|
||||
$entity->setValueTypical((float) $partparameter['normalizedValue']);
|
||||
}
|
||||
if ($partparameter['normalizedMaxValue'] !== null) {
|
||||
$entity->setValueMax((float) $partparameter['normalizedMaxValue']);
|
||||
}
|
||||
|
||||
$part = $this->em->find(Part::class, (int) $partparameter['part_id']);
|
||||
if (!$part) {
|
||||
@@ -185,6 +200,37 @@ class PKPartImporter
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currency for the given ISO code. If the currency does not exist, it is created.
|
||||
* This function returns null if the ISO code is the base currency.
|
||||
* @param string $currency_iso_code
|
||||
* @return Currency|null
|
||||
*/
|
||||
protected function getOrCreateCurrency(string $currency_iso_code): ?Currency
|
||||
{
|
||||
//Normalize ISO code
|
||||
$currency_iso_code = strtoupper($currency_iso_code);
|
||||
|
||||
//We do not have a currency for the base currency to be consistent with prices without currencies
|
||||
if ($currency_iso_code === $this->base_currency) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$currency = $this->em->getRepository(Currency::class)->findOneBy([
|
||||
'iso_code' => $currency_iso_code,
|
||||
]);
|
||||
|
||||
if (!$currency) {
|
||||
$currency = new Currency();
|
||||
$currency->setIsoCode($currency_iso_code);
|
||||
$currency->setName(Currencies::getName($currency_iso_code));
|
||||
$this->em->persist($currency);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
return $currency;
|
||||
}
|
||||
|
||||
protected function importOrderdetails(array $data): void
|
||||
{
|
||||
if (!isset($data['partdistributor'])) {
|
||||
@@ -226,6 +272,7 @@ class PKPartImporter
|
||||
$orderdetail->setSupplier($supplier);
|
||||
$orderdetail->setSupplierpartnr($spn);
|
||||
$part->addOrderdetail($orderdetail);
|
||||
$this->em->persist($orderdetail);
|
||||
}
|
||||
|
||||
//Add the price information to the orderdetail
|
||||
@@ -234,12 +281,25 @@ class PKPartImporter
|
||||
$orderdetail->addPricedetail($pricedetail);
|
||||
//Partkeepr stores the price per item, we need to convert it to the price per packaging unit
|
||||
$price_per_item = BigDecimal::of($partdistributor['price']);
|
||||
$pricedetail->setPrice($price_per_item->multipliedBy($partdistributor['packagingUnit']));
|
||||
$pricedetail->setPriceRelatedQuantity($partdistributor['packagingUnit'] ?? 1);
|
||||
$packaging_unit = $partdistributor['packagingUnit'] ?? 1;
|
||||
$pricedetail->setPrice($price_per_item->multipliedBy($packaging_unit));
|
||||
$pricedetail->setPriceRelatedQuantity($packaging_unit);
|
||||
//We have to set the minimum discount quantity to the packaging unit (PartKeepr does not know this concept)
|
||||
//But in Part-DB the minimum discount qty have to be unique across a orderdetail
|
||||
$pricedetail->setMinDiscountQuantity($packaging_unit);
|
||||
|
||||
//Set the currency of the price
|
||||
if (!empty($partdistributor['currency'])) {
|
||||
$currency = $this->getOrCreateCurrency($partdistributor['currency']);
|
||||
$pricedetail->setCurrency($currency);
|
||||
}
|
||||
|
||||
$this->em->persist($pricedetail);
|
||||
}
|
||||
|
||||
//We have to flush the changes in every loop, so the find function can find newly created entities
|
||||
$this->em->flush();
|
||||
//Clear the entity manager to improve performance
|
||||
$this->em->clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
163
src/Services/LogSystem/LogDataFormatter.php
Normal file
163
src/Services/LogSystem/LogDataFormatter.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Services\LogSystem;
|
||||
|
||||
use App\Entity\LogSystem\AbstractLogEntry;
|
||||
use App\Services\ElementTypeNameGenerator;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class LogDataFormatter
|
||||
{
|
||||
private const STRING_MAX_LENGTH = 1024;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
private EntityManagerInterface $entityManager;
|
||||
private ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, EntityManagerInterface $entityManager, ElementTypeNameGenerator $elementTypeNameGenerator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given data of a log entry as HTML
|
||||
* @param mixed $data
|
||||
* @param AbstractLogEntry $logEntry
|
||||
* @param string $fieldName
|
||||
* @return string
|
||||
*/
|
||||
public function formatData($data, AbstractLogEntry $logEntry, string $fieldName): string
|
||||
{
|
||||
if (is_string($data)) {
|
||||
$tmp = '<span class="text-muted user-select-none">"</span>' . mb_strimwidth(htmlspecialchars($data), 0, self::STRING_MAX_LENGTH, ) . '<span class="text-muted user-select-none">"</span>';
|
||||
|
||||
//Show special characters and line breaks
|
||||
$tmp = preg_replace('/\n/', '<span class="text-muted user-select-none">\\n</span><br>', $tmp);
|
||||
$tmp = preg_replace('/\r/', '<span class="text-muted user-select-none">\\r</span>', $tmp);
|
||||
$tmp = preg_replace('/\t/', '<span class="text-muted user-select-none">\\t</span>', $tmp);
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
if (is_bool($data)) {
|
||||
return $this->formatBool($data);
|
||||
}
|
||||
|
||||
if (is_int($data)) {
|
||||
return (string) $data;
|
||||
}
|
||||
|
||||
if (is_float($data)) {
|
||||
return (string) $data;
|
||||
}
|
||||
|
||||
if (is_null($data)) {
|
||||
return '<i>null</i>';
|
||||
}
|
||||
|
||||
if (is_array($data)) {
|
||||
//If the array contains only one element with the key @id, it is a reference to another entity (foreign key)
|
||||
if (isset($data['@id'])) {
|
||||
return $this->formatForeignKey($data, $logEntry, $fieldName);
|
||||
}
|
||||
|
||||
//If the array contains a "date", "timezone_type" and "timezone" key, it is a DateTime object
|
||||
if (isset($data['date'], $data['timezone_type'], $data['timezone'])) {
|
||||
return $this->formatDateTime($data);
|
||||
}
|
||||
|
||||
|
||||
return $this->formatJSON($data);
|
||||
}
|
||||
|
||||
|
||||
throw new \RuntimeException('Type of $data not supported (' . gettype($data) . ')');
|
||||
}
|
||||
|
||||
private function formatJSON(array $data): string
|
||||
{
|
||||
$json = htmlspecialchars(json_encode($data, JSON_PRETTY_PRINT), ENT_QUOTES | ENT_SUBSTITUTE);
|
||||
|
||||
return sprintf(
|
||||
'<div data-controller="elements--json-formatter" data-json="%s"></div>',
|
||||
$json
|
||||
);
|
||||
}
|
||||
|
||||
private function formatForeignKey(array $data, AbstractLogEntry $logEntry, string $fieldName): string
|
||||
{
|
||||
//Extract the id from the @id key
|
||||
$id = $data['@id'];
|
||||
|
||||
try {
|
||||
//Retrieve the class type from the logEntry and retrieve the doctrine metadata
|
||||
$classMetadata = $this->entityManager->getClassMetadata($logEntry->getTargetClass());
|
||||
$fkTargetClass = $classMetadata->getAssociationTargetClass($fieldName);
|
||||
|
||||
//Try to retrieve the entity from the database
|
||||
$entity = $this->entityManager->getRepository($fkTargetClass)->find($id);
|
||||
|
||||
//If the entity was found, return a label for this entity
|
||||
if ($entity) {
|
||||
return $this->elementTypeNameGenerator->formatLabelHTMLForEntity($entity, true);
|
||||
} else { //Otherwise the entity was deleted, so return the id
|
||||
return $this->elementTypeNameGenerator->formatElementDeletedHTML($fkTargetClass, $id);
|
||||
}
|
||||
|
||||
|
||||
} catch (\InvalidArgumentException|\ReflectionException $exception) {
|
||||
return '<i>unknown target class</i>: ' . $id;
|
||||
}
|
||||
}
|
||||
|
||||
private function formatDateTime(array $data): string
|
||||
{
|
||||
if (!isset($data['date'], $data['timezone_type'], $data['timezone'])) {
|
||||
return '<i>unknown DateTime format</i>';
|
||||
}
|
||||
|
||||
$date = $data['date'];
|
||||
$timezoneType = $data['timezone_type'];
|
||||
$timezone = $data['timezone'];
|
||||
|
||||
if (!is_string($date) || !is_int($timezoneType) || !is_string($timezone)) {
|
||||
return '<i>unknown DateTime format</i>';
|
||||
}
|
||||
|
||||
try {
|
||||
$dateTime = new \DateTime($date, new \DateTimeZone($timezone));
|
||||
} catch (\Exception $exception) {
|
||||
return '<i>unknown DateTime format</i>';
|
||||
}
|
||||
|
||||
//Format it to the users locale
|
||||
$formatter = new \IntlDateFormatter(null, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::MEDIUM);
|
||||
return $formatter->format($dateTime);
|
||||
}
|
||||
|
||||
private function formatBool(bool $data): string
|
||||
{
|
||||
return $data ? $this->translator->trans('true') : $this->translator->trans('false');
|
||||
}
|
||||
}
|
||||
76
src/Services/LogSystem/LogDiffFormatter.php
Normal file
76
src/Services/LogSystem/LogDiffFormatter.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Services\LogSystem;
|
||||
|
||||
use Jfcherng\Diff\DiffHelper;
|
||||
|
||||
class LogDiffFormatter
|
||||
{
|
||||
/**
|
||||
* Format the diff between the given data, depending on the type of the data.
|
||||
* If the diff is not possible, an empty string is returned.
|
||||
* @param $old_data
|
||||
* @param $new_data
|
||||
* @return string
|
||||
*/
|
||||
public function formatDiff($old_data, $new_data): string
|
||||
{
|
||||
if (is_string($old_data) && is_string($new_data)) {
|
||||
return $this->diffString($old_data, $new_data);
|
||||
}
|
||||
|
||||
if (is_numeric($old_data) && is_numeric($new_data)) {
|
||||
return $this->diffNumeric($old_data, $new_data);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function diffString(string $old_data, string $new_data): string
|
||||
{
|
||||
return DiffHelper::calculate($old_data, $new_data, 'Combined',
|
||||
[ //Diff options
|
||||
'context' => 2,
|
||||
],
|
||||
[ //Render options
|
||||
'detailLevel' => 'char',
|
||||
'showHeader' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
private function diffNumeric($old_data, $new_data): string
|
||||
{
|
||||
if ((!is_numeric($old_data)) || (!is_numeric($new_data))) {
|
||||
throw new \InvalidArgumentException('The given data is not numeric.');
|
||||
}
|
||||
|
||||
$difference = $new_data - $old_data;
|
||||
|
||||
//Positive difference
|
||||
if ($difference > 0) {
|
||||
return sprintf('<span class="text-success">+%s</span>', $difference);
|
||||
} else if ($difference < 0) {
|
||||
return sprintf('<span class="text-danger">%s</span>', $difference);
|
||||
} else {
|
||||
return sprintf('<span class="text-muted">%s</span>', $difference);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -131,9 +131,9 @@ class LogEntryExtraFormatter
|
||||
|
||||
if (($context instanceof LogWithEventUndoInterface) && $context->isUndoEvent()) {
|
||||
if ('undo' === $context->getUndoMode()) {
|
||||
$array['log.undo_mode.undo'] = (string) $context->getUndoEventID();
|
||||
$array['log.undo_mode.undo'] = '#' . $context->getUndoEventID();
|
||||
} elseif ('revert' === $context->getUndoMode()) {
|
||||
$array['log.undo_mode.revert'] = (string) $context->getUndoEventID();
|
||||
$array['log.undo_mode.revert'] = '#' . $context->getUndoEventID();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
80
src/Services/LogSystem/LogLevelHelper.php
Normal file
80
src/Services/LogSystem/LogLevelHelper.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Services\LogSystem;
|
||||
|
||||
use App\Entity\LogSystem\AbstractLogEntry;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
class LogLevelHelper
|
||||
{
|
||||
/**
|
||||
* Returns the FontAwesome icon class for the given log level.
|
||||
* This returns just the specific icon class (so 'fa-info' for example).
|
||||
* @param string $logLevel The string representation of the log level (one of the LogLevel::* constants)
|
||||
* @return string
|
||||
*/
|
||||
public function logLevelToIconClass(string $logLevel): string
|
||||
{
|
||||
switch ($logLevel) {
|
||||
case LogLevel::DEBUG:
|
||||
return 'fa-bug';
|
||||
case LogLevel::INFO:
|
||||
return 'fa-info';
|
||||
case LogLevel::NOTICE:
|
||||
return 'fa-flag';
|
||||
case LogLevel::WARNING:
|
||||
return 'fa-exclamation-circle';
|
||||
case LogLevel::ERROR:
|
||||
return 'fa-exclamation-triangle';
|
||||
case LogLevel::CRITICAL:
|
||||
return 'fa-bolt';
|
||||
case LogLevel::ALERT:
|
||||
return 'fa-radiation';
|
||||
case LogLevel::EMERGENCY:
|
||||
return 'fa-skull-crossbones';
|
||||
default:
|
||||
return 'fa-question-circle';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Bootstrap table color class for the given log level.
|
||||
* @param string $logLevel The string representation of the log level (one of the LogLevel::* constants)
|
||||
* @return string The table color class (one of the 'table-*' classes)
|
||||
*/
|
||||
public function logLevelToTableColorClass(string $logLevel): string
|
||||
{
|
||||
|
||||
switch ($logLevel) {
|
||||
case LogLevel::EMERGENCY:
|
||||
case LogLevel::ALERT:
|
||||
case LogLevel::CRITICAL:
|
||||
case LogLevel::ERROR:
|
||||
return 'table-danger';
|
||||
case LogLevel::WARNING:
|
||||
return 'table-warning';
|
||||
case LogLevel::NOTICE:
|
||||
return 'table-info';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
94
src/Services/LogSystem/LogTargetHelper.php
Normal file
94
src/Services/LogSystem/LogTargetHelper.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Services\LogSystem;
|
||||
|
||||
use App\Entity\Attachments\Attachment;
|
||||
use App\Entity\Base\AbstractDBElement;
|
||||
use App\Entity\Contracts\NamedElementInterface;
|
||||
use App\Entity\LogSystem\AbstractLogEntry;
|
||||
use App\Entity\LogSystem\UserNotAllowedLogEntry;
|
||||
use App\Entity\Parameters\AbstractParameter;
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Entity\PriceInformations\Orderdetail;
|
||||
use App\Entity\PriceInformations\Pricedetail;
|
||||
use App\Entity\ProjectSystem\ProjectBOMEntry;
|
||||
use App\Exceptions\EntityNotSupportedException;
|
||||
use App\Repository\LogEntryRepository;
|
||||
use App\Services\ElementTypeNameGenerator;
|
||||
use App\Services\EntityURLGenerator;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class LogTargetHelper
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
protected LogEntryRepository $entryRepository;
|
||||
protected EntityURLGenerator $entityURLGenerator;
|
||||
protected ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, EntityURLGenerator $entityURLGenerator,
|
||||
ElementTypeNameGenerator $elementTypeNameGenerator, TranslatorInterface $translator)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->entryRepository = $entityManager->getRepository(AbstractLogEntry::class);
|
||||
|
||||
$this->entityURLGenerator = $entityURLGenerator;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
private function configureOptions(OptionsResolver $resolver): self
|
||||
{
|
||||
$resolver->setDefault('show_associated', true);
|
||||
$resolver->setDefault('showAccessDeniedPath', true);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function formatTarget(AbstractLogEntry $context, array $options = []): string
|
||||
{
|
||||
$optionsResolver = new OptionsResolver();
|
||||
$this->configureOptions($optionsResolver);
|
||||
$options = $optionsResolver->resolve($options);
|
||||
|
||||
if ($context instanceof UserNotAllowedLogEntry && $options['showAccessDeniedPath']) {
|
||||
return htmlspecialchars($context->getPath());
|
||||
}
|
||||
|
||||
/** @var AbstractLogEntry $context */
|
||||
$target = $this->entryRepository->getTargetElement($context);
|
||||
|
||||
//If the target is null and the context has a target, that means that the target was deleted. Show it that way.
|
||||
if ($target === null) {
|
||||
if ($context->hasTarget()) {
|
||||
return $this->elementTypeNameGenerator->formatElementDeletedHTML($context->getTargetClass(),
|
||||
$context->getTargetId());
|
||||
}
|
||||
//If no target is set, we can't do anything
|
||||
return '';
|
||||
}
|
||||
|
||||
//Otherwise we can return a label for the target
|
||||
return $this->elementTypeNameGenerator->formatLabelHTMLForEntity($target, $options['show_associated']);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ class TimeTravel
|
||||
public function applyEntry(AbstractDBElement $element, TimeTravelInterface $logEntry): void
|
||||
{
|
||||
//Skip if this does not provide any info...
|
||||
if (!$logEntry->hasOldDataInformations()) {
|
||||
if (!$logEntry->hasOldDataInformation()) {
|
||||
return;
|
||||
}
|
||||
if (!$element instanceof TimeStampableInterface) {
|
||||
|
||||
@@ -71,6 +71,8 @@ final class EntityExtension extends AbstractExtension
|
||||
new TwigFunction('entity_type', [$this, 'getEntityType']),
|
||||
/* Returns the URL to the given entity */
|
||||
new TwigFunction('entity_url', [$this, 'generateEntityURL']),
|
||||
/* Returns the URL to the given entity in timetravel mode */
|
||||
new TwigFunction('timetravel_url', [$this->entityURLGenerator, 'timetravelURL']),
|
||||
/* Generates a JSON array of the given tree */
|
||||
new TwigFunction('tree_data', [$this, 'treeData']),
|
||||
|
||||
|
||||
47
src/Twig/LogExtension.php
Normal file
47
src/Twig/LogExtension.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Twig;
|
||||
|
||||
use App\Services\LogSystem\LogDataFormatter;
|
||||
use App\Services\LogSystem\LogDiffFormatter;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
final class LogExtension extends AbstractExtension
|
||||
{
|
||||
|
||||
private LogDataFormatter $logDataFormatter;
|
||||
private LogDiffFormatter $logDiffFormatter;
|
||||
|
||||
public function __construct(LogDataFormatter $logDataFormatter, LogDiffFormatter $logDiffFormatter)
|
||||
{
|
||||
$this->logDataFormatter = $logDataFormatter;
|
||||
$this->logDiffFormatter = $logDiffFormatter;
|
||||
}
|
||||
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new TwigFunction('format_log_data', [$this->logDataFormatter, 'formatData'], ['is_safe' => ['html']]),
|
||||
new TwigFunction('format_log_diff', [$this->logDiffFormatter, 'formatDiff'], ['is_safe' => ['html']]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{# @var entry \App\Entity\LogSystem\CollectionElementDeleted #}
|
||||
|
||||
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
|
||||
|
||||
<p class="m-0">
|
||||
<b>{% trans %}log.collection_deleted.deleted{% endtrans %}</b>:
|
||||
{{ entity_type_label(entry.deletedElementClass) }} #{{ entry.deletedElementID }}
|
||||
{% if entry.oldName is not empty %}
|
||||
({{ entry.oldName }})
|
||||
{% endif %}
|
||||
</p>
|
||||
<p class="m-0">
|
||||
<b>{% trans %}log.collection_deleted.on_collection{% endtrans %}</b>:
|
||||
{{ log_helper.translate_field(entry.collectionName) }}
|
||||
</p>
|
||||
@@ -0,0 +1,23 @@
|
||||
{# @var entry \App\Entity\LogSystem\DatabaseUpdatedLogEntry #}
|
||||
|
||||
{% if entry.successful %}
|
||||
<h5><span class="badge bg-success badge-success">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
{% trans %}log.database_updated.success{% endtrans %}
|
||||
</span></h5>
|
||||
{% else %}
|
||||
<h5><span class="badge bg-danger badge-danger">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
{% trans %}log.database_updated.failed{% endtrans %}</span>
|
||||
</h5>
|
||||
{% endif %}
|
||||
|
||||
<span class="badge bg-secondary badge-secondary badge-pill" title="{% trans %}log.database_updated.old_version{% endtrans %}">
|
||||
<i class="fa-solid fa-database"></i>
|
||||
{{ entry.oldVersion }}
|
||||
</span>
|
||||
<i class="fa-solid fa-arrow-right-long"></i>
|
||||
<span class="badge bg-primary badge-primary badge-pill" title="{% trans %}log.database_updated.new_version{% endtrans %}">
|
||||
<i class="fa-solid fa-database"></i>
|
||||
{{ entry.newVersion }}
|
||||
</span>
|
||||
@@ -0,0 +1,11 @@
|
||||
{# @var entry \App\Entity\LogSystem\ElementCreatedLogEntry #}
|
||||
|
||||
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
|
||||
|
||||
{{ log_helper.comment_field(entry) }}
|
||||
{% if entry.creationInstockValue %}
|
||||
<p>
|
||||
<b>{% trans %}log.element_created.original_instock{% endtrans %}:</b>
|
||||
{{ entry.creationInstockValue }}
|
||||
</p>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,8 @@
|
||||
{# @var entry \App\Entity\LogSystem\ElementDeletedLogEntry #}
|
||||
|
||||
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
|
||||
|
||||
<span class="badge badge-notice"></span>
|
||||
|
||||
{{ log_helper.comment_field(entry) }}
|
||||
{{ log_helper.data_change_table(entry) }}
|
||||
11
templates/log_system/details/_extra_element_edited.html.twig
Normal file
11
templates/log_system/details/_extra_element_edited.html.twig
Normal file
@@ -0,0 +1,11 @@
|
||||
{# @var entry \App\Entity\LogSystem\ElementDeletedLogEntry #}
|
||||
|
||||
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
|
||||
|
||||
{% if entry.undoEvent %}
|
||||
<span class="badge badge-info bg-info">Test</span>
|
||||
{% endif %}
|
||||
|
||||
{{ log_helper.comment_field(entry) }}
|
||||
|
||||
{{ log_helper.data_change_table(entry) }}
|
||||
@@ -0,0 +1,9 @@
|
||||
{# @var entry \App\Entity\LogSystem\UserLoginLogEntry #}
|
||||
|
||||
IP:
|
||||
<span class="badge bg-primary badge-primary">
|
||||
<i class="fa-solid fa-network-wired"></i>
|
||||
{{ entry.iPAddress }}
|
||||
</span>
|
||||
|
||||
<p class="text-muted">{% trans %}log.user_login.ip_anonymize_hint{% endtrans %}</p>
|
||||
9
templates/log_system/details/_extra_user_login.html.twig
Normal file
9
templates/log_system/details/_extra_user_login.html.twig
Normal file
@@ -0,0 +1,9 @@
|
||||
{# @var entry \App\Entity\LogSystem\UserLoginLogEntry #}
|
||||
|
||||
{% trans %}log.user_login.login_from_ip{% endtrans %}:
|
||||
<span class="badge bg-primary badge-primary">
|
||||
<i class="fa-solid fa-network-wired"></i>
|
||||
{{ entry.iPAddress }}
|
||||
</span>
|
||||
|
||||
<p class="text-muted">{% trans %}log.user_login.ip_anonymize_hint{% endtrans %}</p>
|
||||
@@ -0,0 +1,4 @@
|
||||
{# @var entry \App\Entity\LogSystem\UserNotAllowedLogEntry #}
|
||||
|
||||
{% trans %}log.user_not_allowed.unauthorized_access_attempt_to{% endtrans %}: <code>{{ entry.path }}</code>
|
||||
<p class="text-muted">{% trans %}log.user_not_allowed.hint{% endtrans %}</p>
|
||||
143
templates/log_system/details/helper.macro.html.twig
Normal file
143
templates/log_system/details/helper.macro.html.twig
Normal file
@@ -0,0 +1,143 @@
|
||||
{% macro undo_buttons(entry, target_element) %}
|
||||
{# @var entry \App\Entity\LogSystem\ElementEditedLogEntry|\App\Entity\LogSystem\ElementDeletedLogEntry entry #}
|
||||
{% set disabled = not is_granted('revert_element', entry.targetClass) %}
|
||||
|
||||
{% if entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted')
|
||||
or (entry is instanceof('App\\Entity\\LogSystem\\ElementDeletedLogEntry') and entry.hasOldDataInformation) %}
|
||||
|
||||
{% set icon = 'fa-trash-restore' %}
|
||||
{% set title = 'log.undo.undelete'|trans %}
|
||||
{% set title_short = 'log.undo.undelete.short'|trans %}
|
||||
|
||||
{% elseif entry is instanceof('App\\Entity\\LogSystem\\ElementCreatedLogEntry')
|
||||
or (entry is instanceof('App\\Entity\\LogSystem\\ElementEditedLogEntry') and entry.hasOldDataInformation) %}
|
||||
|
||||
{% set icon = 'fa-undo' %}
|
||||
{% set title = 'log.undo.undo'|trans %}
|
||||
{% set title_short = 'log.undo.undo.short'|trans %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{{ path("log_undo") }}"
|
||||
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
|
||||
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
|
||||
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
|
||||
|
||||
<input type="hidden" name="redirect_back" value="{{ app.request.requestUri }}">
|
||||
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button type="submit" class="btn btn-outline-secondary" name="undo" value="{{ entry.id }}" {% if disabled %}disabled{% endif %}>
|
||||
<i class="fas fa-fw {{ icon }}" title="{{ title }}"></i> {{ title_short }}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-outline-secondary" name="revert" value="{{ entry.id }}" {% if disabled %}disabled{% endif %}>
|
||||
<i class="fas fa-fw fa-backward" title="{% trans %}log.undo.revert{% endtrans %}"></i> {{ 'log.undo.revert.short' | trans }}
|
||||
</button>
|
||||
|
||||
{# View button #}
|
||||
{% if target_element and ((attribute(entry, 'oldDataInformation') is defined and entry.oldDataInformation)
|
||||
or entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted')) %}
|
||||
<a class="btn btn-outline-secondary" href="{{ timetravel_url(target_element, entry.timestamp)}}"><i class="fas fa-fw fa-eye"></i>
|
||||
{% trans %}log.view_version{% endtrans %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro comment_field(entry) %}
|
||||
{# @var entry \App\Entity\Contracts\LogWithComment #}
|
||||
<p class="mb-0">
|
||||
<b>{% trans %}edit.log_comment{% endtrans %}:</b>
|
||||
{% if entry.comment %}
|
||||
{{ entry.comment }}
|
||||
{% else %}
|
||||
<span class="text-muted">{% trans %}log.no_comment{% endtrans %}</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro translate_field(field) %}
|
||||
{% set trans_key = 'log.element_edited.changed_fields.'~field %}
|
||||
{# If the translation key is not found, the translation key is returned, and we dont show the translation #}
|
||||
{% if trans_key|trans != trans_key %}
|
||||
{{ ('log.element_edited.changed_fields.'~field) | trans }}
|
||||
<span class="text-muted">({{ field }})</span>
|
||||
{% else %}
|
||||
{{ field }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro data_change_table(entry) %}
|
||||
{# @var entry \App\Entity\LogSystem\ElementEditedLogEntry|\App\Entity\LogSystem\ElementDeletedLogEntry entry #}
|
||||
|
||||
{% set fields, old_data, new_data = {}, {}, {} %}
|
||||
|
||||
{# For log entries where only the changed fields are saved, this is the last executed assignment #}
|
||||
{% if attribute(entry, 'changedFieldInfo') is defined and entry.changedFieldsInfo %}
|
||||
{% set fields = entry.changedFields %}
|
||||
{% endif %}
|
||||
|
||||
{# For log entries, where we know the old data, this is the last exectuted assignment #}
|
||||
{% if attribute(entry, 'oldDataInformation') is defined and entry.oldDataInformation %}
|
||||
{# We have to use the keys of oldData here, as changedFields might not be available #}
|
||||
{% set fields = entry.oldData | keys %}
|
||||
{% set old_data = entry.oldData %}
|
||||
{% endif %}
|
||||
|
||||
{# For log entries, where we have new data, we define it #}
|
||||
{% if attribute(entry, 'newDataInformation') is defined and entry.newDataInformation %}
|
||||
{# We have to use the keys of oldData here, as changedFields might not be available #}
|
||||
{% set fields = entry.newData | keys %}
|
||||
{% set new_data = entry.newData %}
|
||||
{% endif %}
|
||||
|
||||
{% if fields is not empty %}
|
||||
<table class="table table-hover table-striped table-sm table-bordered mt-2">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans %}log.element_changed.field{% endtrans %}</th>
|
||||
{% if old_data is not empty %}
|
||||
<th>{% trans %}log.element_changed.data_before{% endtrans %}</th>
|
||||
{% endif %}
|
||||
{% if new_data is not empty %}
|
||||
<th>{% trans %}log.element_changed.data_after{% endtrans %}</th>
|
||||
{% endif %}
|
||||
{% if new_data is not empty and old_data is not empty %} {# Diff column #}
|
||||
<th>{% trans %}log.element_changed.diff{% endtrans %}</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for field in fields %}
|
||||
<tr>
|
||||
<td title="{{ field }}">
|
||||
{{ _self.translate_field(field) }}
|
||||
</td>
|
||||
{% if old_data is not empty %}
|
||||
<td>
|
||||
{% if old_data[field] is defined %}
|
||||
{{ format_log_data(old_data[field], entry, field) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
{% if new_data is not empty %}
|
||||
<td>
|
||||
{% if new_data[field] is defined %}
|
||||
{{ format_log_data(new_data[field], entry, field) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
{% if new_data is not empty and old_data is not empty %}
|
||||
<td>
|
||||
{% if new_data[field] is defined and old_data[field] is defined %}
|
||||
{{ format_log_diff(old_data[field], new_data[field]) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
117
templates/log_system/details/log_details.html.twig
Normal file
117
templates/log_system/details/log_details.html.twig
Normal file
@@ -0,0 +1,117 @@
|
||||
{% extends "main_card.html.twig" %}
|
||||
|
||||
{% import "helper.twig" as helper %}
|
||||
{% import "log_system/details/helper.macro.html.twig" as log_helper %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}log.details.title{% endtrans %}:
|
||||
{{ ('log.type.' ~ log_entry.type) | trans }} ({{ log_entry.timestamp | format_datetime('short') }})
|
||||
{% endblock %}
|
||||
|
||||
{% block card_title %}
|
||||
<i class="fas fa-binoculars"></i>
|
||||
{% trans %}log.details.title{% endtrans %}:
|
||||
<i>{{ ('log.type.' ~ log_entry.type) | trans }}</i> ({{ log_entry.timestamp | format_datetime('short') }})
|
||||
<span class="float-end">ID: {{ log_entry.iD }}</span>
|
||||
{% endblock %}
|
||||
|
||||
{% block card_body %}
|
||||
<table class="table table-striped table-hover mb-0 {{ log_level_helper.logLevelToTableColorClass(log_entry.levelString) }}">
|
||||
<tr>
|
||||
<td>{% trans %}log.timestamp{% endtrans %}</td>
|
||||
<td>{{ log_entry.timestamp | format_datetime('full') }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}log.type{% endtrans %}</td>
|
||||
<td>
|
||||
{{ ('log.type.' ~ log_entry.type) | trans }}
|
||||
{% if log_entry.type == 'part_stock_changed' %}
|
||||
({{ ('log.part_stock_changed.' ~ log_entry.instockChangeType)|trans }})
|
||||
{% endif %}
|
||||
|
||||
{% if log_entry is instanceof('App\\Entity\\Contracts\\LogWithEventUndoInterface') and log_entry.undoEvent %}
|
||||
<b>({{ ('log.undo_mode.' ~ log_entry.undoMode)|trans }}: <a href="{{ path('log_details', {"id": log_entry.UndoEventID}) }}">#{{ log_entry.UndoEventID }}</a>)</b>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}log.level{% endtrans %}</td>
|
||||
<td>
|
||||
<i class="fa-solid {{ log_level_helper.logLevelToIconClass(log_entry.levelString) }} fa-fw"></i>
|
||||
{{ ('log.level.'~ log_entry.levelString)|trans }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}log.user{% endtrans %}
|
||||
<td>
|
||||
{% if log_entry.cLIEntry %}
|
||||
<i class="fa-solid fa-terminal"></i>
|
||||
{{ log_entry.cLIUsername }} ({% trans %}log.cli_user{% endtrans %})
|
||||
{% else %}
|
||||
{% if log_entry.user %}
|
||||
{{ helper.user_icon_link(log_entry.user) }} (@{{ log_entry.user.username }})
|
||||
{% else %}
|
||||
@{{ log_entry.username }} ({% trans %}log.target_deleted{% endtrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans %}log.target{% endtrans %}</td>
|
||||
<td>{{ target_html|raw }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col-6">
|
||||
{% if log_entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted')
|
||||
or log_entry is instanceof('App\\Entity\\LogSystem\\ElementDeletedLogEntry')
|
||||
or log_entry is instanceof('App\\Entity\\LogSystem\\ElementCreatedLogEntry')
|
||||
or log_entry is instanceof('App\\Entity\\LogSystem\\ElementEditedLogEntry')
|
||||
%}
|
||||
{{ log_helper.undo_buttons(log_entry, target_element) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="col-6 text-end">
|
||||
<form method="post" class="" action="{{ path('log_delete', {'id': log_entry.iD}) }}" {{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
|
||||
data-delete-title="{% trans %}log.delete.message.title{% endtrans %}"
|
||||
data-delete-message="{% trans %}log.delete.message{% endtrans %}">
|
||||
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ log_entry.id) }}">
|
||||
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger" {% if not is_granted('delete', log_entry) %}disabled{% endif %}>
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
{% trans %}log.details.delete_entry{% endtrans %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# This assignment is to improve autocomplete on the subpages, as PHPstorm ignores typehints for log_entry #}
|
||||
{% set entry = log_entry %}
|
||||
{% if log_entry is instanceof('App\\Entity\\LogSystem\\DatabaseUpdatedLogEntry') %}
|
||||
{% include "log_system/details/_extra_database_updated.html.twig" %}
|
||||
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\ElementCreatedLogEntry') %}
|
||||
{% include "log_system/details/_extra_element_created.html.twig" %}
|
||||
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\ElementEditedLogEntry') %}
|
||||
{% include "log_system/details/_extra_element_edited.html.twig" %}
|
||||
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\ElementDeletedLogEntry') %}
|
||||
{% include "log_system/details/_extra_element_deleted.html.twig" %}
|
||||
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\UserLoginLogEntry')
|
||||
or log_entry is instanceof('App\\Entity\\LogSystem\\UserLogoutLogEntry') %}
|
||||
{% include "log_system/details/_extra_user_login.html.twig" %}
|
||||
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\UserNotAllowedLogEntry') %}
|
||||
{% include "log_system/details/_extra_user_not_allowed.html.twig" %}
|
||||
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\SecurityEventLogEntry') %}
|
||||
{% include "log_system/details/_extra_security_event.html.twig" %}
|
||||
{% elseif log_entry is instanceof('App\\Entity\\LogSystem\\CollectionElementDeleted') %}
|
||||
{% include "log_system/details/_extra_collection_element_deleted.html.twig" %}
|
||||
{% else %}
|
||||
{{ extra_html | raw }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -4654,7 +4654,7 @@ Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertr
|
||||
</notes>
|
||||
<segment state="translated">
|
||||
<source>log.undo.undelete</source>
|
||||
<target>Bauteil wiederherstellen</target>
|
||||
<target>Element wiederherstellen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="PI8faHR" name="log.undo.undo">
|
||||
@@ -11255,5 +11255,179 @@ Element 3</target>
|
||||
<target>Weniger als erwünscht</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="cdnsW4q" name="log.cli_user">
|
||||
<segment state="translated">
|
||||
<source>log.cli_user</source>
|
||||
<target>CLI Benutzer</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4GTAJ9E" name="log.element_edited.changed_fields.part_owner_must_match">
|
||||
<segment state="translated">
|
||||
<source>log.element_edited.changed_fields.part_owner_must_match</source>
|
||||
<target>Der Bauteilebesitzer muss dem Lagerortbesitzer entsprechen!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="u6qFa_j" name="part.filter.lessThanDesired">
|
||||
<segment state="translated">
|
||||
<source>part.filter.lessThanDesired</source>
|
||||
<target>Weniger vorhanden als gewünscht (Gesamtmenge < Mindestmenge)</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="lHTN.a1" name="part.filter.lotOwner">
|
||||
<segment state="translated">
|
||||
<source>part.filter.lotOwner</source>
|
||||
<target>Besitzer des Bestands</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="47OCK_W" name="user.show_email_on_profile.label">
|
||||
<segment state="translated">
|
||||
<source>user.show_email_on_profile.label</source>
|
||||
<target>E-Mail-Adresse auf öffentlicher Profilseite anzeigen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="4rkjIk2" name="log.details.title">
|
||||
<segment state="translated">
|
||||
<source>log.details.title</source>
|
||||
<target>Logdetails</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="aeYMkHS" name="log.user_login.login_from_ip">
|
||||
<segment state="translated">
|
||||
<source>log.user_login.login_from_ip</source>
|
||||
<target>Login von IP-Adresse</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="9jOklgS" name="log.user_login.ip_anonymize_hint">
|
||||
<segment state="translated">
|
||||
<source>log.user_login.ip_anonymize_hint</source>
|
||||
<target>Wenn die letzten Stellen der IP-Adresse fehlen, dann ist der DSGV Modus aktiviert, bei dem IP-Adressen anonymisiert werden.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="kaMyDVi" name="log.user_not_allowed.unauthorized_access_attempt_to">
|
||||
<segment state="translated">
|
||||
<source>log.user_not_allowed.unauthorized_access_attempt_to</source>
|
||||
<target>Unerlaubter Zugriffsversuch auf Seite</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="EibB1Wh" name="log.user_not_allowed.hint">
|
||||
<segment state="translated">
|
||||
<source>log.user_not_allowed.hint</source>
|
||||
<target>Die Anfrage wurde blockiert. Es sollte keine weitere Aktion nötig sein.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="JVE17kW" name="log.no_comment">
|
||||
<segment state="translated">
|
||||
<source>log.no_comment</source>
|
||||
<target>Kein Kommentar</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="5xvPvME" name="log.element_changed.field">
|
||||
<segment state="translated">
|
||||
<source>log.element_changed.field</source>
|
||||
<target>Feld</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="vufWYhV" name="log.element_changed.data_before">
|
||||
<segment state="translated">
|
||||
<source>log.element_changed.data_before</source>
|
||||
<target>Daten vor Änderung</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="qk2u9Qg" name="error_table.error">
|
||||
<segment state="translated">
|
||||
<source>error_table.error</source>
|
||||
<target>Während der Anfrage trat ein Fehler auf.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="tLXzED2" name="part.table.invalid_regex">
|
||||
<segment state="translated">
|
||||
<source>part.table.invalid_regex</source>
|
||||
<target>Ungültiger regulärer Ausdruck (regex)</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="VKPOkNO" name="log.element_changed.data_after">
|
||||
<segment state="translated">
|
||||
<source>log.element_changed.data_after</source>
|
||||
<target>Daten nach Änderung</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DiNGTl8" name="log.element_changed.diff">
|
||||
<segment state="translated">
|
||||
<source>log.element_changed.diff</source>
|
||||
<target>Unterschied</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="OB_fVDI" name="log.undo.undo.short">
|
||||
<segment state="translated">
|
||||
<source>log.undo.undo.short</source>
|
||||
<target>Rückgängig machen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="AvoT6DL" name="log.undo.revert.short">
|
||||
<segment state="translated">
|
||||
<source>log.undo.revert.short</source>
|
||||
<target>Auf Version zurücksetzen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="YdXQd2_" name="log.view_version">
|
||||
<segment state="translated">
|
||||
<source>log.view_version</source>
|
||||
<target>Version anzeigen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="l47W4kt" name="log.undo.undelete.short">
|
||||
<segment state="translated">
|
||||
<source>log.undo.undelete.short</source>
|
||||
<target>Wiederherstellen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="PDJYeqj" name="log.element_edited.changed_fields.id">
|
||||
<segment state="translated">
|
||||
<source>log.element_edited.changed_fields.id</source>
|
||||
<target>ID</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="cQTNNI7" name="log.element_edited.changed_fields.id_owner">
|
||||
<segment state="translated">
|
||||
<source>log.element_edited.changed_fields.id_owner</source>
|
||||
<target>Besitzer</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="h1eBlp8" name="log.element_edited.changed_fields.parent_id">
|
||||
<segment state="translated">
|
||||
<source>log.element_edited.changed_fields.parent_id</source>
|
||||
<target>Übergeordnetes Element</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="GUthgcU" name="log.details.delete_entry">
|
||||
<segment state="translated">
|
||||
<source>log.details.delete_entry</source>
|
||||
<target>Logeintrag löschen</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Wv0WAmO" name="log.delete.message.title">
|
||||
<segment state="translated">
|
||||
<source>log.delete.message.title</source>
|
||||
<target>Wollen Sie diesen Logeintrag wirklich löschen?</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="5tbpaLR" name="log.delete.message">
|
||||
<segment state="translated">
|
||||
<source>log.delete.message</source>
|
||||
<target>Wenn dies ein Historieeintrag für ein Element ist, dann wird das Löschen zu Datenverlust der Historie führen! Dies kann unerwartete Ergebnisse liefern, wenn die Zeitreisefunktion verwendet wird.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="P.c4WmY" name="log.collection_deleted.on_collection">
|
||||
<segment state="translated">
|
||||
<source>log.collection_deleted.on_collection</source>
|
||||
<target>in Kollektion</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id=".wiLJk6" name="log.element_edited.changed_fields.attachments">
|
||||
<segment state="translated">
|
||||
<source>log.element_edited.changed_fields.attachments</source>
|
||||
<target>Dateianhänge</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="en">
|
||||
<file id="security.en">
|
||||
<unit id="aazoCks" name="user.login_error.user_disabled">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>user.login_error.user_disabled</source>
|
||||
<target>Your account is disabled! Contact an administrator if you think this is wrong.</target>
|
||||
</segment>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<note priority="1">Part-DB1\src\Entity\UserSystem\Group.php:0</note>
|
||||
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>part.master_attachment.must_be_picture</source>
|
||||
<target>The preview attachment must be a valid picture!</target>
|
||||
</segment>
|
||||
@@ -82,7 +82,7 @@
|
||||
<note priority="1">src\Entity\StructuralDBElement.php:0</note>
|
||||
<note priority="1">src\Entity\Supplier.php:0</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>structural.entity.unique_name</source>
|
||||
<target>An element with this name already exists on this level!</target>
|
||||
</segment>
|
||||
@@ -102,7 +102,7 @@
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>parameters.validator.min_lesser_typical</source>
|
||||
<target>Value must be lesser or equal the the typical value ({{ compared_value }}).</target>
|
||||
</segment>
|
||||
@@ -122,7 +122,7 @@
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>parameters.validator.min_lesser_max</source>
|
||||
<target>Value must be lesser than the maximum value ({{ compared_value }}).</target>
|
||||
</segment>
|
||||
@@ -142,7 +142,7 @@
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>parameters.validator.max_greater_typical</source>
|
||||
<target>Value must be greater or equal than the typical value ({{ compared_value }}).</target>
|
||||
</segment>
|
||||
@@ -152,7 +152,7 @@
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.user.username_already_used</source>
|
||||
<target>A user with this name is already exisiting</target>
|
||||
</segment>
|
||||
@@ -162,7 +162,7 @@
|
||||
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>user.invalid_username</source>
|
||||
<target>The username must contain only letters, numbers, underscores, dots, pluses or minuses!</target>
|
||||
</segment>
|
||||
@@ -171,7 +171,7 @@
|
||||
<notes>
|
||||
<note category="state" priority="1">obsolete</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.noneofitschild.self</source>
|
||||
<target>An element can not be its own parent!</target>
|
||||
</segment>
|
||||
@@ -180,121 +180,121 @@
|
||||
<notes>
|
||||
<note category="state" priority="1">obsolete</note>
|
||||
</notes>
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.noneofitschild.children</source>
|
||||
<target>You can not assign children element as parent (This would cause loops)!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ayNr6QK" name="validator.select_valid_category">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.select_valid_category</source>
|
||||
<target>Please select a valid category!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="6vIlN5q" name="validator.part_lot.only_existing">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.only_existing</source>
|
||||
<target>Can not add new parts to this location as it is marked as "Only Existing"</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="3xoKOIS" name="validator.part_lot.location_full.no_increase">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.location_full.no_increase</source>
|
||||
<target>Location is full. Amount can not be increased (new value must be smaller than {{ old_amount }}).</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="R6Ov4Yt" name="validator.part_lot.location_full">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.location_full</source>
|
||||
<target>Location is full. Can not add new parts to it.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="BNQk2e7" name="validator.part_lot.single_part">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.part_lot.single_part</source>
|
||||
<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>
|
||||
<segment state="translated">
|
||||
<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>
|
||||
<segment state="translated">
|
||||
<source>validator.orderdetail.supplier_must_not_be_null</source>
|
||||
<target>You must select an supplier!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="k5DDdB4" name="validator.measurement_unit.use_si_prefix_needs_unit">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.measurement_unit.use_si_prefix_needs_unit</source>
|
||||
<target>To enable SI prefixes, you have to set a unit symbol!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="DuzIOCr" name="part.ipn.must_be_unique">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>part.ipn.must_be_unique</source>
|
||||
<target>The internal part number must be unique. {{ value }} is already in use!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Z4Kuuo2" name="validator.project.bom_entry.name_or_part_needed">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.project.bom_entry.name_or_part_needed</source>
|
||||
<target>You have to choose a part for a part BOM entry or set a name for a non-part BOM entry.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="WF_v4ih" name="project.bom_entry.name_already_in_bom">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.name_already_in_bom</source>
|
||||
<target>There is already an BOM entry with this name!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="5v4p85H" name="project.bom_entry.part_already_in_bom">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.part_already_in_bom</source>
|
||||
<target>This part already exists in the BOM!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="3lM32Tw" name="project.bom_entry.mountnames_quantity_mismatch">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.mountnames_quantity_mismatch</source>
|
||||
<target>The number of mountnames has to match the BOMs quantity!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="x47D5WT" name="project.bom_entry.can_not_add_own_builds_part">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.can_not_add_own_builds_part</source>
|
||||
<target>You can not add a project's own builds part to the BOM.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="2x2XDI_" name="project.bom_has_to_include_all_subelement_parts">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>project.bom_has_to_include_all_subelement_parts</source>
|
||||
<target>The project BOM has to include all subprojects builds parts. Part %part_name% of project %project_name% missing!</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="U9b1EzD" name="project.bom_entry.price_not_allowed_on_parts">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>project.bom_entry.price_not_allowed_on_parts</source>
|
||||
<target>Prices are not allowed on BOM entries associated with a part. Define the price on the part instead.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="ID056SR" name="validator.project_build.lot_bigger_than_needed">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.project_build.lot_bigger_than_needed</source>
|
||||
<target>You have selected more quantity to withdraw than needed! Remove unnecessary quantity.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="6hV5UqD" name="validator.project_build.lot_smaller_than_needed">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>validator.project_build.lot_smaller_than_needed</source>
|
||||
<target>You have selected less quantity to withdraw than needed for the build! Add additional quantity.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="G9ZKt.4" name="part.name.must_match_category_regex">
|
||||
<segment>
|
||||
<segment state="translated">
|
||||
<source>part.name.must_match_category_regex</source>
|
||||
<target>The part name does not match the regular expression stated by the category: %regex%</target>
|
||||
</segment>
|
||||
|
||||
Reference in New Issue
Block a user