mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-02-21 01:02:53 +01:00
Compare commits
437 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39009a71d5 | ||
|
|
0430178fe2 | ||
|
|
cf9df883c9 | ||
|
|
198befe2bc | ||
|
|
7195bd6cd6 | ||
|
|
a5fa2da80c | ||
|
|
593d37f37c | ||
|
|
2ddd6753ca | ||
|
|
9537c4f210 | ||
|
|
e0ce6ba165 | ||
|
|
ee50ce26f8 | ||
|
|
94a6de4a90 | ||
|
|
d5902314c3 | ||
|
|
60125534ec | ||
|
|
48385cadc9 | ||
|
|
ba6abe6ca7 | ||
|
|
79ad243bf4 | ||
|
|
5ab21e019d | ||
|
|
d8469efba2 | ||
|
|
316b09ddf3 | ||
|
|
866ef73774 | ||
|
|
138d5c6e0f | ||
|
|
4bed50d894 | ||
|
|
55943f5d8f | ||
|
|
133652c296 | ||
|
|
b9331ac1ef | ||
|
|
08f7b2cc87 | ||
|
|
1a2bdaf8e5 | ||
|
|
d81dec78ae | ||
|
|
f78bd03521 | ||
|
|
6aa16272d8 | ||
|
|
e80f7c08ab | ||
|
|
675f05f0fb | ||
|
|
b1f23e1684 | ||
|
|
d612164885 | ||
|
|
b257e1d5f7 | ||
|
|
f26776ecd5 | ||
|
|
bf4a23652c | ||
|
|
e7681aedb1 | ||
|
|
098fcb29fb | ||
|
|
eb46ea19e3 | ||
|
|
99ee05a90f | ||
|
|
fd31f983af | ||
|
|
80bae4167f | ||
|
|
eaee4af715 | ||
|
|
7d4723c3e4 | ||
|
|
33a0981981 | ||
|
|
b62dc1241d | ||
|
|
e2270aec38 | ||
|
|
73346fcdaf | ||
|
|
7b112512a9 | ||
|
|
0e5613b57b | ||
|
|
e66ff40733 | ||
|
|
73d61f7440 | ||
|
|
dedb3071d6 | ||
|
|
a43ee52086 | ||
|
|
97ccb0cb21 | ||
|
|
1fb334b0ca | ||
|
|
fa4af99525 | ||
|
|
b3153dac68 | ||
|
|
c981476706 | ||
|
|
1a3e5ec705 | ||
|
|
aaff0835a3 | ||
|
|
9bf814d4cd | ||
|
|
b5c0f37f88 | ||
|
|
05d73d2f68 | ||
|
|
ff284d056c | ||
|
|
2393c759f3 | ||
|
|
0a983513ea | ||
|
|
c737348cea | ||
|
|
e8e2258357 | ||
|
|
d847b74522 | ||
|
|
5750e7dbdf | ||
|
|
ffe76f9d2e | ||
|
|
5b1ad541a8 | ||
|
|
4824a82c3f | ||
|
|
f7cea1100c | ||
|
|
827dd01e28 | ||
|
|
d969f49ecc | ||
|
|
0f336b6f89 | ||
|
|
43cc37d10f | ||
|
|
6a00b8e168 | ||
|
|
1b3fc2c23c | ||
|
|
8e96971b9c | ||
|
|
8e39e330fe | ||
|
|
15ba6572df | ||
|
|
1c222ff293 | ||
|
|
2fb1ec7f8a | ||
|
|
70f1db9619 | ||
|
|
11be65678e | ||
|
|
80ed064cd6 | ||
|
|
62b1e33616 | ||
|
|
52f2ef6d30 | ||
|
|
8ace78a873 | ||
|
|
5c30210534 | ||
|
|
1d03b6c38d | ||
|
|
d3ead8742e | ||
|
|
ed6b0057b7 | ||
|
|
90fbcb88d8 | ||
|
|
be2ed52d93 | ||
|
|
f1af19a52a | ||
|
|
4c4501073c | ||
|
|
b8b9a416ac | ||
|
|
fc7e436ca9 | ||
|
|
1de1eebc59 | ||
|
|
a4d411656b | ||
|
|
1ec4266f96 | ||
|
|
61f02d693f | ||
|
|
cd80552ce7 | ||
|
|
d59b8817c3 | ||
|
|
8ce5f4a796 | ||
|
|
2e8cb35acc | ||
|
|
c0f626e9bd | ||
|
|
2ddfe48aba | ||
|
|
2c6de84c9a | ||
|
|
87cf4c2d08 | ||
|
|
3a8c835880 | ||
|
|
e2dbd3d873 | ||
|
|
55aabddd41 | ||
|
|
eb07820523 | ||
|
|
8116217019 | ||
|
|
6fb1845ff7 | ||
|
|
75325f0ed8 | ||
|
|
0577f9e166 | ||
|
|
52c6884e28 | ||
|
|
2be76a488f | ||
|
|
686535fe42 | ||
|
|
5c17aee1e4 | ||
|
|
9b35ac3a99 | ||
|
|
59b78e850f | ||
|
|
3a8c5a788f | ||
|
|
afcbbe0f43 | ||
|
|
d10d29e590 | ||
|
|
7b61cb3163 | ||
|
|
4c1c6701b3 | ||
|
|
f423fdf7f8 | ||
|
|
a5995a2ce8 | ||
|
|
c810b6772c | ||
|
|
b74ab18a6d | ||
|
|
edc54aaf91 | ||
|
|
b3b205cd6e | ||
|
|
2fe4def775 | ||
|
|
7bbf612394 | ||
|
|
97ab1f0492 | ||
|
|
81bfcdd158 | ||
|
|
6862d318f0 | ||
|
|
412fa3f0bf | ||
|
|
01d9109c45 | ||
|
|
dd914d1d64 | ||
|
|
5cf3624a3a | ||
|
|
c7ff8c2dd1 | ||
|
|
83c202d675 | ||
|
|
f7648e3311 | ||
|
|
c203de082e | ||
|
|
a95ba1acc4 | ||
|
|
db325525e4 | ||
|
|
db97114fb4 | ||
|
|
b18a300f10 | ||
|
|
61ffb857ee | ||
|
|
701212239d | ||
|
|
422fa01c6f | ||
|
|
62820b4dd9 | ||
|
|
8ea92ef330 | ||
|
|
de82249d8d | ||
|
|
94a26ae75a | ||
|
|
f9fdae9de9 | ||
|
|
0cb46039dd | ||
|
|
c4439cc9db | ||
|
|
6cd9640b30 | ||
|
|
f9bce3dfdb | ||
|
|
8eb0c997ed | ||
|
|
a8f96e06bd | ||
|
|
9a2945927f | ||
|
|
89f9249ec6 | ||
|
|
24f572253f | ||
|
|
4fc9c19893 | ||
|
|
f6fcd730a8 | ||
|
|
716a56979d | ||
|
|
538476be99 | ||
|
|
93a170a893 | ||
|
|
e0301f096f | ||
|
|
9e3cb4d694 | ||
|
|
49b76c3e43 | ||
|
|
9962784991 | ||
|
|
6336b38cfc | ||
|
|
2362835275 | ||
|
|
8a4ede9d43 | ||
|
|
cc1595e048 | ||
|
|
ca16763423 | ||
|
|
b6dd5bb881 | ||
|
|
f8e299ec56 | ||
|
|
91e9c6e048 | ||
|
|
b941b97eee | ||
|
|
d38ac652fc | ||
|
|
bdcf3b71ce | ||
|
|
ddbf8b7725 | ||
|
|
a6fd4547a7 | ||
|
|
d20153c569 | ||
|
|
15e072a2ff | ||
|
|
f98e20aa84 | ||
|
|
e7a1b33ae6 | ||
|
|
2d5f23271f | ||
|
|
059110ae7a | ||
|
|
ac84c175af | ||
|
|
3b6014c229 | ||
|
|
9cb265c6f5 | ||
|
|
a47f0ccc12 | ||
|
|
e032f6b33d | ||
|
|
98e179ba06 | ||
|
|
2ebb4fef4c | ||
|
|
e72b120c12 | ||
|
|
7b87b00b44 | ||
|
|
2b793bf242 | ||
|
|
49ae906029 | ||
|
|
4f82a0f026 | ||
|
|
ae8edffdc8 | ||
|
|
2b67c1c631 | ||
|
|
d395cf66a0 | ||
|
|
956ed9e8ae | ||
|
|
63726b09d6 | ||
|
|
f78d42cc30 | ||
|
|
5d1c807a86 | ||
|
|
fad077aad9 | ||
|
|
24f47bee73 | ||
|
|
d93b7b2cb2 | ||
|
|
ab03111a84 | ||
|
|
1ba03b69f6 | ||
|
|
9957f64628 | ||
|
|
6505af2a8b | ||
|
|
54c74bac6e | ||
|
|
5cf4c879dd | ||
|
|
aa00db48ce | ||
|
|
4a158db632 | ||
|
|
f57a0ecba2 | ||
|
|
3614c82632 | ||
|
|
9207d41f17 | ||
|
|
c5abd0ff3f | ||
|
|
2c2bde1e05 | ||
|
|
dcff8c0d9a | ||
|
|
44555e5289 | ||
|
|
9c4eff68a3 | ||
|
|
8f9122c706 | ||
|
|
3eb1b476dd | ||
|
|
0de9f48be4 | ||
|
|
162b482a8b | ||
|
|
2a46358ccf | ||
|
|
8146d6c293 | ||
|
|
5ab067cf86 | ||
|
|
720859197c | ||
|
|
ce064a0b37 | ||
|
|
bfd82fb415 | ||
|
|
655f656781 | ||
|
|
3f32841f49 | ||
|
|
4d7c021925 | ||
|
|
ac923fe669 | ||
|
|
d35b62995e | ||
|
|
ae7d2745db | ||
|
|
5ff47e63bc | ||
|
|
389341f613 | ||
|
|
00b51ad40d | ||
|
|
34c39597f5 | ||
|
|
4516e75b6f | ||
|
|
040518cca8 | ||
|
|
5d336e5fb9 | ||
|
|
e7d0103869 | ||
|
|
55cb10910f | ||
|
|
ecded8af93 | ||
|
|
20826daa18 | ||
|
|
742f1f4622 | ||
|
|
49cf20545f | ||
|
|
289e6f3d1c | ||
|
|
b246d17a33 | ||
|
|
c6b6616ee3 | ||
|
|
d6500c45aa | ||
|
|
6fd79688b0 | ||
|
|
c6478857bc | ||
|
|
8a711ffecb | ||
|
|
139ea879df | ||
|
|
6a0968cc02 | ||
|
|
5a1fa409d8 | ||
|
|
225da163bb | ||
|
|
801ed0fbaf | ||
|
|
ea44fe0f16 | ||
|
|
6081fe3295 | ||
|
|
6df65a0b9d | ||
|
|
0aec9419ec | ||
|
|
bb510a9240 | ||
|
|
cce3e1cfb8 | ||
|
|
4977f6c270 | ||
|
|
fe1715259a | ||
|
|
f4c0d84380 | ||
|
|
8a20584e27 | ||
|
|
218b0adb8f | ||
|
|
7d99607919 | ||
|
|
9adfcc7aec | ||
|
|
2da7463edf | ||
|
|
4a644d8712 | ||
|
|
afa17ca429 | ||
|
|
50708c6942 | ||
|
|
cbdf0a9392 | ||
|
|
b7c8ca2a48 | ||
|
|
3817ba774d | ||
|
|
e8771ea118 | ||
|
|
2f46fbfc7a | ||
|
|
78b0e1bf7e | ||
|
|
19530a9102 | ||
|
|
74051c5649 | ||
|
|
f3f391ab43 | ||
|
|
fc75621f1a | ||
|
|
fc3290271c | ||
|
|
71cd4057a7 | ||
|
|
485b35fbd4 | ||
|
|
172884ace8 | ||
|
|
b788c3745c | ||
|
|
7658cfcdbd | ||
|
|
52c8ea13af | ||
|
|
8f424f3273 | ||
|
|
3d7cf8f7f3 | ||
|
|
930adaf439 | ||
|
|
e5a14557a2 | ||
|
|
6a2ff9d153 | ||
|
|
bea90a7d94 | ||
|
|
e57d6e508a | ||
|
|
219b57a362 | ||
|
|
df8f54f5a4 | ||
|
|
fcbb1849ec | ||
|
|
684334ba22 | ||
|
|
5629215ce4 | ||
|
|
f63b6d7207 | ||
|
|
98dc553938 | ||
|
|
7ee01d9a05 | ||
|
|
dc6a67c2f0 | ||
|
|
affed459df | ||
|
|
8d4b8b02b8 | ||
|
|
8c430a3af0 | ||
|
|
b7573a40d7 | ||
|
|
624696711d | ||
|
|
56828e9e00 | ||
|
|
d2358c9550 | ||
|
|
ab11747fab | ||
|
|
44cb0fa434 | ||
|
|
13814695ac | ||
|
|
377e2eb613 | ||
|
|
bf4725a768 | ||
|
|
ed65abf786 | ||
|
|
8d29fe8679 | ||
|
|
f4f77c62c8 | ||
|
|
2cc08cdea1 | ||
|
|
03dc6d63ed | ||
|
|
bcb3ccec9a | ||
|
|
4bec8efea1 | ||
|
|
58b2c2bd69 | ||
|
|
636776c531 | ||
|
|
ca4a33d408 | ||
|
|
9db158f4d4 | ||
|
|
ea8b179df1 | ||
|
|
efc152e3c8 | ||
|
|
e68827bf3b | ||
|
|
58bf69882f | ||
|
|
915f313efd | ||
|
|
52d29099a2 | ||
|
|
c06fc926a1 | ||
|
|
79ab1a2277 | ||
|
|
7c03630e24 | ||
|
|
34a65419c7 | ||
|
|
7191ece7a5 | ||
|
|
0837f84a43 | ||
|
|
0bc4699cdc | ||
|
|
bb1285c35c | ||
|
|
21fc554589 | ||
|
|
a43af180a7 | ||
|
|
88ea920dfb | ||
|
|
132aac3951 | ||
|
|
7640ed08bc | ||
|
|
1dbf36b86b | ||
|
|
508de10191 | ||
|
|
ccfe259c69 | ||
|
|
0573f80525 | ||
|
|
8fb4e6c4ee | ||
|
|
05b2515b3b | ||
|
|
0ecb339fdf | ||
|
|
92ddebc289 | ||
|
|
1a3f0675bf | ||
|
|
c24019fd57 | ||
|
|
55641a234c | ||
|
|
9f52d364c9 | ||
|
|
edce70bc12 | ||
|
|
b8a7f81f55 | ||
|
|
ef9b2aefe5 | ||
|
|
cd1413a74e | ||
|
|
4e9d93957e | ||
|
|
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 | ||
|
|
1534f780aa | ||
|
|
4c6ceab8e8 | ||
|
|
f3fc01b740 | ||
|
|
a201be5a01 | ||
|
|
ebf2035351 | ||
|
|
69fc28d5d6 | ||
|
|
4107535b19 |
@@ -26,14 +26,21 @@
|
||||
|
||||
# Pass the configuration from the docker env to the PHP environment (here you should list all .env options)
|
||||
PassEnv APP_ENV APP_DEBUG APP_SECRET
|
||||
PassEnv TRUSTED_PROXIES TRUSTED_HOSTS LOCK_DSN
|
||||
PassEnv DATABASE_URL ENFORCE_CHANGE_COMMENTS_FOR
|
||||
PassEnv DEFAULT_LANG DEFAULT_TIMEZONE BASE_CURRENCY INSTANCE_NAME ALLOW_ATTACHMENT_DOWNLOADS USE_GRAVATAR MAX_ATTACHMENT_FILE_SIZE DEFAULT_URI
|
||||
PassEnv DEFAULT_LANG DEFAULT_TIMEZONE BASE_CURRENCY INSTANCE_NAME ALLOW_ATTACHMENT_DOWNLOADS USE_GRAVATAR MAX_ATTACHMENT_FILE_SIZE DEFAULT_URI CHECK_FOR_UPDATES
|
||||
PassEnv MAILER_DSN ALLOW_EMAIL_PW_RESET EMAIL_SENDER_EMAIL EMAIL_SENDER_NAME
|
||||
PassEnv HISTORY_SAVE_CHANGED_FIELDS HISTORY_SAVE_CHANGED_DATA HISTORY_SAVE_REMOVED_DATA
|
||||
PassEnv HISTORY_SAVE_CHANGED_FIELDS HISTORY_SAVE_CHANGED_DATA HISTORY_SAVE_REMOVED_DATA HISTORY_SAVE_NEW_DATA
|
||||
PassEnv ERROR_PAGE_ADMIN_EMAIL ERROR_PAGE_SHOW_HELP
|
||||
PassEnv DEMO_MODE NO_URL_REWRITE_AVAILABLE FIXER_API_KEY BANNER
|
||||
PassEnv SAML_ENABLED SAML_ROLE_MAPPING SAML_UPDATE_GROUP_ON_LOGIN SAML_IDP_ENTITY_ID SAML_IDP_SINGLE_SIGN_ON_SERVICE SAML_IDP_SINGLE_LOGOUT_SERVICE SAML_IDP_X509_CERT SAML_SP_ENTITY_ID SAML_SP_X509_CERT SAMLP_SP_PRIVATE_KEY
|
||||
# In old version the SAML sp private key env, was wrongly named SAMLP_SP_PRIVATE_KEY, keep it for backward compatibility
|
||||
PassEnv SAML_ENABLED SAML_ROLE_MAPPING SAML_UPDATE_GROUP_ON_LOGIN SAML_IDP_ENTITY_ID SAML_IDP_SINGLE_SIGN_ON_SERVICE SAML_IDP_SINGLE_LOGOUT_SERVICE SAML_IDP_X509_CERT SAML_SP_ENTITY_ID SAML_SP_X509_CERT SAML_SP_PRIVATE_KEY SAMLP_SP_PRIVATE_KEY
|
||||
PassEnv TABLE_DEFAULT_PAGE_SIZE
|
||||
|
||||
PassEnv PROVIDER_DIGIKEY_CLIENT_ID PROVIDER_DIGIKEY_SECRET PROVIDER_DIGIKEY_CURRENCY PROVIDER_DIGIKEY_LANGUAGE PROVIDER_DIGIKEY_COUNTRY
|
||||
PassEnv PROVIDER_ELEMENT14_KEY PROVIDER_ELEMENT14_STORE_ID
|
||||
PassEnv PROVIDER_TME_KEY PROVIDER_TME_SECRET PROVIDER_TME_CURRENCY PROVIDER_TME_LANGUAGE PROVIDER_TME_COUNTRY PROVIDER_TME_GET_GROSS_PRICES
|
||||
PassEnv PROVIDER_OCTOPART_CLIENT_ID PROVIDER_OCTOPART_SECRET PROVIDER_OCTOPART_CURRENCY PROVIDER_OCTOPART_COUNTRY PROVIDER_OCTOPART_SEARCH_LIMIT PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS
|
||||
|
||||
# For most configuration files from conf-available/, which are
|
||||
# enabled or disabled at a global level, it is possible to
|
||||
|
||||
64
.env
64
.env
@@ -44,6 +44,9 @@ DEFAULT_URI="https://partdb.changeme.invalid/"
|
||||
# Leave this empty, to make all change reasons optional
|
||||
ENFORCE_CHANGE_COMMENTS_FOR=""
|
||||
|
||||
# Disable that if you do not want that Part-DB connects to GitHub to check for available updates, or if your server can not connect to the internet
|
||||
CHECK_FOR_UPDATES=1
|
||||
|
||||
###################################################################################
|
||||
# Email settings
|
||||
###################################################################################
|
||||
@@ -71,6 +74,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
|
||||
@@ -81,6 +87,62 @@ ERROR_PAGE_ADMIN_EMAIL=''
|
||||
# If this is set to true, solutions to common problems are shown on error pages. Disable this, if you do not want your users to see them...
|
||||
ERROR_PAGE_SHOW_HELP=1
|
||||
|
||||
##################################################################################
|
||||
# Part table settings
|
||||
##################################################################################
|
||||
|
||||
# The default page size for the part table (set to -1 to show all parts on one page)
|
||||
TABLE_DEFAULT_PAGE_SIZE=50
|
||||
|
||||
##################################################################################
|
||||
# Info provider settings
|
||||
##################################################################################
|
||||
|
||||
# Digikey Provider:
|
||||
# You can get your client id and secret from https://developer.digikey.com/
|
||||
PROVIDER_DIGIKEY_CLIENT_ID=
|
||||
PROVIDER_DIGIKEY_SECRET=
|
||||
# The currency to get prices in
|
||||
PROVIDER_DIGIKEY_CURRENCY=EUR
|
||||
# The language to get results in (en, de, fr, it, es, zh, ja, ko)
|
||||
PROVIDER_DIGIKEY_LANGUAGE=en
|
||||
# The country to get results for
|
||||
PROVIDER_DIGIKEY_COUNTRY=DE
|
||||
|
||||
# Farnell Provider:
|
||||
# You can get your API key from https://partner.element14.com/
|
||||
PROVIDER_ELEMENT14_KEY=
|
||||
# Configure the store domain you want to use. This decides the language and currency of results. You can get a list of available stores from https://partner.element14.com/docs/Product_Search_API_REST__Description
|
||||
PROVIDER_ELEMENT14_STORE_ID=de.farnell.com
|
||||
|
||||
# TME Provider:
|
||||
# You can get your API key from https://developers.tme.eu/en/
|
||||
PROVIDER_TME_KEY=
|
||||
PROVIDER_TME_SECRET=
|
||||
# The currency to get prices in
|
||||
PROVIDER_TME_CURRENCY=EUR
|
||||
# The language to get results in (en, de, pl)
|
||||
PROVIDER_TME_LANGUAGE=en
|
||||
# The country to get results for
|
||||
PROVIDER_TME_COUNTRY=DE
|
||||
# Set this to 1 to get gross prices (including VAT) instead of net prices
|
||||
PROVIDER_TME_GET_GROSS_PRICES=1
|
||||
|
||||
# Octopart / Nexar Provider:
|
||||
# You can get your API key from https://nexar.com/api
|
||||
PROVIDER_OCTOPART_CLIENT_ID=
|
||||
PROVIDER_OCTOPART_SECRET=
|
||||
# The currency and country to get prices for (you have to set both to get meaningful results)
|
||||
# 3 letter ISO currency code (e.g. EUR, USD, GBP)
|
||||
PROVIDER_OCTOPART_CURRENCY=EUR
|
||||
# 2 letter ISO country code (e.g. DE, US, GB)
|
||||
PROVIDER_OCTOPART_COUNTRY=DE
|
||||
# The number of results to get from Octopart while searching (please note that this counts towards your API limits)
|
||||
PROVIDER_OCTOPART_SEARCH_LIMIT=10
|
||||
# Set to false to include non authorized offers in the results
|
||||
PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS=1
|
||||
|
||||
|
||||
###################################################################################
|
||||
# SAML Single sign on-settings
|
||||
###################################################################################
|
||||
@@ -113,7 +175,7 @@ SAML_SP_ENTITY_ID="https://partdb.changeme.invalid/sp"
|
||||
# The public certificate of the SAML SP
|
||||
SAML_SP_X509_CERT="MIIC..."
|
||||
# The private key of the SAML SP
|
||||
SAMLP_SP_PRIVATE_KEY="MIIE..."
|
||||
SAML_SP_PRIVATE_KEY="MIIE..."
|
||||
|
||||
|
||||
######################################################################################
|
||||
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# For sh files, always use LF line endings
|
||||
*.sh text eol=lf
|
||||
2
.github/workflows/assets_artifact_build.yml
vendored
2
.github/workflows/assets_artifact_build.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
APP_ENV: prod
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get Composer Cache Directory
|
||||
id: composer-cache
|
||||
|
||||
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
|
||||
10
.github/workflows/docker_build.yml
vendored
10
.github/workflows/docker_build.yml
vendored
@@ -17,11 +17,11 @@ jobs:
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: |
|
||||
@@ -49,12 +49,12 @@ jobs:
|
||||
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: 'arm64,arm'
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
|
||||
9
.github/workflows/static_analysis.yml
vendored
9
.github/workflows/static_analysis.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get Composer Cache Directory
|
||||
id: composer-cache
|
||||
@@ -38,9 +38,10 @@ jobs:
|
||||
|
||||
- name: Lint twig templates
|
||||
run: ./bin/console lint:twig templates --env=prod
|
||||
|
||||
- name: Lint translations
|
||||
run: ./bin/console lint:xliff translations
|
||||
|
||||
# This causes problems with emtpy language files
|
||||
#- name: Lint translations
|
||||
# run: ./bin/console lint:xliff translations
|
||||
|
||||
- name: Check dependencies for security
|
||||
uses: symfonycorp/security-checker-action@v5
|
||||
|
||||
6
.github/workflows/tests.yml
vendored
6
.github/workflows/tests.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: [ '7.4', '8.0', '8.1', '8.2' ]
|
||||
php-versions: [ '8.1', '8.2' ]
|
||||
db-type: [ 'mysql', 'sqlite' ]
|
||||
|
||||
env:
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
if: matrix.db-type == 'sqlite'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
run: php bin/console --env test doctrine:migrations:migrate -n
|
||||
|
||||
- name: Load fixtures
|
||||
run: php bin/console --env test doctrine:fixtures:load -n --purger reset_autoincrement_purger
|
||||
run: php bin/console --env test doctrine:fixtures:load -n
|
||||
|
||||
- name: Run PHPunit and generate coverage
|
||||
run: ./bin/phpunit --coverage-clover=coverage.xml
|
||||
|
||||
15
Dockerfile
15
Dockerfile
@@ -34,12 +34,25 @@ RUN sed -ri 's/^export ([^=]+)=(.*)$/: ${\1:=\2}\nexport \1/' "$APACHE_ENVVARS"
|
||||
ln -sfT /dev/stderr "$APACHE_LOG_DIR/error.log"; \
|
||||
ln -sfT /dev/stdout "$APACHE_LOG_DIR/access.log"; \
|
||||
ln -sfT /dev/stdout "$APACHE_LOG_DIR/other_vhosts_access.log"; \
|
||||
ln -sfT /dev/stderr /var/log/php8.1-fpm.log; \
|
||||
chown -R --no-dereference "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$APACHE_LOG_DIR";
|
||||
|
||||
# Enable php-fpm
|
||||
RUN a2enmod proxy_fcgi setenvif && a2enconf php8.1-fpm
|
||||
|
||||
# Configure php-fpm to log to stdout of the container (stdout of PID 1)
|
||||
# We have to use /proc/1/fd/1 because /dev/stdout or /proc/self/fd/1 does not point to the container stdout (because we use apache as entrypoint)
|
||||
# We also disable the clear_env option to allow the use of environment variables in php-fpm
|
||||
RUN { \
|
||||
echo '[global]'; \
|
||||
echo 'error_log = /proc/1/fd/1'; \
|
||||
echo; \
|
||||
echo '[www]'; \
|
||||
echo 'access.log = /proc/1/fd/1'; \
|
||||
echo 'catch_workers_output = yes'; \
|
||||
echo 'decorate_workers_output = no'; \
|
||||
echo 'clear_env = no'; \
|
||||
} | tee "/etc/php/8.1/fpm/pool.d/zz-docker.conf"
|
||||
|
||||
# PHP files should be handled by PHP, and should be preferred over any other file type
|
||||
RUN { \
|
||||
echo '<FilesMatch \.php$>'; \
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||

|
||||
[](https://codecov.io/gh/Part-DB/Part-DB-server)
|
||||

|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
@@ -51,6 +51,7 @@ Two-factor authentication is supported (Google Authenticator and Webauthn/U2F ke
|
||||
* Support for multiple currencies and automatic update of exchange rates supported
|
||||
* Powerful search and filter function, including parametric search (search for parts according to some specifications)
|
||||
* Automatic thumbnail generation for pictures
|
||||
* Use cloud providers (like Octopart, Digikey, farnell or TME) to automatically get part information, datasheets and prices for parts
|
||||
|
||||
|
||||
With these features Part-DB is useful to hobbyists, who want to keep track of their private electronic parts inventory,
|
||||
@@ -60,10 +61,10 @@ Part-DB is also used by small companies and universities for managing their inve
|
||||
|
||||
## Requirements
|
||||
* A **web server** (like Apache2 or nginx) that is capable of running [Symfony 5](https://symfony.com/doc/current/reference/requirements.html),
|
||||
this includes a minimum PHP version of **PHP 7.4**
|
||||
this includes a minimum PHP version of **PHP 8.1**
|
||||
* A **MySQL** (at least 5.7) /**MariaDB** (at least 10.2.2) database server if you do not want to use SQLite.
|
||||
* Shell access to your server is highly suggested!
|
||||
* For building the client side assets **yarn** and **nodejs** is needed.
|
||||
* For building the client side assets **yarn** and **nodejs** (>= 18.0) is needed.
|
||||
|
||||
## Installation
|
||||
If you want to upgrade your legacy (< 1.0.0) version of Part-DB to this version, please read [this](https://docs.part-db.de/upgrade_legacy.html) first.
|
||||
|
||||
3
assets/bootstrap.js
vendored
3
assets/bootstrap.js
vendored
@@ -4,8 +4,7 @@ import { startStimulusApp } from '@symfony/stimulus-bridge';
|
||||
export const app = startStimulusApp(require.context(
|
||||
'@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
|
||||
true,
|
||||
/\.(j|t)sx?$/
|
||||
/\.[jt]sx?$/
|
||||
));
|
||||
|
||||
// register any custom, 3rd party controllers here
|
||||
// app.register('some_controller_name', SomeImportedController);
|
||||
|
||||
@@ -181,7 +181,8 @@ Editor.defaultConfig = {
|
||||
'DejaVu Serif, serif',
|
||||
'Helvetica, Arial, sans-serif',
|
||||
'Times New Roman, Times, serif',
|
||||
'Courier New, Courier, monospace'
|
||||
'Courier New, Courier, monospace',
|
||||
'Unifont, monospace',
|
||||
],
|
||||
supportAllValues: true
|
||||
},
|
||||
|
||||
@@ -76,6 +76,7 @@ const PLACEHOLDERS = [
|
||||
['[[FOOTPRINT_FULL]]', 'Footprint (Full path)'],
|
||||
['[[MASS]]', 'Mass'],
|
||||
['[[MPN]]', 'Manufacturer Product Number (MPN)'],
|
||||
['[[IPN]]', 'Internal Part Number (IPN)'],
|
||||
['[[TAGS]]', 'Tags'],
|
||||
['[[M_STATUS]]', 'Manufacturing status'],
|
||||
['[[DESCRIPTION]]', 'Description'],
|
||||
|
||||
@@ -39,6 +39,7 @@ Object.assign( window.CKEDITOR_TRANSLATIONS[ 'de' ].dictionary, {
|
||||
'Footprint (Full path)': 'Footprint (Vollständiger Pfad)',
|
||||
'Mass': 'Gewicht',
|
||||
'Manufacturer Product Number (MPN)': 'Hersteller Produktnummer (MPN)',
|
||||
'Internal Part Number (IPN)': 'Internal Part Number (IPN)',
|
||||
'Tags': 'Tags',
|
||||
'Manufacturing status': 'Herstellungsstatus',
|
||||
'Description': 'Beschreibung',
|
||||
|
||||
@@ -18,43 +18,118 @@
|
||||
*/
|
||||
|
||||
import {Controller} from "@hotwired/stimulus";
|
||||
import Darkmode from "darkmode-js/src";
|
||||
import "darkmode-js"
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
_darkmode;
|
||||
|
||||
connect() {
|
||||
if (typeof window.getComputedStyle(document.body).mixBlendMode == 'undefined') {
|
||||
console.warn("The browser does not support mix blend mode. Darkmode will not work.");
|
||||
this.setMode(this.getMode());
|
||||
document.querySelectorAll('input[name="darkmode"]').forEach((radio) => {
|
||||
radio.addEventListener('change', this._radioChanged.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for the change of radio buttons
|
||||
* @private
|
||||
*/
|
||||
_radioChanged(event) {
|
||||
const new_mode = this.getSelectedMode();
|
||||
this.setMode(new_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current mode from the local storage
|
||||
* @return {'dark', 'light', 'auto'}
|
||||
*/
|
||||
getMode() {
|
||||
return localStorage.getItem('darkmode') ?? 'auto';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the mode in the local storage and apply it and change the state of the radio buttons
|
||||
* @param mode
|
||||
*/
|
||||
setMode(mode) {
|
||||
if (mode !== 'dark' && mode !== 'light' && mode !== 'auto') {
|
||||
console.warn('Invalid darkmode mode: ' + mode);
|
||||
mode = 'auto';
|
||||
}
|
||||
|
||||
localStorage.setItem('darkmode', mode);
|
||||
|
||||
this.setButtonMode(mode);
|
||||
|
||||
if (mode === 'auto') {
|
||||
this._setDarkmodeAuto();
|
||||
} else if (mode === 'dark') {
|
||||
this._enableDarkmode();
|
||||
} else if (mode === 'light') {
|
||||
this._disableDarkmode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selected mode via the radio buttons
|
||||
* @return {'dark', 'light', 'auto'}
|
||||
*/
|
||||
getSelectedMode() {
|
||||
return document.querySelector('input[name="darkmode"]:checked').value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state of the radio buttons
|
||||
* @param mode
|
||||
*/
|
||||
setButtonMode(mode) {
|
||||
document.querySelector('input[name="darkmode"][value="' + mode + '"]').checked = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable darkmode by adding the data-bs-theme="dark" to the html tag
|
||||
* @private
|
||||
*/
|
||||
_enableDarkmode() {
|
||||
//Add data-bs-theme="dark" to the html tag
|
||||
document.documentElement.setAttribute('data-bs-theme', 'dark');
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable darkmode by adding the data-bs-theme="light" to the html tag
|
||||
* @private
|
||||
*/
|
||||
_disableDarkmode() {
|
||||
//Set data-bs-theme to light
|
||||
document.documentElement.setAttribute('data-bs-theme', 'light');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the darkmode to auto and enable/disable it depending on the system settings, also add
|
||||
* an event listener to change the darkmode if the system settings change
|
||||
* @private
|
||||
*/
|
||||
_setDarkmodeAuto() {
|
||||
if (this.getMode() !== 'auto') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const darkmode = new Darkmode();
|
||||
this._darkmode = darkmode;
|
||||
|
||||
//Unhide darkmode button
|
||||
this._showWidget();
|
||||
|
||||
//Set the switch according to our current darkmode state
|
||||
const toggler = document.getElementById("toggleDarkmode");
|
||||
toggler.checked = darkmode.isActivated();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
console.error(e);
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
this._enableDarkmode();
|
||||
} else {
|
||||
this._disableDarkmode();
|
||||
}
|
||||
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
||||
console.log('Prefered color scheme changed to ' + event.matches ? 'dark' : 'light');
|
||||
this._setDarkmodeAuto();
|
||||
});
|
||||
}
|
||||
|
||||
_showWidget() {
|
||||
this.element.classList.remove('hidden');
|
||||
}
|
||||
|
||||
toggleDarkmode() {
|
||||
this._darkmode.toggle();
|
||||
/**
|
||||
* Check if darkmode is activated
|
||||
* @return {boolean}
|
||||
*/
|
||||
isDarkmodeActivated() {
|
||||
return document.documentElement.getAttribute('data-bs-theme') === 'dark';
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
import { marked } from "marked";
|
||||
import { mangle } from "marked-mangle";
|
||||
import { gfmHeadingId } from "marked-gfm-heading-id";
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
import "../../css/app/markdown.css";
|
||||
@@ -81,6 +83,10 @@ export default class extends Controller {
|
||||
*/
|
||||
configureMarked()
|
||||
{
|
||||
marked.use(mangle());
|
||||
marked.use(gfmHeadingId({
|
||||
}));
|
||||
|
||||
marked.setOptions({
|
||||
gfm: true,
|
||||
});
|
||||
|
||||
@@ -61,7 +61,7 @@ export default class extends Controller {
|
||||
|
||||
if(!prototype) {
|
||||
console.warn("Prototype is not set, we cannot create a new element. This is most likely due to missing permissions.");
|
||||
bootbox.alert("You do not have the permsissions to create a new element. (No protoype element is set)");
|
||||
bootbox.alert("You do not have the permissions to create a new element. (No protoype element is set)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,12 +65,19 @@ export default class extends Controller {
|
||||
localStorage.setItem( this.getStateSaveKey(), JSON.stringify(data) );
|
||||
}
|
||||
|
||||
stateLoadCallback(settings) {
|
||||
const data = JSON.parse( localStorage.getItem(this.getStateSaveKey()) );
|
||||
stateLoadCallback() {
|
||||
const json = localStorage.getItem(this.getStateSaveKey());
|
||||
if(json === null || json === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = JSON.parse(json);
|
||||
|
||||
if (data) {
|
||||
//Do not save the start value (current page), as we want to always start at the first page on a page reload
|
||||
data.start = 0;
|
||||
delete data.start;
|
||||
//Reset the data length to the default value by deleting the length property
|
||||
delete data.length;
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -88,6 +95,19 @@ export default class extends Controller {
|
||||
//Add url info, as the one available in the history is not enough, as Turbo may have not changed it yet
|
||||
settings.url = this.element.dataset.dtUrl;
|
||||
|
||||
//Add initial_order info to the settings, so that the order on the initial page load is the one saved in the state
|
||||
const saved_state = this.stateLoadCallback();
|
||||
if (saved_state !== null) {
|
||||
const raw_order = saved_state.order;
|
||||
|
||||
settings.initial_order = raw_order.map((order) => {
|
||||
return {
|
||||
column: order[0],
|
||||
dir: order[1]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let options = {
|
||||
colReorder: true,
|
||||
responsive: true,
|
||||
@@ -97,7 +117,7 @@ export default class extends Controller {
|
||||
},
|
||||
buttons: [{
|
||||
"extend": 'colvis',
|
||||
'className': 'mr-2 btn-light',
|
||||
'className': 'mr-2 btn-outline-secondary',
|
||||
'columns': ':not(.no-colvis)',
|
||||
"text": "<i class='fa fa-cog'></i>"
|
||||
}],
|
||||
@@ -123,6 +143,22 @@ export default class extends Controller {
|
||||
console.error("Error initializing datatables: " + err);
|
||||
});
|
||||
|
||||
//Fix height of the length selector
|
||||
promise.then((dt) => {
|
||||
//Find all length selectors (select with name dt_length), which are inside a label
|
||||
const lengthSelectors = document.querySelectorAll('label select[name="dt_length"]');
|
||||
//And remove the surrounding label, while keeping the select with all event handlers
|
||||
lengthSelectors.forEach((selector) => {
|
||||
selector.parentElement.replaceWith(selector);
|
||||
});
|
||||
|
||||
//Find all column visibility buttons (button with buttons-colvis class) and remove the btn-secondary class
|
||||
const colVisButtons = document.querySelectorAll('button.buttons-colvis');
|
||||
colVisButtons.forEach((button) => {
|
||||
button.classList.remove('btn-secondary');
|
||||
});
|
||||
});
|
||||
|
||||
//Dispatch an event to let others know that the datatables has been loaded
|
||||
promise.then((dt) => {
|
||||
const event = new CustomEvent(EVENT_DT_LOADED, {bubbles: true});
|
||||
@@ -203,4 +239,16 @@ export default class extends Controller {
|
||||
return this.element.dataset.select ?? false;
|
||||
}
|
||||
|
||||
invertSelection() {
|
||||
//Do nothing if the datatable is not selectable
|
||||
if(!this.isSelectable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Invert the selected rows on the datatable
|
||||
const selected_rows = this._dt.rows({selected: true});
|
||||
this._dt.rows().select();
|
||||
selected_rows.deselect();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
72
assets/controllers/elements/link_confirm_controller.js
Normal file
72
assets/controllers/elements/link_confirm_controller.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 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 * as bootbox from "bootbox";
|
||||
import "../../css/components/bootbox_extensions.css";
|
||||
|
||||
export default class extends Controller
|
||||
{
|
||||
|
||||
static values = {
|
||||
message: String,
|
||||
title: String
|
||||
}
|
||||
|
||||
|
||||
|
||||
connect()
|
||||
{
|
||||
this._confirmed = false;
|
||||
|
||||
this.element.addEventListener('click', this._onClick.bind(this));
|
||||
}
|
||||
|
||||
_onClick(event)
|
||||
{
|
||||
|
||||
//If a user has not already confirmed the deletion, just let turbo do its work
|
||||
if (this._confirmed) {
|
||||
this._confirmed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const that = this;
|
||||
|
||||
bootbox.confirm({
|
||||
title: this.titleValue,
|
||||
message: this.messageValue,
|
||||
callback: (result) => {
|
||||
if (result) {
|
||||
//Set a flag to prevent the dialog from popping up again and allowing turbo to submit the form
|
||||
that._confirmed = true;
|
||||
|
||||
//Click the link
|
||||
that.element.click();
|
||||
} else {
|
||||
that._confirmed = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 { zxcvbn, zxcvbnOptions } from '@zxcvbn-ts/core';
|
||||
import * as zxcvbnCommonPackage from '@zxcvbn-ts/language-common';
|
||||
import * as zxcvbnEnPackage from '@zxcvbn-ts/language-en';
|
||||
import * as zxcvbnDePackage from '@zxcvbn-ts/language-de';
|
||||
import * as zxcvbnFrPackage from '@zxcvbn-ts/language-fr';
|
||||
import * as zxcvbnJaPackage from '@zxcvbn-ts/language-ja';
|
||||
import {trans, USER_PASSWORD_STRENGTH_VERY_WEAK, USER_PASSWORD_STRENGTH_WEAK, USER_PASSWORD_STRENGTH_MEDIUM,
|
||||
USER_PASSWORD_STRENGTH_STRONG, USER_PASSWORD_STRENGTH_VERY_STRONG} from '../../translator.js';
|
||||
|
||||
/* stimulusFetch: 'lazy' */
|
||||
export default class extends Controller {
|
||||
|
||||
_passwordInput;
|
||||
|
||||
static targets = ["badge", "warning"]
|
||||
|
||||
_getTranslations() {
|
||||
//Get the current locale
|
||||
const locale = document.documentElement.lang;
|
||||
if (locale.includes('de')) {
|
||||
return zxcvbnDePackage.translations;
|
||||
} else if (locale.includes('fr')) {
|
||||
return zxcvbnFrPackage.translations;
|
||||
} else if (locale.includes('ja')) {
|
||||
return zxcvbnJaPackage.translations;
|
||||
}
|
||||
|
||||
//Fallback to english
|
||||
return zxcvbnEnPackage.translations;
|
||||
}
|
||||
|
||||
connect() {
|
||||
//Find the password input field
|
||||
this._passwordInput = this.element.querySelector('input[type="password"]');
|
||||
|
||||
//Configure zxcvbn
|
||||
const options = {
|
||||
graphs: zxcvbnCommonPackage.adjacencyGraphs,
|
||||
dictionary: {
|
||||
...zxcvbnCommonPackage.dictionary,
|
||||
// We could use the english dictionary here too, but it is very big. So we just use the common words
|
||||
//...zxcvbnEnPackage.dictionary,
|
||||
},
|
||||
translations: this._getTranslations(),
|
||||
};
|
||||
zxcvbnOptions.setOptions(options);
|
||||
|
||||
//Add event listener to the password input field
|
||||
this._passwordInput.addEventListener('input', this._onPasswordInput.bind(this));
|
||||
}
|
||||
|
||||
_onPasswordInput() {
|
||||
//Retrieve the password
|
||||
const password = this._passwordInput.value;
|
||||
|
||||
//Estimate the password strength
|
||||
const result = zxcvbn(password);
|
||||
|
||||
//Update the badge
|
||||
this.badgeTarget.parentElement.classList.remove("d-none");
|
||||
this._setBadgeToLevel(result.score);
|
||||
|
||||
this.warningTarget.innerHTML = result.feedback.warning;
|
||||
}
|
||||
|
||||
_setBadgeToLevel(level) {
|
||||
let text, classes;
|
||||
|
||||
switch (level) {
|
||||
case 0:
|
||||
text = trans(USER_PASSWORD_STRENGTH_VERY_WEAK);
|
||||
classes = "bg-danger badge-danger";
|
||||
break;
|
||||
case 1:
|
||||
text = trans(USER_PASSWORD_STRENGTH_WEAK);
|
||||
classes = "bg-warning badge-warning";
|
||||
break;
|
||||
case 2:
|
||||
text = trans(USER_PASSWORD_STRENGTH_MEDIUM)
|
||||
classes = "bg-info badge-info";
|
||||
break;
|
||||
case 3:
|
||||
text = trans(USER_PASSWORD_STRENGTH_STRONG);
|
||||
classes = "bg-primary badge-primary";
|
||||
break;
|
||||
case 4:
|
||||
text = trans(USER_PASSWORD_STRENGTH_VERY_STRONG);
|
||||
classes = "bg-success badge-success";
|
||||
break;
|
||||
default:
|
||||
text = "???";
|
||||
classes = "bg-secondary badge-secondary";
|
||||
}
|
||||
|
||||
this.badgeTarget.innerHTML = text;
|
||||
//Remove all classes
|
||||
this.badgeTarget.className = '';
|
||||
//Re-add the classes
|
||||
this.badgeTarget.classList.add("badge");
|
||||
this.badgeTarget.classList.add(...classes.split(" "));
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ import '../../css/components/tom-select_extensions.css';
|
||||
import TomSelect from "tom-select";
|
||||
import {Controller} from "@hotwired/stimulus";
|
||||
|
||||
import {trans, ENTITY_SELECT_GROUP_NEW_NOT_ADDED_TO_DB} from '../../translator.js'
|
||||
|
||||
|
||||
export default class extends Controller {
|
||||
_tomSelect;
|
||||
@@ -40,8 +42,7 @@ export default class extends Controller {
|
||||
allowEmptyOption: true,
|
||||
selectOnTab: true,
|
||||
maxOptions: null,
|
||||
create: allowAdd,
|
||||
createFilter: /\D/, //Must contain a non-digit character, otherwise they would be recognized as DB ID
|
||||
create: allowAdd ? this.createItem.bind(this) : false,
|
||||
|
||||
searchField: [
|
||||
{field: "text", weight : 2},
|
||||
@@ -57,10 +58,38 @@ export default class extends Controller {
|
||||
'<small class="text-muted float-end">(' + addHint +')</small>' +
|
||||
'</div>';
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
//Add callbacks to update validity
|
||||
onInitialize: this.updateValidity.bind(this),
|
||||
onChange: this.updateValidity.bind(this),
|
||||
};
|
||||
|
||||
this._tomSelect = new TomSelect(this.element, settings);
|
||||
this._tomSelect.sync();
|
||||
}
|
||||
|
||||
createItem(input, callback) {
|
||||
callback({
|
||||
//$%$ is a special value prefix, that is used to identify items, that are not yet in the DB
|
||||
value: '$%$' + input,
|
||||
text: input,
|
||||
not_in_db_yet: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
updateValidity() {
|
||||
//Mark this input as invalid, if the selected option is disabled
|
||||
|
||||
const input = this.element;
|
||||
const selectedOption = input.options[input.selectedIndex];
|
||||
|
||||
if (selectedOption && selectedOption.disabled) {
|
||||
input.setCustomValidity("This option was disabled. Please select another option.");
|
||||
} else {
|
||||
input.setCustomValidity("");
|
||||
}
|
||||
}
|
||||
|
||||
getTomSelect() {
|
||||
@@ -78,14 +107,27 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
if (data.short) {
|
||||
return '<div><b>' + escape(data.short) + '</b></div>';
|
||||
let short = escape(data.short)
|
||||
|
||||
//Make text italic, if the item is not yet in the DB
|
||||
if (data.not_in_db_yet) {
|
||||
short = '<i>' + short + '</i>';
|
||||
}
|
||||
|
||||
return '<div><b>' + short + '</b></div>';
|
||||
}
|
||||
|
||||
let name = "";
|
||||
if (data.parent) {
|
||||
name += escape(data.parent) + " → ";
|
||||
}
|
||||
name += "<b>" + escape(data.text) + "</b>";
|
||||
|
||||
if (data.not_in_db_yet) {
|
||||
//Not yet added items are shown italic and with a badge
|
||||
name += "<i><b>" + escape(data.text) + "</b></i>" + "<span class='ms-3 badge bg-info badge-info'>" + trans(ENTITY_SELECT_GROUP_NEW_NOT_ADDED_TO_DB) + "</span>";
|
||||
} else {
|
||||
name += "<b>" + escape(data.text) + "</b>";
|
||||
}
|
||||
|
||||
return '<div>' + (data.image ? "<img class='structural-entity-select-image' style='margin-right: 5px;' ' src='" + data.image + "'/>" : "") + name + '</div>';
|
||||
}
|
||||
|
||||
@@ -81,6 +81,14 @@ export default class extends Controller {
|
||||
this._tree.remove();
|
||||
}
|
||||
|
||||
const BS53Theme = {
|
||||
getOptions() {
|
||||
return {
|
||||
onhoverColor: 'var(--bs-secondary-bg)',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
this._tree = new BSTreeView(this.treeTarget, {
|
||||
levels: 1,
|
||||
showTags: this._showTags,
|
||||
@@ -93,7 +101,7 @@ export default class extends Controller {
|
||||
}
|
||||
},
|
||||
//onNodeContextmenu: contextmenu_handler,
|
||||
}, [BS5Theme, FAIconTheme]);
|
||||
}, [BS5Theme, BS53Theme, FAIconTheme]);
|
||||
|
||||
this.treeTarget.addEventListener(EVENT_INITIALIZED, (event) => {
|
||||
/** @type {BSTreeView} */
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 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";
|
||||
|
||||
/**
|
||||
* This controller is used on a checkbox, which toggles the max value of all number input fields
|
||||
*/
|
||||
export default class extends Controller {
|
||||
|
||||
_checkbox;
|
||||
|
||||
getCheckbox() {
|
||||
if (this._checkbox) {
|
||||
return this._checkbox;
|
||||
}
|
||||
|
||||
//Find the checkbox inside the controller element
|
||||
this._checkbox = this.element.querySelector('input[type="checkbox"]');
|
||||
return this._checkbox;
|
||||
}
|
||||
|
||||
connect() {
|
||||
//Add event listener to the checkbox
|
||||
this.getCheckbox().addEventListener('change', this.toggleInputLimits.bind(this));
|
||||
}
|
||||
|
||||
toggleInputLimits() {
|
||||
//Find all input fields with the data-toggle-input-limits-target="max"
|
||||
const inputFields = document.querySelectorAll("input[type='number']");
|
||||
|
||||
inputFields.forEach((inputField) => {
|
||||
//Ensure that the input field has either a max or a data-max attribute
|
||||
if (!inputField.hasAttribute('max') && !inputField.hasAttribute('data-max')) {
|
||||
return;
|
||||
}
|
||||
|
||||
//If the checkbox is checked, rename the max attribute to data-max
|
||||
if (this.getCheckbox().checked) {
|
||||
inputField.setAttribute('data-max', inputField.getAttribute('max'));
|
||||
inputField.removeAttribute('max');
|
||||
} else {
|
||||
//If the checkbox is not checked, rename the data-max attribute back to max
|
||||
inputField.setAttribute('max', inputField.getAttribute('data-max'));
|
||||
inputField.removeAttribute('data-max');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -99,10 +99,25 @@ label:not(.form-check-label, .custom-control-label) {
|
||||
|
||||
form .col-form-label.required:after, form label.required:after {
|
||||
bottom: 4px;
|
||||
color: var(--bs-dark);
|
||||
color: var(--bs-secondary-color);
|
||||
content: "\2022";
|
||||
filter: opacity(75%);
|
||||
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;
|
||||
}
|
||||
@@ -67,7 +67,6 @@ ul.structural_link {
|
||||
padding-bottom: 7px;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
/* Display list items side by side */
|
||||
@@ -79,7 +78,7 @@ ul.structural_link li {
|
||||
/* Add a slash symbol (/) before/behind each list item */
|
||||
ul.structural_link li+li:before {
|
||||
padding: 2px;
|
||||
color: grey;
|
||||
color: var(--bs-tertiary-color);
|
||||
/*content: "/\00a0";*/
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-weight: 900;
|
||||
@@ -89,13 +88,13 @@ ul.structural_link li+li:before {
|
||||
|
||||
/* Add a color to all links inside the list */
|
||||
ul.structural_link li a {
|
||||
color: #0275d8;
|
||||
color: var(--bs-link-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Add a color on mouse-over */
|
||||
ul.structural_link li a:hover {
|
||||
color: #01447e;
|
||||
color: var(--bs-link-hover-color);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,8 +78,6 @@ body {
|
||||
overflow: -moz-scrollbars-none;
|
||||
/* Use standard version for hiding the scrollbar */
|
||||
scrollbar-width: none;
|
||||
|
||||
background-color: var(--light);
|
||||
}
|
||||
|
||||
#sidebar-container {
|
||||
|
||||
@@ -91,7 +91,7 @@ th.select-checkbox {
|
||||
/** Fix datatables select-checkbox position */
|
||||
table.dataTable tr.selected td.select-checkbox:after
|
||||
{
|
||||
margin-top: -28px !important;
|
||||
margin-top: -20px !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,23 +116,33 @@ table.dataTable > thead > tr > th.select-checkbox:before,
|
||||
table.dataTable > thead > tr > th.select-checkbox:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 1.2em;
|
||||
top: 0.9em;
|
||||
left: 50%;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
width: 1em !important;
|
||||
height: 1em !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
table.dataTable > thead > tr > th.select-checkbox:before {
|
||||
content: " ";
|
||||
margin-top: -5px;
|
||||
margin-left: -6px;
|
||||
border: 1px solid black;
|
||||
border: 2px solid var(--bs-tertiary-color);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > th.select-checkbox:before {
|
||||
border: 2px solid var(--bs-tertiary-color) !important;
|
||||
}
|
||||
|
||||
table.dataTable > tbody > tr > td.select-checkbox:before, table.dataTable > tbody > tr > td.select-checkbox:after, table.dataTable > tbody > tr > th.select-checkbox:before, table.dataTable > tbody > tr > th.select-checkbox:after {
|
||||
width: 1em !important;
|
||||
height: 1em !important;
|
||||
}
|
||||
|
||||
table.dataTable > thead > tr.selected > th.select-checkbox:after {
|
||||
content: "✓";
|
||||
font-size: 20px;
|
||||
margin-top: -23px;
|
||||
margin-top: -20px;
|
||||
margin-left: -6px;
|
||||
text-align: center;
|
||||
/*text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9; */
|
||||
|
||||
@@ -36,3 +36,42 @@
|
||||
.ck-html-label .ck-content hr {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Hide CKEditor powered by message
|
||||
***********************************************/
|
||||
.ck-powered-by {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************
|
||||
* Use Bootstrap color vars for CKEditor
|
||||
***********************************************/
|
||||
:root {
|
||||
--ck-color-base-foreground: var(--bs-secondary-bg);
|
||||
--ck-color-base-background: var(--bs-body-bg);
|
||||
--ck-color-base-border: var(--bs-border-color);
|
||||
--ck-color-base-action: var(--bs-success);
|
||||
--ck-color-base-focus: var(--bs-primary-border-subtle);
|
||||
--ck-color-base-text: var(--bs-body-color);
|
||||
--ck-color-base-active: var(--bs-primary-bg-subtle);
|
||||
--ck-color-base-active-focus: var(--bs-primary);
|
||||
--ck-color-base-error: var(--bs-danger);
|
||||
|
||||
/* Improve contrast between text and toolbar */
|
||||
--ck-color-toolbar-background: var(--bs-tertiary-bg);
|
||||
|
||||
/* Buttons */
|
||||
--ck-color-button-default-hover-background: var(--bs-secondary-bg);
|
||||
--ck-color-button-default-active-background: var(--bs-secondary-bg);
|
||||
|
||||
--ck-color-button-on-background: var(--bs-body-bg);
|
||||
--ck-color-button-on-hover-background: var(--bs-secondary-bg);
|
||||
--ck-color-button-on-active-background: var(--bs-secondary-bg);
|
||||
--ck-color-button-on-disabled-background: var(--bs-secondary-bg);
|
||||
--ck-color-button-on-color: var(--bs-primary)
|
||||
|
||||
}
|
||||
@@ -18,6 +18,29 @@
|
||||
*/
|
||||
|
||||
.tagsinput.ts-wrapper.multi .ts-control > div {
|
||||
background: var(--bs-secondary);
|
||||
color: var(--bs-white);
|
||||
}
|
||||
background: var(--bs-secondary-bg);
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
/*********
|
||||
* BS 5.3 compatible dark mode
|
||||
***************/
|
||||
|
||||
.ts-dropdown .active {
|
||||
background-color: var(--bs-secondary-bg) !important;
|
||||
color: var(--bs-body-color) !important;
|
||||
}
|
||||
|
||||
.ts-dropdown, .ts-control, .ts-control input {
|
||||
color: var(--bs-body-color) !important;
|
||||
}
|
||||
|
||||
.ts-dropdown, .ts-dropdown.form-control, .ts-dropdown.form-select {
|
||||
background: var(--bs-body-bg);
|
||||
}
|
||||
|
||||
.ts-dropdown .optgroup-header {
|
||||
color: var(--bs-tertiary-color);
|
||||
background: var(--bs-body-bg);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
3
assets/fonts/dompdf/.gitignore
vendored
Normal file
3
assets/fonts/dompdf/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Ignore font files
|
||||
*.otf
|
||||
*.ttf
|
||||
1
assets/fonts/dompdf/README.md
Normal file
1
assets/fonts/dompdf/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Put your font ttf files in this folder to make them available to the label generator.
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
import '../css/app/layout.css';
|
||||
import '../css/app/helpers.css';
|
||||
import '../css/app/darkmode.css';
|
||||
import '../css/app/tables.css';
|
||||
import '../css/app/bs-overrides.css';
|
||||
import '../css/app/treeview.css';
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
method: config.method,
|
||||
data: {
|
||||
_dt: config.name,
|
||||
_init: true
|
||||
_init: true,
|
||||
order: config.initial_order ?? undefined,
|
||||
}
|
||||
}).done(function(data) {
|
||||
var baseState;
|
||||
@@ -72,6 +73,17 @@
|
||||
}
|
||||
} else {
|
||||
request._dt = config.name;
|
||||
|
||||
//Try to resolve the original column index when the column was reordered (using the ColReorder plugin)
|
||||
//Only do this when _ColReorder_iOrigCol is available
|
||||
if (settings.aoColumns && settings.aoColumns.length && settings.aoColumns[0]._ColReorder_iOrigCol !== undefined) {
|
||||
if (request.order && request.order.length) {
|
||||
request.order.forEach(function (order) {
|
||||
order.column = settings.aoColumns[order.column]._ColReorder_iOrigCol;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax(typeof config.url === 'function' ? config.url(dt) : config.url, {
|
||||
method: config.method,
|
||||
data: request
|
||||
|
||||
@@ -59,13 +59,16 @@ class RegisterEventHelper {
|
||||
}
|
||||
|
||||
registerTooltips() {
|
||||
this.registerLoadHandler(() => {
|
||||
const handler = () => {
|
||||
$(".tooltip").remove();
|
||||
//Exclude dropdown buttons from tooltips, otherwise we run into endless errors from bootstrap (bootstrap.esm.js:614 Bootstrap doesn't allow more than one instance per element. Bound instance: bs.dropdown.)
|
||||
$('a[title], button[title]:not([data-bs-toggle="dropdown"]), p[title], span[title], h6[title], h3[title], i.fas[title]')
|
||||
$('a[title], label[title], button[title]:not([data-bs-toggle="dropdown"]), p[title], span[title], h6[title], h3[title], i[title], small[title]')
|
||||
//@ts-ignore
|
||||
.tooltip("hide").tooltip({container: "body", placement: "auto", boundary: 'window'});
|
||||
});
|
||||
};
|
||||
|
||||
this.registerLoadHandler(handler);
|
||||
document.addEventListener('dt:loaded', handler);
|
||||
}
|
||||
|
||||
registerSpecialCharInput() {
|
||||
|
||||
@@ -21,8 +21,13 @@
|
||||
|
||||
class WebauthnTFA {
|
||||
|
||||
// Decodes a Base64Url string
|
||||
_base64UrlDecode = (input) => {
|
||||
_b64UrlSafeEncode = (str) => {
|
||||
const b64 = btoa(str);
|
||||
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
||||
}
|
||||
|
||||
// Decodes a Base64Url string
|
||||
_b64UrlSafeDecode = (input) => {
|
||||
input = input
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
@@ -39,13 +44,16 @@ class WebauthnTFA {
|
||||
};
|
||||
|
||||
// Converts an array of bytes into a Base64Url string
|
||||
_arrayToBase64String = (a) => btoa(String.fromCharCode(...a));
|
||||
_arrayToBase64String = (a) => {
|
||||
const str = String.fromCharCode(...a);
|
||||
return this._b64UrlSafeEncode(str);
|
||||
}
|
||||
|
||||
// Prepares the public key options object returned by the Webauthn Framework
|
||||
_preparePublicKeyOptions = publicKey => {
|
||||
//Convert challenge from Base64Url string to Uint8Array
|
||||
publicKey.challenge = Uint8Array.from(
|
||||
this._base64UrlDecode(publicKey.challenge),
|
||||
this._b64UrlSafeDecode(publicKey.challenge),
|
||||
c => c.charCodeAt(0)
|
||||
);
|
||||
|
||||
@@ -67,7 +75,7 @@ class WebauthnTFA {
|
||||
return {
|
||||
...data,
|
||||
id: Uint8Array.from(
|
||||
this._base64UrlDecode(data.id),
|
||||
this._b64UrlSafeDecode(data.id),
|
||||
c => c.charCodeAt(0)
|
||||
),
|
||||
};
|
||||
@@ -81,7 +89,7 @@ class WebauthnTFA {
|
||||
return {
|
||||
...data,
|
||||
id: Uint8Array.from(
|
||||
this._base64UrlDecode(data.id),
|
||||
this._b64UrlSafeDecode(data.id),
|
||||
c => c.charCodeAt(0)
|
||||
),
|
||||
};
|
||||
|
||||
16
assets/translator.js
Normal file
16
assets/translator.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { localeFallbacks } from '../var/translations/configuration';
|
||||
import { trans, getLocale, setLocale, setLocaleFallbacks } from '@symfony/ux-translator';
|
||||
/*
|
||||
* This file is part of the Symfony UX Translator package.
|
||||
*
|
||||
* If folder "../var/translations" does not exist, or some translations are missing,
|
||||
* you must warmup your Symfony cache to refresh JavaScript translations.
|
||||
*
|
||||
* If you use TypeScript, you can rename this file to "translator.ts" to take advantage of types checking.
|
||||
*/
|
||||
|
||||
setLocaleFallbacks(localeFallbacks);
|
||||
|
||||
export { trans };
|
||||
|
||||
export * from '../var/translations';
|
||||
123
composer.json
123
composer.json
@@ -2,74 +2,79 @@
|
||||
"type": "project",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0",
|
||||
"php": "^8.1",
|
||||
"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",
|
||||
"brick/math": "^0.11.0",
|
||||
"composer/package-versions-deprecated": "^1.11.99.5",
|
||||
"doctrine/annotations": "1.14.3",
|
||||
"doctrine/data-fixtures": "^1.6.6",
|
||||
"doctrine/dbal": "^3.4.6",
|
||||
"doctrine/doctrine-bundle": "^2.0",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||
"doctrine/orm": "^2.9",
|
||||
"dompdf/dompdf": "^2.0.0",
|
||||
"doctrine/orm": "^2.16",
|
||||
"dompdf/dompdf": "dev-master#87bea32efe0b0db309e1d31537201f64d5508280 as v2.0.3",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"florianv/swap": "^4.0",
|
||||
"florianv/swap-bundle": "dev-master",
|
||||
"gregwar/captcha-bundle": "^2.1.0",
|
||||
"hslavich/oneloginsaml-bundle": "^2.10",
|
||||
"jbtronics/2fa-webauthn": "^1.0.0",
|
||||
"jbtronics/2fa-webauthn": "^v2.0.0",
|
||||
"jbtronics/dompdf-font-loader-bundle": "^1.0.0",
|
||||
"jfcherng/php-diff": "^6.14",
|
||||
"knpuniversity/oauth2-client-bundle": "^2.15",
|
||||
"league/csv": "^9.8.0",
|
||||
"league/html-to-markdown": "^5.0.1",
|
||||
"liip/imagine-bundle": "^2.2",
|
||||
"nbgrp/onelogin-saml-bundle": "^1.3",
|
||||
"nelexa/zip": "^4.0",
|
||||
"nelmio/security-bundle": "^3.0",
|
||||
"nyholm/psr7": "^1.1",
|
||||
"ocramius/proxy-manager": "2.2.*",
|
||||
"omines/datatables-bundle": "^0.5.0",
|
||||
"php-translation/symfony-bundle": "^0.13.0",
|
||||
"omines/datatables-bundle": "^0.7.2",
|
||||
"part-db/label-fonts": "^1.0",
|
||||
"php-translation/symfony-bundle": "^0.14.0",
|
||||
"phpdocumentor/reflection-docblock": "^5.2",
|
||||
"s9e/text-formatter": "^2.1",
|
||||
"scheb/2fa-backup-code": "^5.13",
|
||||
"scheb/2fa-bundle": "^5.13",
|
||||
"scheb/2fa-google-authenticator": "^5.13",
|
||||
"scheb/2fa-trusted-device": "^5.13",
|
||||
"sensio/framework-extra-bundle": "^6.1.1",
|
||||
"scheb/2fa-backup-code": "^6.8.0",
|
||||
"scheb/2fa-bundle": "^6.8.0",
|
||||
"scheb/2fa-google-authenticator": "^6.8.0",
|
||||
"scheb/2fa-trusted-device": "^6.8.0",
|
||||
"shivas/versioning-bundle": "^4.0",
|
||||
"spatie/db-dumper": "^2.21",
|
||||
"spatie/db-dumper": "^3.3.1",
|
||||
"symfony/apache-pack": "^1.0",
|
||||
"symfony/asset": "5.4.*",
|
||||
"symfony/console": "5.4.*",
|
||||
"symfony/dotenv": "5.4.*",
|
||||
"symfony/expression-language": "5.4.*",
|
||||
"symfony/flex": "^1.1",
|
||||
"symfony/form": "5.4.*",
|
||||
"symfony/framework-bundle": "5.4.*",
|
||||
"symfony/http-client": "5.4.*",
|
||||
"symfony/http-kernel": "5.4.*",
|
||||
"symfony/mailer": "5.4.*",
|
||||
"symfony/asset": "6.3.*",
|
||||
"symfony/console": "6.3.*",
|
||||
"symfony/dotenv": "6.3.*",
|
||||
"symfony/expression-language": "6.3.*",
|
||||
"symfony/flex": "^v2.3.1",
|
||||
"symfony/form": "6.3.*",
|
||||
"symfony/framework-bundle": "6.3.*",
|
||||
"symfony/http-client": "6.3.*",
|
||||
"symfony/http-kernel": "6.3.*",
|
||||
"symfony/mailer": "6.3.*",
|
||||
"symfony/monolog-bundle": "^3.1",
|
||||
"symfony/process": "5.4.*",
|
||||
"symfony/property-access": "5.4.*",
|
||||
"symfony/property-info": "5.4.*",
|
||||
"symfony/proxy-manager-bridge": "5.4.*",
|
||||
"symfony/rate-limiter": "5.4.*",
|
||||
"symfony/runtime": "5.4.*",
|
||||
"symfony/security-bundle": "5.4.*",
|
||||
"symfony/serializer": "5.4.*",
|
||||
"symfony/translation": "5.4.*",
|
||||
"symfony/twig-bundle": "5.4.*",
|
||||
"symfony/process": "6.3.*",
|
||||
"symfony/property-access": "6.3.*",
|
||||
"symfony/property-info": "6.3.*",
|
||||
"symfony/proxy-manager-bridge": "6.3.*",
|
||||
"symfony/rate-limiter": "6.3.*",
|
||||
"symfony/runtime": "6.3.*",
|
||||
"symfony/security-bundle": "6.3.*",
|
||||
"symfony/serializer": "6.3.*",
|
||||
"symfony/translation": "6.3.*",
|
||||
"symfony/twig-bundle": "6.3.*",
|
||||
"symfony/ux-translator": "^2.10",
|
||||
"symfony/ux-turbo": "^2.0",
|
||||
"symfony/validator": "5.4.*",
|
||||
"symfony/web-link": "5.4.*",
|
||||
"symfony/webpack-encore-bundle": "^1.1",
|
||||
"symfony/yaml": "5.4.*",
|
||||
"symfony/validator": "6.3.*",
|
||||
"symfony/web-link": "6.3.*",
|
||||
"symfony/webpack-encore-bundle": "^v2.0.1",
|
||||
"symfony/yaml": "6.3.*",
|
||||
"tecnickcom/tc-lib-barcode": "^1.15",
|
||||
"twig/cssinliner-extra": "^3.0",
|
||||
"twig/extra-bundle": "^3.0",
|
||||
@@ -77,30 +82,30 @@
|
||||
"twig/inky-extra": "^3.0",
|
||||
"twig/intl-extra": "^3.0",
|
||||
"twig/markdown-extra": "^3.0",
|
||||
"web-auth/webauthn-symfony-bundle": "^3.3",
|
||||
"webmozart/assert": "^1.4",
|
||||
"doctrine/data-fixtures": "^1.6.6"
|
||||
|
||||
"web-auth/webauthn-symfony-bundle": "^4.0.0",
|
||||
"webmozart/assert": "^1.4"
|
||||
},
|
||||
"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",
|
||||
"phpstan/phpstan-doctrine": "^1.2.11",
|
||||
"phpstan/phpstan-strict-rules": "^1.5",
|
||||
"phpstan/phpstan-symfony": "^1.1.7",
|
||||
"psalm/plugin-symfony": "^v5.0.1",
|
||||
"rector/rector": "^0.18.0",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"symfony/browser-kit": "^5.2",
|
||||
"symfony/css-selector": "^5.2",
|
||||
"symfony/debug-bundle": "^5.2",
|
||||
"symfony/browser-kit": "6.3.*",
|
||||
"symfony/css-selector": "6.3.*",
|
||||
"symfony/debug-bundle": "6.3.*",
|
||||
"symfony/maker-bundle": "^1.13",
|
||||
"symfony/phpunit-bridge": "5.4.*",
|
||||
"symfony/stopwatch": "^5.2",
|
||||
"symfony/web-profiler-bundle": "^5.2",
|
||||
"symplify/easy-coding-standard": "^11.0",
|
||||
"vimeo/psalm": "^5.6.0",
|
||||
"doctrine/doctrine-fixtures-bundle": "^3.2"
|
||||
"symfony/phpunit-bridge": "6.3.*",
|
||||
"symfony/stopwatch": "6.3.*",
|
||||
"symfony/web-profiler-bundle": "6.3.*",
|
||||
"symplify/easy-coding-standard": "^12.0",
|
||||
"vimeo/psalm": "^5.6.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "Used to improve price calculation performance",
|
||||
@@ -111,7 +116,7 @@
|
||||
"*": "dist"
|
||||
},
|
||||
"platform": {
|
||||
"php": "7.4.0"
|
||||
"php": "8.1.0"
|
||||
},
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
@@ -143,7 +148,7 @@
|
||||
"post-update-cmd": [
|
||||
"@auto-scripts"
|
||||
],
|
||||
"phpstan": "vendor/bin/phpstan analyse src --level 2 --memory-limit 1G"
|
||||
"phpstan": "vendor/bin/phpstan analyse src --level 5 --memory-limit 1G"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/symfony": "*"
|
||||
@@ -151,9 +156,7 @@
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "5.4.*"
|
||||
"require": "6.3.*"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
6909
composer.lock
generated
6909
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
|
||||
require dirname(__DIR__).'/vendor/autoload.php';
|
||||
|
||||
if (!class_exists(Dotenv::class)) {
|
||||
throw new LogicException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
|
||||
}
|
||||
|
||||
// Load cached env vars if the .env.local.php file exists
|
||||
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
|
||||
if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) {
|
||||
(new Dotenv(false))->populate($env);
|
||||
} else {
|
||||
// load all the .env files
|
||||
(new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
|
||||
}
|
||||
|
||||
$_SERVER += $_ENV;
|
||||
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
|
||||
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
|
||||
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
return [
|
||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||
Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
@@ -27,5 +26,9 @@ return [
|
||||
Scheb\TwoFactorBundle\SchebTwoFactorBundle::class => ['all' => true],
|
||||
SpomkyLabs\CborBundle\SpomkyLabsCborBundle::class => ['all' => true],
|
||||
Webauthn\Bundle\WebauthnBundle::class => ['all' => true],
|
||||
Hslavich\OneloginSamlBundle\HslavichOneloginSamlBundle::class => ['all' => true],
|
||||
Nbgrp\OneloginSamlBundle\NbgrpOneloginSamlBundle::class => ['all' => true],
|
||||
Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
|
||||
Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true],
|
||||
Jbtronics\DompdfFontLoaderBundle\DompdfFontLoaderBundle::class => ['all' => true],
|
||||
KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true],
|
||||
];
|
||||
|
||||
@@ -20,3 +20,6 @@ framework:
|
||||
tree.cache:
|
||||
adapter: cache.app
|
||||
tags: true
|
||||
|
||||
info_provider.cache:
|
||||
adapter: cache.app
|
||||
|
||||
@@ -9,7 +9,7 @@ datatables:
|
||||
# Set options, as documented at https://datatables.net/reference/option/
|
||||
options:
|
||||
lengthMenu : [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]]
|
||||
pageLength: 50
|
||||
pageLength: '%partdb.table.default_page_size%' # Set to -1 to disable pagination (i.e. show all rows) by default
|
||||
#dom: "<'row' <'col-sm-12' tr>><'row' <'col-sm-6'l><'col-sm-6 text-right'pif>>"
|
||||
dom: " <'row'<'col mb-2 input-group' B l> <'col mb-2' <'pull-end' p>>>
|
||||
<'card'
|
||||
|
||||
@@ -21,12 +21,15 @@ doctrine:
|
||||
|
||||
orm:
|
||||
auto_generate_proxy_classes: true
|
||||
enable_lazy_ghost_objects: true
|
||||
report_fields_where_declared: true
|
||||
validate_xml_mapping: true
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
auto_mapping: true
|
||||
mappings:
|
||||
App:
|
||||
is_bundle: false
|
||||
type: annotation
|
||||
type: attribute
|
||||
dir: '%kernel.project_dir%/src/Entity'
|
||||
prefix: 'App\Entity'
|
||||
alias: App
|
||||
@@ -35,6 +38,8 @@ doctrine:
|
||||
string_functions:
|
||||
regexp: DoctrineExtensions\Query\Mysql\Regexp
|
||||
ifnull: DoctrineExtensions\Query\Mysql\IfNull
|
||||
field: DoctrineExtensions\Query\Mysql\Field
|
||||
field2: App\Doctrine\Functions\Field2
|
||||
|
||||
when@test:
|
||||
doctrine:
|
||||
|
||||
11
config/packages/dompdf_font_loader.yaml
Normal file
11
config/packages/dompdf_font_loader.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
dompdf_font_loader:
|
||||
auto_install: true
|
||||
|
||||
fonts:
|
||||
unifont:
|
||||
normal: "%kernel.project_dir%/vendor/part-db/label-fonts/fonts/unifont.ttf"
|
||||
|
||||
# Enable autodiscovery of fonts, so that font installation is much easier
|
||||
autodiscovery:
|
||||
paths:
|
||||
- "%kernel.project_dir%/assets/fonts/dompdf"
|
||||
@@ -2,8 +2,12 @@
|
||||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
csrf_protection: true
|
||||
handle_all_throwables: true
|
||||
|
||||
# Must be set to true, to enable the change of HTTP methhod via _method parameter, otherwise our delete routines does not work anymore
|
||||
# We set this header by ourself, so we can disable it here
|
||||
disallow_search_engine_index: false
|
||||
|
||||
# Must be set to true, to enable the change of HTTP method via _method parameter, otherwise our delete routines does not work anymore
|
||||
# TODO: Rework delete routines to work without _method parameter as it is not recommended anymore (see https://github.com/symfony/symfony/issues/45278)
|
||||
http_method_override: true
|
||||
|
||||
@@ -29,9 +33,6 @@ framework:
|
||||
php_errors:
|
||||
log: true
|
||||
|
||||
form:
|
||||
legacy_error_messages: false # Enable to use the new Form component validation messages
|
||||
|
||||
when@test:
|
||||
framework:
|
||||
test: true
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
# See https://github.com/SAML-Toolkits/php-saml for more information about the SAML settings
|
||||
|
||||
hslavich_onelogin_saml:
|
||||
# Basic settings
|
||||
idp:
|
||||
entityId: '%env(string:SAML_IDP_ENTITY_ID)%'
|
||||
singleSignOnService:
|
||||
url: '%env(string:SAML_IDP_SINGLE_SIGN_ON_SERVICE)%'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
|
||||
singleLogoutService:
|
||||
url: '%env(string:SAML_IDP_SINGLE_LOGOUT_SERVICE)%'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
|
||||
x509cert: '%env(string:SAML_IDP_X509_CERT)%'
|
||||
sp:
|
||||
entityId: '%env(string:SAML_SP_ENTITY_ID)%'
|
||||
assertionConsumerService:
|
||||
url: '%partdb.default_uri%saml/acs'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
|
||||
singleLogoutService:
|
||||
url: '%partdb.default_uri%logout'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
|
||||
x509cert: '%env(string:SAML_SP_X509_CERT)%'
|
||||
privateKey: '%env(string:SAMLP_SP_PRIVATE_KEY)%'
|
||||
|
||||
# Optional settings
|
||||
#baseurl: 'http://myapp.com'
|
||||
strict: true
|
||||
debug: false
|
||||
security:
|
||||
allowRepeatAttributeName: true
|
||||
# nameIdEncrypted: false
|
||||
authnRequestsSigned: true
|
||||
logoutRequestSigned: true
|
||||
logoutResponseSigned: true
|
||||
# wantMessagesSigned: false
|
||||
# wantAssertionsSigned: true
|
||||
# wantNameIdEncrypted: false
|
||||
# requestedAuthnContext: true
|
||||
# signMetadata: false
|
||||
# wantXMLValidation: true
|
||||
# relaxDestinationValidation: false
|
||||
# destinationStrictlyMatches: true
|
||||
# rejectUnsolicitedResponsesWithInResponseTo: false
|
||||
# signatureAlgorithm: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
|
||||
# digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256'
|
||||
#contactPerson:
|
||||
# technical:
|
||||
# givenName: 'Tech User'
|
||||
# emailAddress: 'techuser@example.com'
|
||||
# support:
|
||||
# givenName: 'Support User'
|
||||
# emailAddress: 'supportuser@example.com'
|
||||
# administrative:
|
||||
# givenName: 'Administrative User'
|
||||
# emailAddress: 'administrativeuser@example.com'
|
||||
#organization:
|
||||
# en:
|
||||
# name: 'Part-DB-name'
|
||||
# displayname: 'Displayname'
|
||||
# url: 'http://example.com'
|
||||
5
config/packages/http_client.yaml
Normal file
5
config/packages/http_client.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
framework:
|
||||
http_client:
|
||||
default_options:
|
||||
headers:
|
||||
'User-Agent': 'Part-DB'
|
||||
10
config/packages/http_discovery.yaml
Normal file
10
config/packages/http_discovery.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
services:
|
||||
Psr\Http\Message\RequestFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\ResponseFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\ServerRequestFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\StreamFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\UploadedFileFactoryInterface: '@http_discovery.psr17_factory'
|
||||
Psr\Http\Message\UriFactoryInterface: '@http_discovery.psr17_factory'
|
||||
|
||||
http_discovery.psr17_factory:
|
||||
class: Http\Discovery\Psr17Factory
|
||||
38
config/packages/knpu_oauth2_client.yaml
Normal file
38
config/packages/knpu_oauth2_client.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
knpu_oauth2_client:
|
||||
clients:
|
||||
# configure your clients as described here: https://github.com/knpuniversity/oauth2-client-bundle#configuration
|
||||
|
||||
ip_digikey_oauth:
|
||||
type: generic
|
||||
provider_class: '\League\OAuth2\Client\Provider\GenericProvider'
|
||||
|
||||
client_id: '%env(PROVIDER_DIGIKEY_CLIENT_ID)%'
|
||||
client_secret: '%env(PROVIDER_DIGIKEY_SECRET)%'
|
||||
|
||||
redirect_route: 'oauth_client_check'
|
||||
redirect_params: {name: 'ip_digikey_oauth'}
|
||||
|
||||
provider_options:
|
||||
urlAuthorize: 'https://api.digikey.com/v1/oauth2/authorize'
|
||||
urlAccessToken: 'https://api.digikey.com/v1/oauth2/token'
|
||||
urlResourceOwnerDetails: ''
|
||||
|
||||
# Sandbox
|
||||
#urlAuthorize: 'https://sandbox-api.digikey.com/v1/oauth2/authorize'
|
||||
#urlAccessToken: 'https://sandbox-api.digikey.com/v1/oauth2/token'
|
||||
#urlResourceOwnerDetails: ''
|
||||
|
||||
ip_octopart_oauth:
|
||||
type: generic
|
||||
provider_class: '\League\OAuth2\Client\Provider\GenericProvider'
|
||||
|
||||
client_id: '%env(PROVIDER_OCTOPART_CLIENT_ID)%'
|
||||
client_secret: '%env(PROVIDER_OCTOPART_SECRET)%'
|
||||
|
||||
redirect_route: 'oauth_client_check'
|
||||
redirect_params: { name: 'ip_octopart_oauth' }
|
||||
|
||||
provider_options:
|
||||
urlAuthorize: 'https://identity.nexar.com/connect/authorize'
|
||||
urlAccessToken: 'https://identity.nexar.com/connect/token'
|
||||
urlResourceOwnerDetails: ''
|
||||
@@ -1,2 +0,0 @@
|
||||
framework:
|
||||
lock: '%env(LOCK_DSN)%'
|
||||
68
config/packages/nbgrp_onelogin_saml.yaml
Normal file
68
config/packages/nbgrp_onelogin_saml.yaml
Normal file
@@ -0,0 +1,68 @@
|
||||
# See https://github.com/SAML-Toolkits/php-saml for more information about the SAML settings
|
||||
|
||||
# Define a parameter here, so we can access it later in the default fallback
|
||||
parameters:
|
||||
saml.sp.privateKey: '%env(string:SAML_SP_PRIVATE_KEY)%'
|
||||
|
||||
nbgrp_onelogin_saml:
|
||||
onelogin_settings:
|
||||
default:
|
||||
# Basic settings
|
||||
idp:
|
||||
entityId: '%env(string:SAML_IDP_ENTITY_ID)%'
|
||||
singleSignOnService:
|
||||
url: '%env(string:SAML_IDP_SINGLE_SIGN_ON_SERVICE)%'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
|
||||
singleLogoutService:
|
||||
url: '%env(string:SAML_IDP_SINGLE_LOGOUT_SERVICE)%'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
|
||||
x509cert: '%env(string:SAML_IDP_X509_CERT)%'
|
||||
sp:
|
||||
entityId: '%env(string:SAML_SP_ENTITY_ID)%'
|
||||
assertionConsumerService:
|
||||
url: '%partdb.default_uri%saml/acs'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
|
||||
singleLogoutService:
|
||||
url: '%partdb.default_uri%logout'
|
||||
binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
|
||||
x509cert: '%env(string:SAML_SP_X509_CERT)%'
|
||||
# Before the env variable was wrongly named "SAMLP_SP_PRIVATE_KEY".
|
||||
# For compatibility reasons we keep it and only fallback to the new name if the old one is not set. This may be removed in the future.
|
||||
privateKey: '%env(string:default:saml.sp.privateKey:string:SAMLP_SP_PRIVATE_KEY)%'
|
||||
|
||||
# Optional settings
|
||||
#baseurl: 'http://myapp.com'
|
||||
strict: true
|
||||
debug: false
|
||||
security:
|
||||
allowRepeatAttributeName: true
|
||||
# nameIdEncrypted: false
|
||||
authnRequestsSigned: true
|
||||
logoutRequestSigned: true
|
||||
logoutResponseSigned: true
|
||||
# wantMessagesSigned: false
|
||||
# wantAssertionsSigned: true
|
||||
# wantNameIdEncrypted: false
|
||||
# requestedAuthnContext: true
|
||||
# signMetadata: false
|
||||
# wantXMLValidation: true
|
||||
# relaxDestinationValidation: false
|
||||
# destinationStrictlyMatches: true
|
||||
# rejectUnsolicitedResponsesWithInResponseTo: false
|
||||
# signatureAlgorithm: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
|
||||
# digestAlgorithm: 'http://www.w3.org/2001/04/xmlenc#sha256'
|
||||
#contactPerson:
|
||||
# technical:
|
||||
# givenName: 'Tech User'
|
||||
# emailAddress: 'techuser@example.com'
|
||||
# support:
|
||||
# givenName: 'Support User'
|
||||
# emailAddress: 'supportuser@example.com'
|
||||
# administrative:
|
||||
# givenName: 'Administrative User'
|
||||
# emailAddress: 'administrativeuser@example.com'
|
||||
#organization:
|
||||
# en:
|
||||
# name: 'Part-DB-name'
|
||||
# displayname: 'Displayname'
|
||||
# url: 'http://example.com'
|
||||
@@ -12,6 +12,13 @@ nelmio_security:
|
||||
external_redirects:
|
||||
abort: true
|
||||
log: true
|
||||
allow_list:
|
||||
# Whitelist the domain of the SAML IDP, so we can redirect to it during the SAML login process
|
||||
- '%env(string:key:host:url:SAML_IDP_SINGLE_SIGN_ON_SERVICE)%'
|
||||
|
||||
# Whitelist the info provider APIs (OAuth redirects)
|
||||
- 'digikey.com'
|
||||
- 'nexar.com'
|
||||
|
||||
# forces Microsoft's XSS-Protection with
|
||||
# its block mode
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# See the configuration reference at https://symfony.com/bundles/SchebTwoFactorBundle/5.x/configuration.html
|
||||
# See the configuration reference at https://symfony.com/bundles/SchebTwoFactorBundle/6.x/configuration.html
|
||||
scheb_two_factor:
|
||||
|
||||
google:
|
||||
enabled: true # If Google Authenticator should be enabled, default false
|
||||
server_name: '%partdb.title%' # Server name used in QR code
|
||||
issuer: 'Part-DB' # Issuer name used in QR code
|
||||
server_name: '$$DOMAIN$$' # This field is replaced by the domain name of the server in DecoratedGoogleAuthenticator
|
||||
issuer: '%partdb.title%' # Issuer name used in QR code
|
||||
digits: 6 # Number of digits in authentication code
|
||||
window: 1 # How many codes before/after the current one would be accepted as valid
|
||||
template: security/2fa_form.html.twig
|
||||
@@ -23,6 +23,6 @@ scheb_two_factor:
|
||||
security_tokens:
|
||||
- Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
|
||||
# If you're using guard-based authentication, you have to use this one:
|
||||
# - Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken
|
||||
# - Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken
|
||||
# If you're using authenticator-based security (introduced in Symfony 5.1), you have to use this one:
|
||||
# - Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken
|
||||
- Symfony\Component\Security\Http\Authenticator\Token\PostAuthenticationToken
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
security:
|
||||
enable_authenticator_manager: true
|
||||
|
||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||
password_hashers:
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||
|
||||
@@ -22,6 +21,9 @@ security:
|
||||
user_checker: App\Security\UserChecker
|
||||
entry_point: form_login
|
||||
|
||||
# Enable user impersonation
|
||||
switch_user: { role: CAN_SWITCH_USER }
|
||||
|
||||
two_factor:
|
||||
auth_form_path: 2fa_login
|
||||
check_path: 2fa_login_check
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
sensio_framework_extra:
|
||||
router:
|
||||
annotations: false
|
||||
@@ -1,4 +1,2 @@
|
||||
framework:
|
||||
test: true
|
||||
session:
|
||||
storage_id: session.storage.mock_file
|
||||
|
||||
4
config/packages/uid.yaml
Normal file
4
config/packages/uid.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
framework:
|
||||
uid:
|
||||
default_uuid_version: 7
|
||||
time_based_uuid_version: 7
|
||||
3
config/packages/ux_translator.yaml
Normal file
3
config/packages/ux_translator.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
ux_translator:
|
||||
# The directory where the JavaScript translations are dumped
|
||||
dump_directory: '%kernel.project_dir%/var/translations'
|
||||
@@ -4,7 +4,9 @@ when@dev:
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
profiler: { only_exceptions: false }
|
||||
profiler:
|
||||
only_exceptions: false
|
||||
collect_serializer_data: true
|
||||
|
||||
when@test:
|
||||
web_profiler:
|
||||
|
||||
@@ -11,7 +11,7 @@ parameters:
|
||||
partdb.banner: '%env(trim:string:BANNER)%' # The info text shown in the homepage, if empty config/banner.md is used
|
||||
partdb.default_currency: '%env(string:BASE_CURRENCY)%' # The currency that is used inside the DB (and is assumed when no currency is set). This can not be changed later, so be sure to set it the currency used in your country
|
||||
partdb.global_theme: '' # The theme to use globally (see public/build/themes/ for choices, use name without .css). Set to '' for default bootstrap theme
|
||||
partdb.locale_menu: ['en', 'de', 'fr', 'ru', 'ja'] # The languages that are shown in user drop down menu
|
||||
partdb.locale_menu: ['en', 'de', 'it', 'fr', 'ru', 'ja'] # The languages that are shown in user drop down menu
|
||||
partdb.enforce_change_comments_for: '%env(csv:ENFORCE_CHANGE_COMMENTS_FOR)%' # The actions for which a change comment is required (e.g. "part_edit", "part_create", etc.). If this is empty, change comments are not required at all.
|
||||
|
||||
partdb.default_uri: '%env(string:DEFAULT_URI)%' # The default URI to use for the Part-DB instance (e.g. https://part-db.example.com/). This is used for generating links in emails
|
||||
@@ -19,10 +19,12 @@ parameters:
|
||||
######################################################################################################################
|
||||
# Users and Privacy
|
||||
######################################################################################################################
|
||||
partdb.gpdr_compliance: true # If this option is activated, IP addresses are anonymized to be GPDR compliant
|
||||
partdb.gdpr_compliance: true # If this option is activated, IP addresses are anonymized to be GDPR compliant
|
||||
partdb.users.use_gravatar: '%env(bool:USE_GRAVATAR)%' # Set to false, if no Gravatar images should be used for user profiles.
|
||||
partdb.users.email_pw_reset: '%env(bool:ALLOW_EMAIL_PW_RESET)%' # Config if users are able, to reset their password by email. By default this enabled, when a mail server is configured.
|
||||
|
||||
partdb.check_for_updates: '%env(bool:CHECK_FOR_UPDATES)' # Set to false, if Part-DB should not contact the GitHub API to check for updates
|
||||
|
||||
######################################################################################################################
|
||||
# Mail settings
|
||||
######################################################################################################################
|
||||
@@ -48,6 +50,11 @@ parameters:
|
||||
######################################################################################################################
|
||||
partdb.saml.enabled: '%env(bool:SAML_ENABLED)%' # If this is set to true, SAML authentication is enabled
|
||||
|
||||
######################################################################################################################
|
||||
# Table settings
|
||||
######################################################################################################################
|
||||
partdb.table.default_page_size: '%env(int:TABLE_DEFAULT_PAGE_SIZE)%' # The default number of entries shown per page in tables
|
||||
|
||||
######################################################################################################################
|
||||
# Sidebar
|
||||
######################################################################################################################
|
||||
@@ -119,9 +126,17 @@ parameters:
|
||||
env(EMAIL_SENDER_NAME): 'Part-DB Mailer'
|
||||
env(ALLOW_EMAIL_PW_RESET): 0
|
||||
|
||||
env(TABLE_DEFAULT_PAGE_SIZE): 50
|
||||
|
||||
env(TRUSTED_PROXIES): '127.0.0.1' #By default trust only our own server
|
||||
env(TRUSTED_HOSTS): '' # Trust all host names by default
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -139,6 +139,13 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
|
||||
ic_logos:
|
||||
label: "perm.tools.ic_logos"
|
||||
|
||||
info_providers:
|
||||
label: "perm.part.info_providers"
|
||||
operations:
|
||||
create_parts:
|
||||
label: "perm.part.info_providers.create_parts"
|
||||
alsoSet: ['parts.create']
|
||||
|
||||
groups:
|
||||
label: "perm.groups"
|
||||
group: "system"
|
||||
@@ -190,6 +197,9 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
|
||||
set_password:
|
||||
label: "perm.users.set_password"
|
||||
alsoSet: 'read'
|
||||
impersonate:
|
||||
label: "perm.users.impersonate"
|
||||
alsoSet: ['set_password']
|
||||
change_user_settings:
|
||||
label: "perm.users.change_user_settings"
|
||||
show_history:
|
||||
@@ -239,6 +249,10 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
|
||||
alsoSet: 'show_logs'
|
||||
server_infos:
|
||||
label: "perm.server_infos"
|
||||
manage_oauth_tokens:
|
||||
label: "Manage OAuth tokens"
|
||||
show_updates:
|
||||
label: "perm.system.show_available_updates"
|
||||
|
||||
attachments:
|
||||
label: "perm.part.attachments"
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
#index:
|
||||
# path: /
|
||||
# controller: App\Controller\DefaultController::index
|
||||
|
||||
# Redirect every url without an locale to the locale of the user/the global base locale
|
||||
|
||||
scan_qr:
|
||||
path: /scan/{type}/{id}
|
||||
controller: App\Controller\ScanController:scanQRCode
|
||||
controller: App\Controller\ScanController::scanQRCode
|
||||
|
||||
csp_report:
|
||||
path: /csp/report
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
controllers:
|
||||
resource: ../../src/Controller/
|
||||
type: annotation
|
||||
resource:
|
||||
path: ../../src/Controller/
|
||||
namespace: App\Controller
|
||||
type: attribute
|
||||
prefix: '{_locale}'
|
||||
|
||||
defaults:
|
||||
@@ -11,4 +13,4 @@ controllers:
|
||||
|
||||
kernel:
|
||||
resource: ../../src/Kernel.php
|
||||
type: annotation
|
||||
type: attribute
|
||||
@@ -1,4 +1,4 @@
|
||||
hslavich_saml_sp:
|
||||
resource: "@HslavichOneloginSamlBundle/Resources/config/routing.yml"
|
||||
nbgrp_saml:
|
||||
resource: "@NbgrpOneloginSamlBundle/Resources/config/routes.php"
|
||||
# Only load the SAML routes if SAML is enabled
|
||||
condition: "env('SAML_ENABLED') == '1' or env('SAML_ENABLED') == 'true'"
|
||||
@@ -14,16 +14,19 @@ services:
|
||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||
bind:
|
||||
bool $demo_mode: '%partdb.demo_mode%'
|
||||
bool $gpdr_compliance : '%partdb.gpdr_compliance%'
|
||||
bool $kernel_debug: '%kernel.debug%'
|
||||
bool $gdpr_compliance: '%partdb.gdpr_compliance%'
|
||||
bool $kernel_debug_enabled: '%kernel.debug%'
|
||||
string $kernel_cache_dir: '%kernel.cache_dir%'
|
||||
string $partdb_title: '%partdb.title%'
|
||||
string $default_currency: '%partdb.default_currency%'
|
||||
string $base_currency: '%partdb.default_currency%'
|
||||
|
||||
_instanceof:
|
||||
App\Services\LabelSystem\PlaceholderProviders\PlaceholderProviderInterface:
|
||||
tags: ['app.label_placeholder_provider']
|
||||
|
||||
App\Services\InfoProviderSystem\Providers\InfoProviderInterface:
|
||||
tags: ['app.info_provider']
|
||||
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
@@ -78,6 +81,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' }
|
||||
|
||||
@@ -87,7 +91,7 @@ services:
|
||||
|
||||
App\Form\AttachmentFormType:
|
||||
arguments:
|
||||
$allow_attachments_downloads: '%partdb.attachments.allow_downloads%'
|
||||
$allow_attachments_download: '%partdb.attachments.allow_downloads%'
|
||||
$max_file_size: '%partdb.attachments.max_file_size%'
|
||||
|
||||
App\Services\Attachments\AttachmentSubmitHandler:
|
||||
@@ -96,12 +100,6 @@ services:
|
||||
$mimeTypes: '@mime_types'
|
||||
$max_upload_size: '%partdb.attachments.max_file_size%'
|
||||
|
||||
App\EventSubscriber\LogSystem\LogoutLoggerListener:
|
||||
tags:
|
||||
- name: 'kernel.event_listener'
|
||||
event: 'Symfony\Component\Security\Http\Event\LogoutEvent'
|
||||
dispatcher: security.event_dispatcher.main
|
||||
|
||||
App\Services\LogSystem\EventCommentNeededHelper:
|
||||
arguments:
|
||||
$enforce_change_comments_for: '%partdb.enforce_change_comments_for%'
|
||||
@@ -182,7 +180,7 @@ services:
|
||||
|
||||
App\EventSubscriber\UserSystem\SetUserTimezoneSubscriber:
|
||||
arguments:
|
||||
$timezone: '%partdb.timezone%'
|
||||
$default_timezone: '%partdb.timezone%'
|
||||
|
||||
App\Controller\SecurityController:
|
||||
arguments:
|
||||
@@ -226,6 +224,11 @@ services:
|
||||
tags:
|
||||
- { name: 'app.label_placeholder_provider', priority: 10}
|
||||
|
||||
App\Services\LabelSystem\DompdfFactory:
|
||||
arguments:
|
||||
$fontDirectory: '%kernel.project_dir%/var/dompdf/fonts/'
|
||||
$tmpDirectory: '%kernel.project_dir%/var/dompdf/tmp/'
|
||||
|
||||
####################################################################################################################
|
||||
# Trees
|
||||
####################################################################################################################
|
||||
@@ -234,6 +237,46 @@ services:
|
||||
$rootNodeExpandedByDefault: '%partdb.sidebar.root_expanded%'
|
||||
$rootNodeEnabled: '%partdb.sidebar.root_node_enable%'
|
||||
|
||||
####################################################################################################################
|
||||
# Part info provider system
|
||||
####################################################################################################################
|
||||
App\Services\InfoProviderSystem\ProviderRegistry:
|
||||
arguments:
|
||||
$providers: !tagged_iterator 'app.info_provider'
|
||||
|
||||
App\Services\InfoProviderSystem\Providers\Element14Provider:
|
||||
arguments:
|
||||
$api_key: '%env(string:PROVIDER_ELEMENT14_KEY)%'
|
||||
$store_id: '%env(string:PROVIDER_ELEMENT14_STORE_ID)%'
|
||||
|
||||
App\Services\InfoProviderSystem\Providers\DigikeyProvider:
|
||||
arguments:
|
||||
$clientId: '%env(string:PROVIDER_DIGIKEY_CLIENT_ID)%'
|
||||
$currency: '%env(string:PROVIDER_DIGIKEY_CURRENCY)%'
|
||||
$language: '%env(string:PROVIDER_DIGIKEY_LANGUAGE)%'
|
||||
$country: '%env(string:PROVIDER_DIGIKEY_COUNTRY)%'
|
||||
|
||||
App\Services\InfoProviderSystem\Providers\TMEClient:
|
||||
arguments:
|
||||
$secret: '%env(string:PROVIDER_TME_SECRET)%'
|
||||
$token: '%env(string:PROVIDER_TME_KEY)%'
|
||||
|
||||
App\Services\InfoProviderSystem\Providers\TMEProvider:
|
||||
arguments:
|
||||
$currency: '%env(string:PROVIDER_TME_CURRENCY)%'
|
||||
$country: '%env(string:PROVIDER_TME_COUNTRY)%'
|
||||
$language: '%env(string:PROVIDER_TME_LANGUAGE)%'
|
||||
$get_gross_prices: '%env(bool:PROVIDER_TME_GET_GROSS_PRICES)%'
|
||||
|
||||
App\Services\InfoProviderSystem\Providers\OctopartProvider:
|
||||
arguments:
|
||||
$clientId: '&env(string:PROVIDER_OCTOPART_CLIENT_ID)%'
|
||||
$secret: '%env(string:PROVIDER_OCTOPART_SECRET)%'
|
||||
$country: '%env(string:PROVIDER_OCTOPART_COUNTRY)%'
|
||||
$currency: '%env(string:PROVIDER_OCTOPART_CURRENCY)%'
|
||||
$search_limit: '%env(int:PROVIDER_OCTOPART_SEARCH_LIMIT)%'
|
||||
$onlyAuthorizedSellers: '%env(bool:PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS)%'
|
||||
|
||||
####################################################################################################################
|
||||
# Symfony overrides
|
||||
####################################################################################################################
|
||||
@@ -264,7 +307,7 @@ services:
|
||||
tags:
|
||||
- { name: 'doctrine.fixtures.purger_factory', alias: 'reset_autoincrement_purger' }
|
||||
|
||||
# We are needing this service inside of a migration, where only the container is injected. So we need to define it as public, to access it from the container.
|
||||
# We are needing this service inside a migration, where only the container is injected. So we need to define it as public, to access it from the container.
|
||||
App\Services\UserSystem\PermissionPresetsHelper:
|
||||
public: true
|
||||
|
||||
@@ -272,6 +315,10 @@ services:
|
||||
arguments:
|
||||
$project_dir: '%kernel.project_dir%'
|
||||
|
||||
App\Services\System\UpdateAvailableManager:
|
||||
arguments:
|
||||
$check_for_updates: '%partdb.check_for_updates%'
|
||||
|
||||
####################################################################################################################
|
||||
# Monolog
|
||||
####################################################################################################################
|
||||
@@ -288,3 +335,14 @@ services:
|
||||
autowire: true
|
||||
tags:
|
||||
- { name: monolog.processor }
|
||||
|
||||
when@test:
|
||||
services:
|
||||
# Decorate the doctrine fixtures load command to use our custom purger by default
|
||||
doctrine.fixtures_load_command.custom:
|
||||
decorates: doctrine.fixtures_load_command
|
||||
class: Doctrine\Bundle\FixturesBundle\Command\LoadDataFixturesDoctrineCommand
|
||||
arguments:
|
||||
- '@doctrine.fixtures.loader'
|
||||
- '@doctrine'
|
||||
- { default: '@App\Doctrine\Purger\ResetAutoIncrementPurgerFactory' }
|
||||
BIN
docs/assets/usage/information_provider_system/animation.gif
Normal file
BIN
docs/assets/usage/information_provider_system/animation.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 358 KiB |
@@ -36,6 +36,7 @@ The following configuration options can only be changed by the server administra
|
||||
* `datastructure_edit`: Edit operation of a existing datastructure (e.g. category, manufacturer, ...)
|
||||
* `datastructure_delete`: Delete operation of a existing datastructure (e.g. category, manufacturer, ...)
|
||||
* `datastructure_create`: Creation of a new datastructure (e.g. category, manufacturer, ...)
|
||||
* `CHECK_FOR_UPDATES` (default `1`): Set this to 0, if you do not want Part-DB to connect to GitHub to check for new versions, or if your server can not connect to the internet.
|
||||
|
||||
### E-Mail settings
|
||||
* `MAILER_DSN`: You can configure the mail provider which should be used for email delivery (see https://symfony.com/doc/current/components/mailer.html for full documentation). If you just want to use an SMTP mail account, you can use the following syntax `MAILER_DSN=smtp://user:password@smtp.mailserver.invalid:587`
|
||||
@@ -43,11 +44,15 @@ The following configuration options can only be changed by the server administra
|
||||
* `EMAIL_SENDER_NAME`: Similar to `EMAIL_SENDER_EMAIL` but this allows you to specify the name from which the mails are sent from.
|
||||
* `ALLOW_EMAIL_PW_RESET`: Set this value to true, if you wan to allow users to reset their password via an email notification. You have to configure the mailprovider first before via the MAILER_DSN setting.
|
||||
|
||||
### Table related settings
|
||||
* `TABLE_DEFAULT_PAGE_SIZE`: The default page size for tables. This is the number of rows which are shown per page. Set to `-1` to disable pagination and show all rows at once.
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -70,6 +75,9 @@ You can find more advanced settings in the `config/packages/hslavich_onelogin_sa
|
||||
* `SAML_SP_X509_CERT`: The public X.509 certificate of your SAML SP (here Part-DB). This is the value you have configured for the Part-DB client in your IdP. It should start with `MIIC` and end with `=`. IdPs like keycloak allows you to generate a public/private key pair for the client which you can setup here and in the `SAML_SP_PRIVATE_KEY` setting.
|
||||
* `SAML_SP_PRIVATE_KEY`: The private key of your SAML SP (here Part-DB), corresponding the public key specified in `SAML_SP_X509_CERT`. This is the value you have configured for the Part-DB client in your IdP. It should start with `MIIE` and end with `=`. IdPs like keycloak allows you to generate a public/private key pair for the client which you can setup here and in the `SAML_SP_X509_CERT` setting.
|
||||
|
||||
### Information provider settings
|
||||
The settings prefixes with `PROVIDER_*` are used to configure the information providers.
|
||||
See the [information providers]({% link usage/information_provider_system.md %}) page for more information.
|
||||
|
||||
### Other / less used options
|
||||
* `TRUSTED_PROXIES`: Set the IP addresses (or IP blocks) of trusted reverse proxies here. This is needed to get correct IP informations (see [here](https://symfony.com/doc/current/deployment/proxies.html) for more info).
|
||||
@@ -97,7 +105,7 @@ The following options are available:
|
||||
|
||||
* `partdb.global_theme`: The default theme to use, when no user specific theme is set. Should be one of the themes from the `partdb.available_themes` config option.
|
||||
* `partdb.locale_menu`: The codes of the languages, which should be shown in the language chooser menu (the one with the user icon in the navbar). The first language in the list will be the default language.
|
||||
* `partdb.gpdr_compliance`: When set to true (default value), IP addresses which are saved in the database will be anonymized, by removing the last byte of the IP. This is required by the GDPR (General Data Protection Regulation) in the EU.
|
||||
* `partdb.gdpr_compliance`: When set to true (default value), IP addresses which are saved in the database will be anonymized, by removing the last byte of the IP. This is required by the GDPR (General Data Protection Regulation) in the EU.
|
||||
* `partdb.sidebar.items`: The panel contents which should be shown in the sidebar by default. You can also change the number of sidebar panels by changing the number of items in this list.
|
||||
* `partdb.sidebar.root_node_enable`: Show a root node in the sidebar trees, of which all nodes are children of
|
||||
* `partdb.sidebar.root_expanded`: Expand the root node in the sidebar trees by default
|
||||
|
||||
@@ -37,6 +37,7 @@ It is installed on a web server and so can be accessed with any browser without
|
||||
* Support for multiple currencies and automatic update of exchange rates supported
|
||||
* Powerful search and filter function, including parametric search (search for parts according to some specifications)
|
||||
* Easy migration from an existing PartKeepr instance (see [here]({%link partkeepr_migration.md %}))
|
||||
* Use cloud providers (like Octopart, Digikey, farnell or TME) to automatically get part information, datasheets and prices for parts (see [here]({% link usage/information_provider_system.md %}))
|
||||
|
||||
With these features Part-DB is useful to hobbyists, who want to keep track of their private electronic parts inventory,
|
||||
or makerspaces, where many users have should have (controlled) access to the shared inventory.
|
||||
|
||||
@@ -22,9 +22,9 @@ sudo apt install git curl zip ca-certificates software-properties-common apt-tra
|
||||
```
|
||||
|
||||
### Install PHP and apache2
|
||||
Part-DB is written in [PHP](https://php.net) and therefore needs an PHP interpreter to run. Part-DB needs PHP 7.3 or higher, however it is recommended to use the most recent version of PHP for performance reasons and future compatibility.
|
||||
Part-DB is written in [PHP](https://php.net) and therefore needs an PHP interpreter to run. Part-DB needs PHP 8.1 or higher, however it is recommended to use the most recent version of PHP for performance reasons and future compatibility.
|
||||
|
||||
As Debian 11 does not ship PHP 8.1 in it's default repositories, we have to add a repository for it. You can skip this step if your distribution is shipping a recent version of PHP or you want to use the built-in PHP version.
|
||||
As Debian 11 does not ship PHP 8.1 in it's default repositories, we have to add a repository for it. You can skip this step if your distribution is shipping a recent version of PHP or you want to use the built-in PHP version. If you are using Debian 12, you can skip this step, as PHP 8.1 is already included in the default repositories.
|
||||
```bash
|
||||
# Add sury repository for PHP 8.1
|
||||
sudo curl -sSL https://packages.sury.org/php/README.txt | sudo bash -x
|
||||
@@ -74,6 +74,17 @@ We now have all prerequisites installed and can start to install Part-DB. We wil
|
||||
git clone https://github.com/Part-DB/Part-DB-symfony.git /var/www/partdb
|
||||
```
|
||||
|
||||
By default you are now on the latest development version. In most cases you want to use the latest stable version. You can switch to the latest stable version (tagged) by running the following command:
|
||||
```bash
|
||||
# This finds the latest release/tag and checks it out
|
||||
git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
|
||||
```
|
||||
Alternatively you can checkout a specific version by running (see [GitHub Relases page](https://github.com/Part-DB/Part-DB-server/releases) for a list of available versions):
|
||||
```bash
|
||||
# This checks out the version 1.5.2
|
||||
git checkout v1.5.2
|
||||
```
|
||||
|
||||
Change ownership of the files to the apache user:
|
||||
```bash
|
||||
chown -R www-data:www-data /var/www/partdb
|
||||
@@ -90,7 +101,7 @@ The basic configuration of Part-DB is done by a `.env.local` file in the main di
|
||||
cp .env .env.local
|
||||
```
|
||||
|
||||
In your `.env.local` you can configure Part-DB according to your wishes. A full list of configuration options can be found [here]({% link configuration.md %}.
|
||||
In your `.env.local` you can configure Part-DB according to your wishes. A full list of configuration options can be found [here](../configuration.md).
|
||||
Other configuration options like the default language or default currency can be found in `config/parameters.yaml`.
|
||||
|
||||
Please check that the `partdb.default_currency` value in `config/parameters.yaml` matches your mainly used currency, as this can not be changed after creating price informations.
|
||||
@@ -184,6 +195,10 @@ If you want to update your existing Part-DB installation, you just have to run t
|
||||
cd /var/www/partdb
|
||||
# Pull latest Part-DB version from GitHub
|
||||
git pull
|
||||
|
||||
# Checkout the latest version (or use a specific version, like described above)
|
||||
git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
|
||||
|
||||
# Apply correct permission
|
||||
chown -R www-data:www-data .
|
||||
# Install new composer dependencies
|
||||
|
||||
@@ -143,7 +143,7 @@ The reverse is also possible: If you have existing SAML users and want them to b
|
||||
> It is recommended that you let the original admin user (ID: 2) be a local user, so you can still login to Part-DB if the SAML identity provider is not available.
|
||||
|
||||
## Advanced SAML configuration
|
||||
You can find some more advanced SAML configuration options in the `config/packages/hslavich_onelogin_saml.yaml` file. Refer to the file for more information.
|
||||
You can find some more advanced SAML configuration options in the `config/packages/nbgrp_onelogin_saml.yaml` file. Refer to the file for more information.
|
||||
Normally you don't have to change anything here.
|
||||
|
||||
Please note that this file is not saved by the Part-DB backup tool, so you have to save it manually if you want to keep your changes. On docker containers you have to configure a volume mapping for it.
|
||||
|
||||
142
docs/usage/information_provider_system.md
Normal file
142
docs/usage/information_provider_system.md
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
title: Information provider system
|
||||
layout: default
|
||||
parent: Usage
|
||||
---
|
||||
|
||||
# Information provider system
|
||||
|
||||
Part-DB can create parts based on information from external sources: For example with the right setup you can just search for a part number
|
||||
and Part-DB will query selected distributors and manufacturers for the part and create a part with the information it found.
|
||||
This way your Part-DB parts automatically get datasheet links, prices, parameters and more, with just a few clicks.
|
||||
|
||||
## Usage
|
||||
|
||||
Before you can use the information provider system, you have to configure at least one information provider, which act as data source.
|
||||
See below for a list of available information providers and available configuration options.
|
||||
For many providers it is enough, to setup the API keys in the env configuration, some require an additional OAuth connection.
|
||||
You can list all enabled information providers in the browser at `https://your-partdb-instance.tld/tools/info_providers/providers` (you need the right permission for it, see below).
|
||||
|
||||
To use the information provider system, your user need to have the right permissions. Go to the permission management page of
|
||||
a user or a group and assign the permissions of the "Info providers" group in the "Miscellaneous" tab.
|
||||
|
||||
If you have the required permission you will find in the sidebar in the "Tools" section the entry "Create part from info provider".
|
||||
Click this and you will land on a search page. Enter the part number you want to search for and select the information providers you want to use.
|
||||
|
||||
After you click Search, you will be presented with the results and can select the result that fits best.
|
||||
With a click on the blue plus button, you will be redirected to the part creation page with the information already filled in.
|
||||
|
||||

|
||||
|
||||
## Alternative names
|
||||
|
||||
Part-DB tries to automatically find existing elements from your database for the information it got from the providers for fields like manufacturer, footprint, etc.
|
||||
For this it searches for a element with the same name (case-insensitive) as the information it got from the provider. So e.g. if the provider returns "EXAMPLE CORP" as manufacturer,
|
||||
Part-DB will automatically select the element with the name "Example Corp" from your database.
|
||||
|
||||
As the names of these fields differ from provider to provider (and maybe not even normalized for the same provider), you
|
||||
can define multiple alternative names for an element (on their editing page).
|
||||
For example if define a manufacturer "Example Corp" with the alternative names "Example Corp.", "Example Corp", "Example Corp. Inc." and "Example Corporation",
|
||||
then the provider can return any of these names and Part-DB will still automatically select the right element.
|
||||
|
||||
If Part-DB finds no matching element, it will automatically create a new one, when you do not change the value before saving.
|
||||
|
||||
## Attachment types
|
||||
|
||||
The information provider system uses attachment types to differentiate between datasheets and image attachments.
|
||||
For this it will create a "Datasheet" and "Image" attachment type on the first run. You can change the names of these
|
||||
types in the attachment type settings (as long as you keep the "Datasheet"/"Image" in the alternative names field).
|
||||
|
||||
If you already have attachment types for images and datasheets and want the information provider system to use them, you can
|
||||
add the alternative names "Datasheet" and "Image" to the alternative names field of the attachment types.
|
||||
|
||||
## Data providers
|
||||
|
||||
The system tries to be as flexible as possible, so many different information sources can be used.
|
||||
Each information source is called am "info provider" and handles the communication with the external source.
|
||||
The providers are just a driver which handles the communication with the different external sources and converts them into a common format Part-DB understands.
|
||||
That way it is pretty easy to create new providers as they just need to do very little work.
|
||||
|
||||
Normally the providers utilize an API of a service, and you need to create a account at the provider and get an API key.
|
||||
Also there are limits on how many requests you can do per day or months, depending on the provider and your contract with them.
|
||||
|
||||
The following providers are currently available and shipped with Part-DB:
|
||||
|
||||
(All trademarks are property of their respective owners. Part-DB is not affiliated with any of the companies.)
|
||||
|
||||
### Ocotpart
|
||||
The Octopart provider uses the [Octopart / Nexar API](https://nexar.com/api) to search for parts and getting informations.
|
||||
To use it you have to create an account at Nexar and create a new application on the [Nexar Portal](https://portal.nexar.com/).
|
||||
The name does not matter, but it is important that the application has access to the "Supply" scope.
|
||||
In the Authorization tab, you will find the client ID and client secret, which you have to enter in the Part-DB env configuration (see below).
|
||||
|
||||
Please note that the Nexar API in the free plan is limited to 1000 results per month.
|
||||
That means if you search for a keyword and results in 10 parts, then 10 will be substracted from your monthly limit. You can see your current usage on the Nexar portal.
|
||||
Part-DB caches the search results internally, so if you have searched for a part before, it will not count against your monthly limit again, when you create it from the search results.
|
||||
|
||||
Following env configuration options are available:
|
||||
|
||||
* `PROVIDER_OCTOPART_CLIENT_ID`: The client ID you got from Nexar (mandatory)
|
||||
* `PROVIDER_OCTOPART_SECRET`: The client secret you got from Nexar (mandatory)
|
||||
* `PROVIDER_OCTOPART_CURRENCY`: The currency you want to get prices in if available (optional, 3 letter ISO-code, default: `EUR`). If an offer is only available in a certain currency,
|
||||
Part-DB will save the prices in their native currency, and you can use Part-DB currency conversion feature to convert it to your preferred currency.
|
||||
* `PROVIDER_OCOTPART_COUNTRY`: The country you want to get prices in if available (optional, 2 letter ISO-code, default: `DE`). To get correct prices, you have to set this and the currency setting to the correct value.
|
||||
* `PROVIDER_OCTOPART_SEARCH_LIMIT`: The maximum number of results to return per search (optional, default: `10`). This affects how quickly your monthly limit is used up.
|
||||
* `PROVIDER_OCTOPART_ONLY_AUTHORIZED_SELLERS`: If set to `true`, only offers from [authorized sellers](https://octopart.com/authorized) will be returned (optional, default: `false`).
|
||||
|
||||
**Attention**: If you change the octopart clientID after you have already used the provider, you have to remove the OAuth token in the Part-DB database. Remove the entry in the table `oauth_tokens` with the name `ip_octopart_oauth`.
|
||||
|
||||
### Digi-Key
|
||||
The Digi-Key provider uses the [Digi-Key API](https://developer.digikey.com/) to search for parts and getting shopping information from [Digi-Key](https://www.digikey.com/).
|
||||
To use it you have to create an account at Digi-Key and get an API key on the [Digi-Key API page](https://developer.digikey.com/).
|
||||
You must create an organization there and create a "Production app". Most settings are not important, you just have to grant access to the "Product Information" API.
|
||||
You will get an Client ID and a Client Secret, which you have to enter in the Part-DB env configuration (see below).
|
||||
|
||||
Following env configuration options are available:
|
||||
* `PROVIDER_DIGIKEY_CLIENT_ID`: The client ID you got from Digi-Key (mandatory)
|
||||
* `PROVIDER_DIGIKEY_SECRET`: The client secret you got from Digi-Key (mandatory)
|
||||
* `PROVIDER_DIGIKEY_CURRENCY`: The currency you want to get prices in (optional, default: `EUR`)
|
||||
* `PROVIDER_DIGIKEY_LANGUAGE`: The language you want to get the descriptions in (optional, default: `en`)
|
||||
* `PROVIDER_DIGIKEY_COUNTRY`: The country you want to get the prices for (optional, default: `DE`)
|
||||
|
||||
The Digi-Key provider needs an additional OAuth connection. To do this, go to the information provider list (`https://your-partdb-instance.tld/tools/info_providers/providers`),
|
||||
go the Digi-Key provider (in the disabled page) and click on the "Connect OAuth" button. You will be redirected to Digi-Key, where you have to login and grant access to the app.
|
||||
To do this your user needs the "Manage OAuth tokens" permission from the "System" section in the "System" tab.
|
||||
The OAuth connection should only be needed once, but if you have any problems with the provider, just click the button again, to establish a new connection.
|
||||
|
||||
### TME
|
||||
The TME provider use the API of [TME](https://www.tme.eu/) to search for parts and getting shopping information from them.
|
||||
To use it you have to create an account at TME and get an API key on the [TME API page](https://developers.tme.eu/en/).
|
||||
You have to generate a new anonymous key there and enter the key and secret in the Part-DB env configuration (see below).
|
||||
|
||||
Following env configuration options are available:
|
||||
* `PROVIDER_TME_KEY`: The API key you got from TME (mandatory)
|
||||
* `PROVIDER_TME_SECRET`: The API secret you got from TME (mandatory)
|
||||
* `PROVIDER_TME_CURRENCY`: The currency you want to get prices in (optional, default: `EUR`)
|
||||
* `PROVIDER_TME_LANGUAGE`: The language you want to get the descriptions in (`en`, `de` and `pl`) (optional, default: `en`)
|
||||
* `PROVIDER_TME_COUNTRY`: The country you want to get the prices for (optional, default: `DE`)
|
||||
* `PROVIDER_TME_GET_GROSS_PRICES`: If this is set to `1` the prices will be gross prices (including tax), otherwise net prices (optional, default: `0`)
|
||||
|
||||
### Farnell / Element14 / Newark
|
||||
The Farnell provider uses the [Farnell API](https://partner.element14.com/) to search for parts and getting shopping information from [Farnell](https://www.farnell.com/).
|
||||
You have to create an account at Farnell and get an API key on the [Farnell API page](https://partner.element14.com/).
|
||||
Register a new application there (settings does not matter, as long as you select the "Product Search API") and you will get an API key.
|
||||
|
||||
Following env configuration options are available:
|
||||
* `PROVIDER_ELEMENT14_KEY`: The API key you got from Farnell (mandatory)
|
||||
* `PROVIDER_ELEMENT14_STORE_ID`: The store ID you want to use. This decides the language of results, currency and country of prices (optional, default: `de.farnell.com`, see [here](https://partner.element14.com/docs/Product_Search_API_REST__Description) for availailable values)
|
||||
|
||||
|
||||
### Custom provider
|
||||
To create a custom provider, you have to create a new class implementing the `InfoProviderInterface` interface. As long as it is a valid Symfony service, it will be automatically loaded and can be used.
|
||||
Besides some metadata functions, you have to implement the `searchByKeyword()` and `getDetails()` functions, which do the actual API requests and return the information to Part-DB.
|
||||
See the existing providers for examples.
|
||||
If you created a new provider, feel free to create a pull request to add it to the Part-DB core.
|
||||
|
||||
## Result caching
|
||||
To reduce the number of API calls against the providers, the results are cached:
|
||||
* The search results (exact search term) are cached for 7 days
|
||||
* The product details are cached for 4 days
|
||||
|
||||
If you need a fresh result, you can clear the cache by running `php .\bin\console cache:pool:clear info_provider.cache` on the command line.
|
||||
The default `php bin/console cache:clear` also clears the result cache, as it clears all caches.
|
||||
@@ -92,4 +92,27 @@ The following variables are in injected into Twig and can be accessed using `{%
|
||||
| `{% raw %}{{ element }}{% endraw %}` | The target element, selected in label dialog |
|
||||
| `{% raw %}{{ user }}{% endraw %}` | The current logged in user. Null if you are not logged in |
|
||||
| `{% raw %}{{ install_title }}{% endraw %}` | The name of the current Part-DB instance (similar to [[INSTALL_NAME]] placeholder). |
|
||||
| `{% raw %}{{ page }}{% endraw %}` | The page number (the nth-element for which the label is generated |
|
||||
| `{% raw %}{{ page }}{% endraw %}` | The page number (the nth-element for which the label is generated |
|
||||
|
||||
|
||||
## Use custom fonts for PDF labels
|
||||
You can use your own fonts for label generation. To do this, put the TTF files of the fonts you want to use into the `assets/fonts/dompdf` folder.
|
||||
The filename will be used as name for the font family and you can use a `_bold` (or `_b`), `_italic` (or `_i`) or `_bold_italic` (or `_bi`) suffix to define
|
||||
different styles of the font. So for example, if you copy the file `myfont.ttf` and `myfont_bold.ttf` into the `assets/fonts/dompdf` folder, you can use the font family `myfont` with regular and bold style.
|
||||
Afterwards regenerate cache with `php bin/console cache:clear`, so the new fonts will be available for label generation.
|
||||
|
||||
The fonts will not be availble from the UI directly, you have to use it in the HTML directly either by defining a `style="font-family: 'myfont';"` attribute on the HTML element or by using a CSS class.
|
||||
You can define the font globally for the label, by adding following statement to the "Additional styles (CSS)" option in the label generator settings:
|
||||
```css
|
||||
* {
|
||||
font-family: 'myfont';
|
||||
}
|
||||
```
|
||||
|
||||
## Non-latin characters in PDF labels
|
||||
The default used font (DejaVu) does not support all characters. Especially characters from non-latin languages like Chinese, Japanese, Korean, Arabic, Hebrew, Cyrillic, etc. are not supported.
|
||||
For this we use [Unifont](http://unifoundry.com/unifont.html) as fallback font. This font supports all (or most) unicode characters, but is not as beautiful as DejaVu.
|
||||
|
||||
If you want to use a different (more beautiful) font, you can use the [custom fonts](#use-custom-fonts-for-pdf-labels) feature.
|
||||
There is the [Noto](https://www.google.com/get/noto/) font family from Google, which supports a lot of languages and is available in different styles (regular, bold, italic, bold-italic).
|
||||
For example you can use [Noto CJK](https://github.com/notofonts/noto-cjk) for more beautful Chinese, Japanese and Korean characters.
|
||||
@@ -72,4 +72,11 @@ See the configuration reference for more information.
|
||||
|
||||
## Personal stocks and stock locations
|
||||
For makerspaces and universities with a lot of users, where each user can have his own stock, which only he should be able to access, you can assign
|
||||
the user as "owner" of a part lot. This way, only him is allowed to add or remove parts from this lot.
|
||||
the user as "owner" of a part lot. This way, only him is allowed to add or remove parts from this lot.
|
||||
|
||||
## Update notfications
|
||||
Part-DB can show you a notification that there is a newer version than currently installed available. The notification will be shown on the homepage and the server info page.
|
||||
It is only be shown to users which has the `Show available Part-DB updates` permission.
|
||||
|
||||
For the notification to work, Part-DB queries the GitHub API every 2 days to check for new releases. No data is sent to GitHub besides the metadata required for the connection (so the public IP address of your computer running Part-DB).
|
||||
If you don't want Part-DB to query the GitHub API, or if your server can not reach the internet, you can disable the update notifications by setting the `CHECK_FOR_UPDATES` option to `false`.
|
||||
@@ -69,6 +69,12 @@ final class Version20190902140506 extends AbstractMultiPlatformMigration
|
||||
//For attachments
|
||||
$this->addSql('DELETE FROM `attachements` WHERE attachements.class_name = "Part" AND (SELECT COUNT(parts.id) FROM parts WHERE parts.id = attachements.element_id) = 0;');
|
||||
|
||||
//Add perms_labels column to groups table if not existing (it was not created in certain legacy versions)
|
||||
//This prevents the migration failing (see https://github.com/Part-DB/Part-DB-server/issues/366 and https://github.com/Part-DB/Part-DB-server/issues/67)
|
||||
if (!$this->doesColumnExist('groups', 'perms_labels')) {
|
||||
$this->addSql('ALTER TABLE `groups` ADD `perms_labels` SMALLINT NOT NULL AFTER `perms_tools`');
|
||||
}
|
||||
|
||||
/**************************************************************************************************************
|
||||
* Doctrine generated SQL
|
||||
**************************************************************************************************************/
|
||||
|
||||
@@ -8,9 +8,6 @@ use App\Migration\AbstractMultiPlatformMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20230417211732 extends AbstractMultiPlatformMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
@@ -41,7 +38,7 @@ final class Version20230417211732 extends AbstractMultiPlatformMigration
|
||||
public function sqLiteUp(Schema $schema): void
|
||||
{
|
||||
//As legacy database can only be migrated to MySQL, we don't need to implement this method.
|
||||
$this->skipIf(true, 'Not needed for SQLite');
|
||||
//Dont skip here, as this causes this migration always to be executed. Do nothing instead.
|
||||
}
|
||||
|
||||
public function sqLiteDown(Schema $schema): void
|
||||
|
||||
65
migrations/Version20230528000149.php
Normal file
65
migrations/Version20230528000149.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use App\Migration\AbstractMultiPlatformMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20230528000149 extends AbstractMultiPlatformMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add other_ui column to webauthn_keys table, needed for future compatibility with more complex webauthn authenticators';
|
||||
}
|
||||
|
||||
public function mySQLUp(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE webauthn_keys ADD other_ui LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:array)\'');
|
||||
}
|
||||
|
||||
public function mySQLDown(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE webauthn_keys DROP other_ui');
|
||||
}
|
||||
|
||||
public function sqLiteUp(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added FROM webauthn_keys');
|
||||
$this->addSql('DROP TABLE webauthn_keys');
|
||||
$this->addSql('CREATE TABLE webauthn_keys (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, public_key_credential_id CLOB NOT NULL --(DC2Type:base64)
|
||||
, type VARCHAR(255) NOT NULL, transports CLOB NOT NULL --(DC2Type:array)
|
||||
, attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL --(DC2Type:trust_path)
|
||||
, aaguid CLOB NOT NULL --(DC2Type:aaguid)
|
||||
, credential_public_key CLOB NOT NULL --(DC2Type:base64)
|
||||
, user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, other_ui CLOB DEFAULT NULL --(DC2Type:array)
|
||||
, CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO webauthn_keys (id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added) SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added FROM __temp__webauthn_keys');
|
||||
$this->addSql('DROP TABLE __temp__webauthn_keys');
|
||||
$this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)');
|
||||
}
|
||||
|
||||
public function sqLiteDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added FROM webauthn_keys');
|
||||
$this->addSql('DROP TABLE webauthn_keys');
|
||||
$this->addSql('CREATE TABLE webauthn_keys (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, public_key_credential_id CLOB NOT NULL --
|
||||
(DC2Type:base64)
|
||||
, type VARCHAR(255) NOT NULL, transports CLOB NOT NULL --
|
||||
(DC2Type:array)
|
||||
, attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL --
|
||||
(DC2Type:trust_path)
|
||||
, aaguid CLOB NOT NULL --
|
||||
(DC2Type:aaguid)
|
||||
, credential_public_key CLOB NOT NULL --
|
||||
(DC2Type:base64)
|
||||
, user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO webauthn_keys (id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added) SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added FROM __temp__webauthn_keys');
|
||||
$this->addSql('DROP TABLE __temp__webauthn_keys');
|
||||
$this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)');
|
||||
}
|
||||
}
|
||||
351
migrations/Version20230716184033.php
Normal file
351
migrations/Version20230716184033.php
Normal file
@@ -0,0 +1,351 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use App\Migration\AbstractMultiPlatformMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
final class Version20230716184033 extends AbstractMultiPlatformMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Create the structure needed for the information provider system';
|
||||
}
|
||||
|
||||
public function mySQLUp(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TABLE oauth_tokens (id INT AUTO_INCREMENT NOT NULL, token VARCHAR(255) DEFAULT NULL, expires_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', refresh_token VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, UNIQUE INDEX oauth_tokens_unique_name (name), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
|
||||
$this->addSql('ALTER TABLE attachment_types ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE categories ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE currencies ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE footprints ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE `groups` ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE manufacturers ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE measurement_units ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE parts ADD provider_reference_provider_key VARCHAR(255) DEFAULT NULL, ADD provider_reference_provider_id VARCHAR(255) DEFAULT NULL, ADD provider_reference_provider_url VARCHAR(255) DEFAULT NULL, ADD provider_reference_last_updated DATETIME DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE projects ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE storelocations ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE suppliers ADD alternative_names LONGTEXT DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function mySQLDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql('DROP TABLE oauth_tokens');
|
||||
$this->addSql('ALTER TABLE `attachment_types` DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `categories` DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE currencies DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `footprints` DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `groups` DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `manufacturers` DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `measurement_units` DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `parts` DROP provider_reference_provider_key, DROP provider_reference_provider_id, DROP provider_reference_provider_url, DROP provider_reference_last_updated');
|
||||
$this->addSql('ALTER TABLE projects DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `storelocations` DROP alternative_names');
|
||||
$this->addSql('ALTER TABLE `suppliers` DROP alternative_names');
|
||||
}
|
||||
|
||||
public function sqLiteUp(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TABLE oauth_tokens (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, token VARCHAR(255) DEFAULT NULL, expires_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable)
|
||||
, refresh_token VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL)');
|
||||
$this->addSql('CREATE UNIQUE INDEX oauth_tokens_unique_name ON oauth_tokens (name)');
|
||||
$this->addSql('ALTER TABLE attachment_types ADD COLUMN alternative_names CLOB DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE categories ADD COLUMN alternative_names CLOB DEFAULT NULL');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__currencies AS SELECT id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added FROM currencies');
|
||||
$this->addSql('DROP TABLE currencies');
|
||||
$this->addSql('CREATE TABLE currencies (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, exchange_rate NUMERIC(11, 5) DEFAULT NULL --(DC2Type:big_decimal)
|
||||
, iso_code VARCHAR(255) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_37C44693727ACA70 FOREIGN KEY (parent_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_37C44693EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO currencies (id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added FROM __temp__currencies');
|
||||
$this->addSql('DROP TABLE __temp__currencies');
|
||||
$this->addSql('CREATE INDEX IDX_37C44693727ACA70 ON currencies (parent_id)');
|
||||
$this->addSql('CREATE INDEX currency_idx_name ON currencies (name)');
|
||||
$this->addSql('CREATE INDEX currency_idx_parent_name ON currencies (parent_id, name)');
|
||||
$this->addSql('CREATE INDEX IDX_37C44693EA7100A1 ON currencies (id_preview_attachment)');
|
||||
$this->addSql('ALTER TABLE footprints ADD COLUMN alternative_names CLOB DEFAULT NULL');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__groups AS SELECT id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data FROM groups');
|
||||
$this->addSql('DROP TABLE groups');
|
||||
$this->addSql('CREATE TABLE groups (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, enforce_2fa BOOLEAN NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB NOT NULL --(DC2Type:json)
|
||||
, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_F06D3970727ACA70 FOREIGN KEY (parent_id) REFERENCES groups (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_F06D3970EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO groups (id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data) SELECT id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data FROM __temp__groups');
|
||||
$this->addSql('DROP TABLE __temp__groups');
|
||||
$this->addSql('CREATE INDEX group_idx_parent_name ON groups (parent_id, name)');
|
||||
$this->addSql('CREATE INDEX group_idx_name ON groups (name)');
|
||||
$this->addSql('CREATE INDEX IDX_F06D3970727ACA70 ON groups (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_F06D3970EA7100A1 ON groups (id_preview_attachment)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__log AS SELECT id, id_user, datetime, level, target_id, target_type, extra, type, username FROM log');
|
||||
$this->addSql('DROP TABLE log');
|
||||
$this->addSql('CREATE TABLE log (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_user INTEGER DEFAULT NULL, datetime DATETIME NOT NULL, level TINYINT NOT NULL --(DC2Type:tinyint)
|
||||
, target_id INTEGER NOT NULL, target_type SMALLINT NOT NULL, extra CLOB NOT NULL --(DC2Type:json)
|
||||
, type SMALLINT NOT NULL, username VARCHAR(255) NOT NULL, CONSTRAINT FK_8F3F68C56B3CA4B FOREIGN KEY (id_user) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO log (id, id_user, datetime, level, target_id, target_type, extra, type, username) SELECT id, id_user, datetime, level, target_id, target_type, extra, type, username FROM __temp__log');
|
||||
$this->addSql('DROP TABLE __temp__log');
|
||||
$this->addSql('CREATE INDEX log_idx_datetime ON log (datetime)');
|
||||
$this->addSql('CREATE INDEX log_idx_type_target ON log (type, target_type, target_id)');
|
||||
$this->addSql('CREATE INDEX log_idx_type ON log (type)');
|
||||
$this->addSql('CREATE INDEX IDX_8F3F68C56B3CA4B ON log (id_user)');
|
||||
$this->addSql('ALTER TABLE manufacturers ADD COLUMN alternative_names CLOB DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE measurement_units ADD COLUMN alternative_names CLOB DEFAULT NULL');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__parts AS SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn FROM parts');
|
||||
$this->addSql('DROP TABLE parts');
|
||||
$this->addSql('CREATE TABLE parts (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_category INTEGER NOT NULL, id_footprint INTEGER DEFAULT NULL, id_part_unit INTEGER DEFAULT NULL, id_manufacturer INTEGER DEFAULT NULL, order_orderdetails_id INTEGER DEFAULT NULL, built_project_id INTEGER DEFAULT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags CLOB NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url VARCHAR(255) NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INTEGER NOT NULL, manual_order BOOLEAN NOT NULL, ipn VARCHAR(100) DEFAULT NULL, provider_reference_provider_key VARCHAR(255) DEFAULT NULL, provider_reference_provider_id VARCHAR(255) DEFAULT NULL, provider_reference_provider_url VARCHAR(255) DEFAULT NULL, provider_reference_last_updated DATETIME DEFAULT NULL, CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES footprints (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES measurement_units (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES manufacturers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES orderdetails (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO parts (id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn) SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn FROM __temp__parts');
|
||||
$this->addSql('DROP TABLE __temp__parts');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON parts (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX parts_idx_ipn ON parts (ipn)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON parts (ipn)');
|
||||
$this->addSql('CREATE INDEX parts_idx_name ON parts (name)');
|
||||
$this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON parts (datetime_added, name, last_modified, id, needs_review)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON parts (id_category)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON parts (id_footprint)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON parts (id_part_unit)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON parts (id_manufacturer)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON parts (order_orderdetails_id)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON parts (built_project_id)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__pricedetails AS SELECT id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added FROM pricedetails');
|
||||
$this->addSql('DROP TABLE pricedetails');
|
||||
$this->addSql('CREATE TABLE pricedetails (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_currency INTEGER DEFAULT NULL, orderdetails_id INTEGER NOT NULL, price NUMERIC(11, 5) NOT NULL --(DC2Type:big_decimal)
|
||||
, price_related_quantity DOUBLE PRECISION NOT NULL, min_discount_quantity DOUBLE PRECISION NOT NULL, manual_input BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_C68C4459398D64AA FOREIGN KEY (id_currency) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_C68C44594A01DDC7 FOREIGN KEY (orderdetails_id) REFERENCES orderdetails (id) ON UPDATE NO ACTION ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO pricedetails (id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added) SELECT id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added FROM __temp__pricedetails');
|
||||
$this->addSql('DROP TABLE __temp__pricedetails');
|
||||
$this->addSql('CREATE INDEX IDX_C68C44594A01DDC7 ON pricedetails (orderdetails_id)');
|
||||
$this->addSql('CREATE INDEX IDX_C68C4459398D64AA ON pricedetails (id_currency)');
|
||||
$this->addSql('CREATE INDEX pricedetails_idx_min_discount ON pricedetails (min_discount_quantity)');
|
||||
$this->addSql('CREATE INDEX pricedetails_idx_min_discount_price_qty ON pricedetails (min_discount_quantity, price_related_quantity)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__project_bom_entries AS SELECT id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added FROM project_bom_entries');
|
||||
$this->addSql('DROP TABLE project_bom_entries');
|
||||
$this->addSql('CREATE TABLE project_bom_entries (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_device INTEGER DEFAULT NULL, id_part INTEGER DEFAULT NULL, price_currency_id INTEGER DEFAULT NULL, quantity DOUBLE PRECISION NOT NULL, mountnames CLOB NOT NULL, name VARCHAR(255) DEFAULT NULL, comment CLOB NOT NULL, price NUMERIC(11, 5) DEFAULT NULL --(DC2Type:big_decimal)
|
||||
, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_AFC547992F180363 FOREIGN KEY (id_device) REFERENCES projects (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AFC54799C22F6CC4 FOREIGN KEY (id_part) REFERENCES parts (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1AA2DD313FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO project_bom_entries (id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added) SELECT id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added FROM __temp__project_bom_entries');
|
||||
$this->addSql('DROP TABLE __temp__project_bom_entries');
|
||||
$this->addSql('CREATE INDEX IDX_1AA2DD31C22F6CC4 ON project_bom_entries (id_part)');
|
||||
$this->addSql('CREATE INDEX IDX_1AA2DD312F180363 ON project_bom_entries (id_device)');
|
||||
$this->addSql('CREATE INDEX IDX_1AA2DD313FFDCD60 ON project_bom_entries (price_currency_id)');
|
||||
$this->addSql('ALTER TABLE projects ADD COLUMN alternative_names CLOB DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE storelocations ADD COLUMN alternative_names CLOB DEFAULT NULL');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__suppliers AS SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added FROM suppliers');
|
||||
$this->addSql('DROP TABLE suppliers');
|
||||
$this->addSql('CREATE TABLE suppliers (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, default_currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, shipping_costs NUMERIC(11, 5) DEFAULT NULL --(DC2Type:big_decimal)
|
||||
, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, alternative_names CLOB DEFAULT NULL, CONSTRAINT FK_AC28B95C727ACA70 FOREIGN KEY (parent_id) REFERENCES suppliers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CECD792C0 FOREIGN KEY (default_currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO suppliers (id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added FROM __temp__suppliers');
|
||||
$this->addSql('DROP TABLE __temp__suppliers');
|
||||
$this->addSql('CREATE INDEX IDX_AC28B95CECD792C0 ON suppliers (default_currency_id)');
|
||||
$this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON suppliers (parent_id)');
|
||||
$this->addSql('CREATE INDEX supplier_idx_name ON suppliers (name)');
|
||||
$this->addSql('CREATE INDEX supplier_idx_parent_name ON suppliers (parent_id, name)');
|
||||
$this->addSql('CREATE INDEX IDX_AC28B95CEA7100A1 ON suppliers (id_preview_attachment)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__users AS SELECT id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added, permissions_data, saml_user, about_me, show_email_on_profile FROM users');
|
||||
$this->addSql('DROP TABLE users');
|
||||
$this->addSql('CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, group_id INTEGER DEFAULT NULL, currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, disabled BOOLEAN NOT NULL, config_theme VARCHAR(255) DEFAULT NULL, pw_reset_token VARCHAR(255) DEFAULT NULL, config_instock_comment_a CLOB NOT NULL, config_instock_comment_w CLOB NOT NULL, trusted_device_cookie_version INTEGER NOT NULL, backup_codes CLOB NOT NULL --(DC2Type:json)
|
||||
, google_authenticator_secret VARCHAR(255) DEFAULT NULL, config_timezone VARCHAR(255) DEFAULT NULL, config_language VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, department VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, first_name VARCHAR(255) DEFAULT NULL, need_pw_change BOOLEAN NOT NULL, password VARCHAR(255) DEFAULT NULL, name VARCHAR(180) NOT NULL, settings CLOB NOT NULL --(DC2Type:json)
|
||||
, backup_codes_generation_date DATETIME DEFAULT NULL, pw_reset_expires DATETIME DEFAULT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB NOT NULL --(DC2Type:json)
|
||||
, saml_user BOOLEAN NOT NULL, about_me CLOB NOT NULL, show_email_on_profile BOOLEAN DEFAULT 0 NOT NULL, CONSTRAINT FK_1483A5E9FE54D947 FOREIGN KEY (group_id) REFERENCES groups (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E938248176 FOREIGN KEY (currency_id) REFERENCES currencies (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E9EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO users (id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added, permissions_data, saml_user, about_me, show_email_on_profile) SELECT id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, last_modified, datetime_added, permissions_data, saml_user, about_me, show_email_on_profile FROM __temp__users');
|
||||
$this->addSql('DROP TABLE __temp__users');
|
||||
$this->addSql('CREATE INDEX user_idx_username ON users (name)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E95E237E06 ON users (name)');
|
||||
$this->addSql('CREATE INDEX IDX_1483A5E9FE54D947 ON users (group_id)');
|
||||
$this->addSql('CREATE INDEX IDX_1483A5E938248176 ON users (currency_id)');
|
||||
$this->addSql('CREATE INDEX IDX_1483A5E9EA7100A1 ON users (id_preview_attachment)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui FROM webauthn_keys');
|
||||
$this->addSql('DROP TABLE webauthn_keys');
|
||||
$this->addSql('CREATE TABLE webauthn_keys (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, public_key_credential_id CLOB NOT NULL --(DC2Type:base64)
|
||||
, type VARCHAR(255) NOT NULL, transports CLOB NOT NULL --(DC2Type:array)
|
||||
, attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL --(DC2Type:trust_path)
|
||||
, aaguid CLOB NOT NULL --(DC2Type:aaguid)
|
||||
, credential_public_key CLOB NOT NULL --(DC2Type:base64)
|
||||
, user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, other_ui CLOB DEFAULT NULL --(DC2Type:array)
|
||||
, CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO webauthn_keys (id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui) SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, name, last_modified, datetime_added, other_ui FROM __temp__webauthn_keys');
|
||||
$this->addSql('DROP TABLE __temp__webauthn_keys');
|
||||
$this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)');
|
||||
}
|
||||
|
||||
public function sqLiteDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql('DROP TABLE oauth_tokens');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__attachment_types AS SELECT id, parent_id, id_preview_attachment, filetype_filter, comment, not_selectable, name, last_modified, datetime_added FROM "attachment_types"');
|
||||
$this->addSql('DROP TABLE "attachment_types"');
|
||||
$this->addSql('CREATE TABLE "attachment_types" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, filetype_filter CLOB NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_EFAED719727ACA70 FOREIGN KEY (parent_id) REFERENCES "attachment_types" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_EFAED719EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "attachment_types" (id, parent_id, id_preview_attachment, filetype_filter, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachment, filetype_filter, comment, not_selectable, name, last_modified, datetime_added FROM __temp__attachment_types');
|
||||
$this->addSql('DROP TABLE __temp__attachment_types');
|
||||
$this->addSql('CREATE INDEX IDX_EFAED719727ACA70 ON "attachment_types" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_EFAED719EA7100A1 ON "attachment_types" (id_preview_attachment)');
|
||||
$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)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__categories AS SELECT id, parent_id, id_preview_attachment, partname_hint, partname_regex, disable_footprints, disable_manufacturers, disable_autodatasheets, disable_properties, default_description, default_comment, comment, not_selectable, name, last_modified, datetime_added FROM "categories"');
|
||||
$this->addSql('DROP TABLE "categories"');
|
||||
$this->addSql('CREATE TABLE "categories" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, partname_hint CLOB NOT NULL, partname_regex CLOB NOT NULL, disable_footprints BOOLEAN NOT NULL, disable_manufacturers BOOLEAN NOT NULL, disable_autodatasheets BOOLEAN NOT NULL, disable_properties BOOLEAN NOT NULL, default_description CLOB NOT NULL, default_comment CLOB NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_3AF34668727ACA70 FOREIGN KEY (parent_id) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_3AF34668EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "categories" (id, parent_id, id_preview_attachment, partname_hint, partname_regex, disable_footprints, disable_manufacturers, disable_autodatasheets, disable_properties, default_description, default_comment, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachment, partname_hint, partname_regex, disable_footprints, disable_manufacturers, disable_autodatasheets, disable_properties, default_description, default_comment, comment, not_selectable, name, last_modified, datetime_added FROM __temp__categories');
|
||||
$this->addSql('DROP TABLE __temp__categories');
|
||||
$this->addSql('CREATE INDEX IDX_3AF34668727ACA70 ON "categories" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_3AF34668EA7100A1 ON "categories" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX category_idx_name ON "categories" (name)');
|
||||
$this->addSql('CREATE INDEX category_idx_parent_name ON "categories" (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__currencies AS SELECT id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added FROM currencies');
|
||||
$this->addSql('DROP TABLE currencies');
|
||||
$this->addSql('CREATE TABLE currencies (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, exchange_rate NUMERIC(11, 5) DEFAULT NULL --
|
||||
(DC2Type:big_decimal)
|
||||
, iso_code VARCHAR(255) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_37C44693727ACA70 FOREIGN KEY (parent_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_37C44693EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO currencies (id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachment, exchange_rate, iso_code, comment, not_selectable, name, last_modified, datetime_added FROM __temp__currencies');
|
||||
$this->addSql('DROP TABLE __temp__currencies');
|
||||
$this->addSql('CREATE INDEX IDX_37C44693727ACA70 ON currencies (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_37C44693EA7100A1 ON currencies (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX currency_idx_name ON currencies (name)');
|
||||
$this->addSql('CREATE INDEX currency_idx_parent_name ON currencies (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__footprints AS SELECT id, parent_id, id_footprint_3d, id_preview_attachment, comment, not_selectable, name, last_modified, datetime_added FROM "footprints"');
|
||||
$this->addSql('DROP TABLE "footprints"');
|
||||
$this->addSql('CREATE TABLE "footprints" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_footprint_3d INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_A34D68A2727ACA70 FOREIGN KEY (parent_id) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_A34D68A232A38C34 FOREIGN KEY (id_footprint_3d) REFERENCES "attachments" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_A34D68A2EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "footprints" (id, parent_id, id_footprint_3d, id_preview_attachment, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_footprint_3d, id_preview_attachment, comment, not_selectable, name, last_modified, datetime_added FROM __temp__footprints');
|
||||
$this->addSql('DROP TABLE __temp__footprints');
|
||||
$this->addSql('CREATE INDEX IDX_A34D68A2727ACA70 ON "footprints" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_A34D68A232A38C34 ON "footprints" (id_footprint_3d)');
|
||||
$this->addSql('CREATE INDEX IDX_A34D68A2EA7100A1 ON "footprints" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX footprint_idx_name ON "footprints" (name)');
|
||||
$this->addSql('CREATE INDEX footprint_idx_parent_name ON "footprints" (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__groups AS SELECT id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data FROM "groups"');
|
||||
$this->addSql('DROP TABLE "groups"');
|
||||
$this->addSql('CREATE TABLE "groups" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, enforce_2fa BOOLEAN NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB NOT NULL --
|
||||
(DC2Type:json)
|
||||
, CONSTRAINT FK_F06D3970727ACA70 FOREIGN KEY (parent_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_F06D3970EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "groups" (id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data) SELECT id, parent_id, id_preview_attachment, enforce_2fa, comment, not_selectable, name, last_modified, datetime_added, permissions_data FROM __temp__groups');
|
||||
$this->addSql('DROP TABLE __temp__groups');
|
||||
$this->addSql('CREATE INDEX IDX_F06D3970727ACA70 ON "groups" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_F06D3970EA7100A1 ON "groups" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX group_idx_name ON "groups" (name)');
|
||||
$this->addSql('CREATE INDEX group_idx_parent_name ON "groups" (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__log AS SELECT id, id_user, username, datetime, level, target_id, target_type, extra, type FROM log');
|
||||
$this->addSql('DROP TABLE log');
|
||||
$this->addSql('CREATE TABLE log (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_user INTEGER DEFAULT NULL, username VARCHAR(255) NOT NULL, datetime DATETIME NOT NULL, level TINYINT NOT NULL --
|
||||
(DC2Type:tinyint)
|
||||
, target_id INTEGER NOT NULL, target_type SMALLINT NOT NULL, extra CLOB NOT NULL --
|
||||
(DC2Type:json)
|
||||
, type SMALLINT NOT NULL, CONSTRAINT FK_8F3F68C56B3CA4B FOREIGN KEY (id_user) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO log (id, id_user, username, datetime, level, target_id, target_type, extra, type) SELECT id, id_user, username, datetime, level, target_id, target_type, extra, type FROM __temp__log');
|
||||
$this->addSql('DROP TABLE __temp__log');
|
||||
$this->addSql('CREATE INDEX IDX_8F3F68C56B3CA4B ON log (id_user)');
|
||||
$this->addSql('CREATE INDEX log_idx_type ON log (type)');
|
||||
$this->addSql('CREATE INDEX log_idx_type_target ON log (type, target_type, target_id)');
|
||||
$this->addSql('CREATE INDEX log_idx_datetime ON log (datetime)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__manufacturers AS SELECT id, parent_id, id_preview_attachment, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added FROM "manufacturers"');
|
||||
$this->addSql('DROP TABLE "manufacturers"');
|
||||
$this->addSql('CREATE TABLE "manufacturers" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_94565B12727ACA70 FOREIGN KEY (parent_id) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_94565B12EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "manufacturers" (id, parent_id, id_preview_attachment, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachment, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added FROM __temp__manufacturers');
|
||||
$this->addSql('DROP TABLE __temp__manufacturers');
|
||||
$this->addSql('CREATE INDEX IDX_94565B12727ACA70 ON "manufacturers" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_94565B12EA7100A1 ON "manufacturers" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX manufacturer_name ON "manufacturers" (name)');
|
||||
$this->addSql('CREATE INDEX manufacturer_idx_parent_name ON "manufacturers" (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__measurement_units AS SELECT id, parent_id, id_preview_attachment, unit, is_integer, use_si_prefix, comment, not_selectable, name, last_modified, datetime_added FROM "measurement_units"');
|
||||
$this->addSql('DROP TABLE "measurement_units"');
|
||||
$this->addSql('CREATE TABLE "measurement_units" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, unit VARCHAR(255) DEFAULT NULL, is_integer BOOLEAN NOT NULL, use_si_prefix BOOLEAN NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_F5AF83CF727ACA70 FOREIGN KEY (parent_id) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_F5AF83CFEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "measurement_units" (id, parent_id, id_preview_attachment, unit, is_integer, use_si_prefix, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachment, unit, is_integer, use_si_prefix, comment, not_selectable, name, last_modified, datetime_added FROM __temp__measurement_units');
|
||||
$this->addSql('DROP TABLE __temp__measurement_units');
|
||||
$this->addSql('CREATE INDEX IDX_F5AF83CF727ACA70 ON "measurement_units" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_F5AF83CFEA7100A1 ON "measurement_units" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX unit_idx_name ON "measurement_units" (name)');
|
||||
$this->addSql('CREATE INDEX unit_idx_parent_name ON "measurement_units" (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__parts AS SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order FROM "parts"');
|
||||
$this->addSql('DROP TABLE "parts"');
|
||||
$this->addSql('CREATE TABLE "parts" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_category INTEGER NOT NULL, id_footprint INTEGER DEFAULT NULL, id_part_unit INTEGER DEFAULT NULL, id_manufacturer INTEGER DEFAULT NULL, order_orderdetails_id INTEGER DEFAULT NULL, built_project_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags CLOB NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, ipn VARCHAR(100) DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url VARCHAR(255) NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INTEGER NOT NULL, manual_order BOOLEAN NOT NULL, CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES "orderdetails" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "parts" (id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order) SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order FROM __temp__parts');
|
||||
$this->addSql('DROP TABLE __temp__parts');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON "parts" (ipn)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON "parts" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON "parts" (id_category)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON "parts" (id_footprint)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON "parts" (id_part_unit)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON "parts" (id_manufacturer)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON "parts" (order_orderdetails_id)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON "parts" (built_project_id)');
|
||||
$this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON "parts" (datetime_added, name, last_modified, id, needs_review)');
|
||||
$this->addSql('CREATE INDEX parts_idx_name ON "parts" (name)');
|
||||
$this->addSql('CREATE INDEX parts_idx_ipn ON "parts" (ipn)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__pricedetails AS SELECT id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added FROM "pricedetails"');
|
||||
$this->addSql('DROP TABLE "pricedetails"');
|
||||
$this->addSql('CREATE TABLE "pricedetails" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_currency INTEGER DEFAULT NULL, orderdetails_id INTEGER NOT NULL, price NUMERIC(11, 5) NOT NULL --
|
||||
(DC2Type:big_decimal)
|
||||
, price_related_quantity DOUBLE PRECISION NOT NULL, min_discount_quantity DOUBLE PRECISION NOT NULL, manual_input BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_C68C4459398D64AA FOREIGN KEY (id_currency) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_C68C44594A01DDC7 FOREIGN KEY (orderdetails_id) REFERENCES "orderdetails" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "pricedetails" (id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added) SELECT id, id_currency, orderdetails_id, price, price_related_quantity, min_discount_quantity, manual_input, last_modified, datetime_added FROM __temp__pricedetails');
|
||||
$this->addSql('DROP TABLE __temp__pricedetails');
|
||||
$this->addSql('CREATE INDEX IDX_C68C4459398D64AA ON "pricedetails" (id_currency)');
|
||||
$this->addSql('CREATE INDEX IDX_C68C44594A01DDC7 ON "pricedetails" (orderdetails_id)');
|
||||
$this->addSql('CREATE INDEX pricedetails_idx_min_discount ON "pricedetails" (min_discount_quantity)');
|
||||
$this->addSql('CREATE INDEX pricedetails_idx_min_discount_price_qty ON "pricedetails" (min_discount_quantity, price_related_quantity)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__project_bom_entries AS SELECT id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added FROM project_bom_entries');
|
||||
$this->addSql('DROP TABLE project_bom_entries');
|
||||
$this->addSql('CREATE TABLE project_bom_entries (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_device INTEGER DEFAULT NULL, id_part INTEGER DEFAULT NULL, price_currency_id INTEGER DEFAULT NULL, quantity DOUBLE PRECISION NOT NULL, mountnames CLOB NOT NULL, name VARCHAR(255) DEFAULT NULL, comment CLOB NOT NULL, price NUMERIC(11, 5) DEFAULT NULL --
|
||||
(DC2Type:big_decimal)
|
||||
, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_1AA2DD312F180363 FOREIGN KEY (id_device) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1AA2DD31C22F6CC4 FOREIGN KEY (id_part) REFERENCES "parts" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1AA2DD313FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO project_bom_entries (id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added) SELECT id, id_device, id_part, price_currency_id, quantity, mountnames, name, comment, price, last_modified, datetime_added FROM __temp__project_bom_entries');
|
||||
$this->addSql('DROP TABLE __temp__project_bom_entries');
|
||||
$this->addSql('CREATE INDEX IDX_1AA2DD312F180363 ON project_bom_entries (id_device)');
|
||||
$this->addSql('CREATE INDEX IDX_1AA2DD31C22F6CC4 ON project_bom_entries (id_part)');
|
||||
$this->addSql('CREATE INDEX IDX_1AA2DD313FFDCD60 ON project_bom_entries (price_currency_id)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__projects AS SELECT id, parent_id, id_preview_attachment, order_quantity, status, order_only_missing_parts, description, comment, not_selectable, name, last_modified, datetime_added FROM projects');
|
||||
$this->addSql('DROP TABLE projects');
|
||||
$this->addSql('CREATE TABLE projects (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, order_quantity INTEGER NOT NULL, status VARCHAR(64) DEFAULT NULL, order_only_missing_parts BOOLEAN NOT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_5C93B3A4727ACA70 FOREIGN KEY (parent_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_5C93B3A4EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO projects (id, parent_id, id_preview_attachment, order_quantity, status, order_only_missing_parts, description, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, id_preview_attachment, order_quantity, status, order_only_missing_parts, description, comment, not_selectable, name, last_modified, datetime_added FROM __temp__projects');
|
||||
$this->addSql('DROP TABLE __temp__projects');
|
||||
$this->addSql('CREATE INDEX IDX_5C93B3A4727ACA70 ON projects (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_5C93B3A4EA7100A1 ON projects (id_preview_attachment)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__storelocations AS SELECT id, parent_id, storage_type_id, id_owner, id_preview_attachment, is_full, only_single_part, limit_to_existing_parts, part_owner_must_match, comment, not_selectable, name, last_modified, datetime_added FROM "storelocations"');
|
||||
$this->addSql('DROP TABLE "storelocations"');
|
||||
$this->addSql('CREATE TABLE "storelocations" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, storage_type_id INTEGER DEFAULT NULL, id_owner INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, is_full BOOLEAN NOT NULL, only_single_part BOOLEAN NOT NULL, limit_to_existing_parts BOOLEAN NOT NULL, part_owner_must_match BOOLEAN DEFAULT 0 NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_7517020727ACA70 FOREIGN KEY (parent_id) REFERENCES "storelocations" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_7517020B270BFF1 FOREIGN KEY (storage_type_id) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_751702021E5A74C FOREIGN KEY (id_owner) REFERENCES "users" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_7517020EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "storelocations" (id, parent_id, storage_type_id, id_owner, id_preview_attachment, is_full, only_single_part, limit_to_existing_parts, part_owner_must_match, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, storage_type_id, id_owner, id_preview_attachment, is_full, only_single_part, limit_to_existing_parts, part_owner_must_match, comment, not_selectable, name, last_modified, datetime_added FROM __temp__storelocations');
|
||||
$this->addSql('DROP TABLE __temp__storelocations');
|
||||
$this->addSql('CREATE INDEX IDX_7517020727ACA70 ON "storelocations" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_7517020B270BFF1 ON "storelocations" (storage_type_id)');
|
||||
$this->addSql('CREATE INDEX IDX_751702021E5A74C ON "storelocations" (id_owner)');
|
||||
$this->addSql('CREATE INDEX IDX_7517020EA7100A1 ON "storelocations" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX location_idx_name ON "storelocations" (name)');
|
||||
$this->addSql('CREATE INDEX location_idx_parent_name ON "storelocations" (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__suppliers AS SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added FROM "suppliers"');
|
||||
$this->addSql('DROP TABLE "suppliers"');
|
||||
$this->addSql('CREATE TABLE "suppliers" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_id INTEGER DEFAULT NULL, default_currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, shipping_costs NUMERIC(11, 5) DEFAULT NULL --
|
||||
(DC2Type:big_decimal)
|
||||
, address VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, fax_number VARCHAR(255) NOT NULL, email_address VARCHAR(255) NOT NULL, website VARCHAR(255) NOT NULL, auto_product_url VARCHAR(255) NOT NULL, comment CLOB NOT NULL, not_selectable BOOLEAN NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_AC28B95C727ACA70 FOREIGN KEY (parent_id) REFERENCES "suppliers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CECD792C0 FOREIGN KEY (default_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_AC28B95CEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "suppliers" (id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added) SELECT id, parent_id, default_currency_id, id_preview_attachment, shipping_costs, address, phone_number, fax_number, email_address, website, auto_product_url, comment, not_selectable, name, last_modified, datetime_added FROM __temp__suppliers');
|
||||
$this->addSql('DROP TABLE __temp__suppliers');
|
||||
$this->addSql('CREATE INDEX IDX_AC28B95C727ACA70 ON "suppliers" (parent_id)');
|
||||
$this->addSql('CREATE INDEX IDX_AC28B95CECD792C0 ON "suppliers" (default_currency_id)');
|
||||
$this->addSql('CREATE INDEX IDX_AC28B95CEA7100A1 ON "suppliers" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX supplier_idx_name ON "suppliers" (name)');
|
||||
$this->addSql('CREATE INDEX supplier_idx_parent_name ON "suppliers" (parent_id, name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__users AS SELECT id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, about_me, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, show_email_on_profile, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, saml_user, last_modified, datetime_added, permissions_data FROM "users"');
|
||||
$this->addSql('DROP TABLE "users"');
|
||||
$this->addSql('CREATE TABLE "users" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, group_id INTEGER DEFAULT NULL, currency_id INTEGER DEFAULT NULL, id_preview_attachment INTEGER DEFAULT NULL, disabled BOOLEAN NOT NULL, config_theme VARCHAR(255) DEFAULT NULL, pw_reset_token VARCHAR(255) DEFAULT NULL, config_instock_comment_a CLOB NOT NULL, config_instock_comment_w CLOB NOT NULL, about_me CLOB NOT NULL, trusted_device_cookie_version INTEGER NOT NULL, backup_codes CLOB NOT NULL --
|
||||
(DC2Type:json)
|
||||
, google_authenticator_secret VARCHAR(255) DEFAULT NULL, config_timezone VARCHAR(255) DEFAULT NULL, config_language VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, show_email_on_profile BOOLEAN DEFAULT 0 NOT NULL, department VARCHAR(255) DEFAULT NULL, last_name VARCHAR(255) DEFAULT NULL, first_name VARCHAR(255) DEFAULT NULL, need_pw_change BOOLEAN NOT NULL, password VARCHAR(255) DEFAULT NULL, name VARCHAR(180) NOT NULL, settings CLOB NOT NULL --
|
||||
(DC2Type:json)
|
||||
, backup_codes_generation_date DATETIME DEFAULT NULL, pw_reset_expires DATETIME DEFAULT NULL, saml_user BOOLEAN NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, permissions_data CLOB NOT NULL --
|
||||
(DC2Type:json)
|
||||
, CONSTRAINT FK_1483A5E9FE54D947 FOREIGN KEY (group_id) REFERENCES "groups" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E938248176 FOREIGN KEY (currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_1483A5E9EA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "users" (id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, about_me, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, show_email_on_profile, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, saml_user, last_modified, datetime_added, permissions_data) SELECT id, group_id, currency_id, id_preview_attachment, disabled, config_theme, pw_reset_token, config_instock_comment_a, config_instock_comment_w, about_me, trusted_device_cookie_version, backup_codes, google_authenticator_secret, config_timezone, config_language, email, show_email_on_profile, department, last_name, first_name, need_pw_change, password, name, settings, backup_codes_generation_date, pw_reset_expires, saml_user, last_modified, datetime_added, permissions_data FROM __temp__users');
|
||||
$this->addSql('DROP TABLE __temp__users');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E95E237E06 ON "users" (name)');
|
||||
$this->addSql('CREATE INDEX IDX_1483A5E9FE54D947 ON "users" (group_id)');
|
||||
$this->addSql('CREATE INDEX IDX_1483A5E938248176 ON "users" (currency_id)');
|
||||
$this->addSql('CREATE INDEX IDX_1483A5E9EA7100A1 ON "users" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX user_idx_username ON "users" (name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__webauthn_keys AS SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, name, last_modified, datetime_added FROM webauthn_keys');
|
||||
$this->addSql('DROP TABLE webauthn_keys');
|
||||
$this->addSql('CREATE TABLE webauthn_keys (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, user_id INTEGER DEFAULT NULL, public_key_credential_id CLOB NOT NULL --
|
||||
(DC2Type:base64)
|
||||
, type VARCHAR(255) NOT NULL, transports CLOB NOT NULL --
|
||||
(DC2Type:array)
|
||||
, attestation_type VARCHAR(255) NOT NULL, trust_path CLOB NOT NULL --
|
||||
(DC2Type:trust_path)
|
||||
, aaguid CLOB NOT NULL --
|
||||
(DC2Type:aaguid)
|
||||
, credential_public_key CLOB NOT NULL --
|
||||
(DC2Type:base64)
|
||||
, user_handle VARCHAR(255) NOT NULL, counter INTEGER NOT NULL, other_ui CLOB DEFAULT NULL --
|
||||
(DC2Type:array)
|
||||
, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_799FD143A76ED395 FOREIGN KEY (user_id) REFERENCES "users" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO webauthn_keys (id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, name, last_modified, datetime_added) SELECT id, user_id, public_key_credential_id, type, transports, attestation_type, trust_path, aaguid, credential_public_key, user_handle, counter, other_ui, name, last_modified, datetime_added FROM __temp__webauthn_keys');
|
||||
$this->addSql('DROP TABLE __temp__webauthn_keys');
|
||||
$this->addSql('CREATE INDEX IDX_799FD143A76ED395 ON webauthn_keys (user_id)');
|
||||
}
|
||||
}
|
||||
102
migrations/Version20230730131708.php
Normal file
102
migrations/Version20230730131708.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use App\Migration\AbstractMultiPlatformMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
final class Version20230730131708 extends AbstractMultiPlatformMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Allow longer fields for manufacturer and supplier product urls, allow client credentials grant to have null refresh token';
|
||||
}
|
||||
|
||||
public function mySQLUp(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE oauth_tokens CHANGE token token LONGTEXT DEFAULT NULL, CHANGE refresh_token refresh_token LONGTEXT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE orderdetails CHANGE supplier_product_url supplier_product_url LONGTEXT NOT NULL');
|
||||
$this->addSql('ALTER TABLE parts CHANGE manufacturer_product_url manufacturer_product_url LONGTEXT NOT NULL');
|
||||
}
|
||||
|
||||
public function mySQLDown(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE oauth_tokens CHANGE token token VARCHAR(255) DEFAULT NULL, CHANGE refresh_token refresh_token VARCHAR(255) NOT NULL');
|
||||
$this->addSql('ALTER TABLE `orderdetails` CHANGE supplier_product_url supplier_product_url VARCHAR(255) NOT NULL');
|
||||
$this->addSql('ALTER TABLE `parts` CHANGE manufacturer_product_url manufacturer_product_url VARCHAR(255) NOT NULL');
|
||||
}
|
||||
|
||||
public function sqLiteUp(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__oauth_tokens AS SELECT id, token, expires_at, refresh_token, name, last_modified, datetime_added FROM oauth_tokens');
|
||||
$this->addSql('DROP TABLE oauth_tokens');
|
||||
$this->addSql('CREATE TABLE oauth_tokens (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, token CLOB DEFAULT NULL, expires_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable)
|
||||
, refresh_token CLOB DEFAULT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL)');
|
||||
$this->addSql('INSERT INTO oauth_tokens (id, token, expires_at, refresh_token, name, last_modified, datetime_added) SELECT id, token, expires_at, refresh_token, name, last_modified, datetime_added FROM __temp__oauth_tokens');
|
||||
$this->addSql('DROP TABLE __temp__oauth_tokens');
|
||||
$this->addSql('CREATE UNIQUE INDEX oauth_tokens_unique_name ON oauth_tokens (name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__orderdetails AS SELECT id, part_id, id_supplier, supplierpartnr, obsolete, supplier_product_url, last_modified, datetime_added FROM orderdetails');
|
||||
$this->addSql('DROP TABLE orderdetails');
|
||||
$this->addSql('CREATE TABLE orderdetails (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, part_id INTEGER NOT NULL, id_supplier INTEGER DEFAULT NULL, supplierpartnr VARCHAR(255) NOT NULL, obsolete BOOLEAN NOT NULL, supplier_product_url CLOB NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_489AFCDC4CE34BEC FOREIGN KEY (part_id) REFERENCES parts (id) ON UPDATE NO ACTION ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_489AFCDCCBF180EB FOREIGN KEY (id_supplier) REFERENCES suppliers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO orderdetails (id, part_id, id_supplier, supplierpartnr, obsolete, supplier_product_url, last_modified, datetime_added) SELECT id, part_id, id_supplier, supplierpartnr, obsolete, supplier_product_url, last_modified, datetime_added FROM __temp__orderdetails');
|
||||
$this->addSql('DROP TABLE __temp__orderdetails');
|
||||
$this->addSql('CREATE INDEX orderdetails_supplier_part_nr ON orderdetails (supplierpartnr)');
|
||||
$this->addSql('CREATE INDEX IDX_489AFCDC4CE34BEC ON orderdetails (part_id)');
|
||||
$this->addSql('CREATE INDEX IDX_489AFCDCCBF180EB ON orderdetails (id_supplier)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__parts AS SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated FROM parts');
|
||||
$this->addSql('DROP TABLE parts');
|
||||
$this->addSql('CREATE TABLE parts (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_category INTEGER NOT NULL, id_footprint INTEGER DEFAULT NULL, id_part_unit INTEGER DEFAULT NULL, id_manufacturer INTEGER DEFAULT NULL, order_orderdetails_id INTEGER DEFAULT NULL, built_project_id INTEGER DEFAULT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags CLOB NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url CLOB NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INTEGER NOT NULL, manual_order BOOLEAN NOT NULL, ipn VARCHAR(100) DEFAULT NULL, provider_reference_provider_key VARCHAR(255) DEFAULT NULL, provider_reference_provider_id VARCHAR(255) DEFAULT NULL, provider_reference_provider_url VARCHAR(255) DEFAULT NULL, provider_reference_last_updated DATETIME DEFAULT NULL, CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES categories (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES footprints (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES measurement_units (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES manufacturers (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES orderdetails (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES attachments (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO parts (id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated) SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, datetime_added, name, last_modified, needs_review, tags, mass, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, ipn, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated FROM __temp__parts');
|
||||
$this->addSql('DROP TABLE __temp__parts');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON parts (built_project_id)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON parts (order_orderdetails_id)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON parts (id_manufacturer)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON parts (id_part_unit)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON parts (id_footprint)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON parts (id_category)');
|
||||
$this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON parts (datetime_added, name, last_modified, id, needs_review)');
|
||||
$this->addSql('CREATE INDEX parts_idx_name ON parts (name)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON parts (ipn)');
|
||||
$this->addSql('CREATE INDEX parts_idx_ipn ON parts (ipn)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON parts (id_preview_attachment)');
|
||||
}
|
||||
|
||||
public function sqLiteDown(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__oauth_tokens AS SELECT id, token, expires_at, refresh_token, name, last_modified, datetime_added FROM oauth_tokens');
|
||||
$this->addSql('DROP TABLE oauth_tokens');
|
||||
$this->addSql('CREATE TABLE oauth_tokens (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, token VARCHAR(255) DEFAULT NULL, expires_at DATETIME DEFAULT NULL --(DC2Type:datetime_immutable)
|
||||
, refresh_token VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL)');
|
||||
$this->addSql('INSERT INTO oauth_tokens (id, token, expires_at, refresh_token, name, last_modified, datetime_added) SELECT id, token, expires_at, refresh_token, name, last_modified, datetime_added FROM __temp__oauth_tokens');
|
||||
$this->addSql('DROP TABLE __temp__oauth_tokens');
|
||||
$this->addSql('CREATE UNIQUE INDEX oauth_tokens_unique_name ON oauth_tokens (name)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__orderdetails AS SELECT id, part_id, id_supplier, supplierpartnr, obsolete, supplier_product_url, last_modified, datetime_added FROM "orderdetails"');
|
||||
$this->addSql('DROP TABLE "orderdetails"');
|
||||
$this->addSql('CREATE TABLE "orderdetails" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, part_id INTEGER NOT NULL, id_supplier INTEGER DEFAULT NULL, supplierpartnr VARCHAR(255) NOT NULL, obsolete BOOLEAN NOT NULL, supplier_product_url VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CONSTRAINT FK_489AFCDC4CE34BEC FOREIGN KEY (part_id) REFERENCES "parts" (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_489AFCDCCBF180EB FOREIGN KEY (id_supplier) REFERENCES "suppliers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "orderdetails" (id, part_id, id_supplier, supplierpartnr, obsolete, supplier_product_url, last_modified, datetime_added) SELECT id, part_id, id_supplier, supplierpartnr, obsolete, supplier_product_url, last_modified, datetime_added FROM __temp__orderdetails');
|
||||
$this->addSql('DROP TABLE __temp__orderdetails');
|
||||
$this->addSql('CREATE INDEX IDX_489AFCDC4CE34BEC ON "orderdetails" (part_id)');
|
||||
$this->addSql('CREATE INDEX IDX_489AFCDCCBF180EB ON "orderdetails" (id_supplier)');
|
||||
$this->addSql('CREATE INDEX orderdetails_supplier_part_nr ON "orderdetails" (supplierpartnr)');
|
||||
$this->addSql('CREATE TEMPORARY TABLE __temp__parts AS SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated FROM "parts"');
|
||||
$this->addSql('DROP TABLE "parts"');
|
||||
$this->addSql('CREATE TABLE "parts" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, id_preview_attachment INTEGER DEFAULT NULL, id_category INTEGER NOT NULL, id_footprint INTEGER DEFAULT NULL, id_part_unit INTEGER DEFAULT NULL, id_manufacturer INTEGER DEFAULT NULL, order_orderdetails_id INTEGER DEFAULT NULL, built_project_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, needs_review BOOLEAN NOT NULL, tags CLOB NOT NULL, mass DOUBLE PRECISION DEFAULT NULL, ipn VARCHAR(100) DEFAULT NULL, description CLOB NOT NULL, comment CLOB NOT NULL, visible BOOLEAN NOT NULL, favorite BOOLEAN NOT NULL, minamount DOUBLE PRECISION NOT NULL, manufacturer_product_url VARCHAR(255) NOT NULL, manufacturer_product_number VARCHAR(255) NOT NULL, manufacturing_status VARCHAR(255) DEFAULT NULL, order_quantity INTEGER NOT NULL, manual_order BOOLEAN NOT NULL, provider_reference_provider_key VARCHAR(255) DEFAULT NULL, provider_reference_provider_id VARCHAR(255) DEFAULT NULL, provider_reference_provider_url VARCHAR(255) DEFAULT NULL, provider_reference_last_updated DATETIME DEFAULT NULL, CONSTRAINT FK_6940A7FEEA7100A1 FOREIGN KEY (id_preview_attachment) REFERENCES "attachments" (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE5697F554 FOREIGN KEY (id_category) REFERENCES "categories" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE7E371A10 FOREIGN KEY (id_footprint) REFERENCES "footprints" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE2626CEF9 FOREIGN KEY (id_part_unit) REFERENCES "measurement_units" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE1ECB93AE FOREIGN KEY (id_manufacturer) REFERENCES "manufacturers" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FE81081E9B FOREIGN KEY (order_orderdetails_id) REFERENCES "orderdetails" (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE)');
|
||||
$this->addSql('INSERT INTO "parts" (id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated) SELECT id, id_preview_attachment, id_category, id_footprint, id_part_unit, id_manufacturer, order_orderdetails_id, built_project_id, name, last_modified, datetime_added, needs_review, tags, mass, ipn, description, comment, visible, favorite, minamount, manufacturer_product_url, manufacturer_product_number, manufacturing_status, order_quantity, manual_order, provider_reference_provider_key, provider_reference_provider_id, provider_reference_provider_url, provider_reference_last_updated FROM __temp__parts');
|
||||
$this->addSql('DROP TABLE __temp__parts');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE3D721C14 ON "parts" (ipn)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FEEA7100A1 ON "parts" (id_preview_attachment)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE5697F554 ON "parts" (id_category)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE7E371A10 ON "parts" (id_footprint)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE2626CEF9 ON "parts" (id_part_unit)');
|
||||
$this->addSql('CREATE INDEX IDX_6940A7FE1ECB93AE ON "parts" (id_manufacturer)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FE81081E9B ON "parts" (order_orderdetails_id)');
|
||||
$this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON "parts" (built_project_id)');
|
||||
$this->addSql('CREATE INDEX parts_idx_datet_name_last_id_needs ON "parts" (datetime_added, name, last_modified, id, needs_review)');
|
||||
$this->addSql('CREATE INDEX parts_idx_name ON "parts" (name)');
|
||||
$this->addSql('CREATE INDEX parts_idx_ipn ON "parts" (ipn)');
|
||||
}
|
||||
}
|
||||
80
package.json
80
package.json
@@ -7,10 +7,12 @@
|
||||
"@hotwired/turbo": "^7.0.1",
|
||||
"@popperjs/core": "^2.10.2",
|
||||
"@symfony/stimulus-bridge": "^3.2.0",
|
||||
"@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets",
|
||||
"@symfony/ux-turbo": "file:vendor/symfony/ux-turbo/assets",
|
||||
"@symfony/webpack-encore": "^4.1.0",
|
||||
"bootstrap": "^5.1.3",
|
||||
"core-js": "^3.23.0",
|
||||
"intl-messageformat": "^10.2.5",
|
||||
"jquery": "^3.5.1",
|
||||
"popper.js": "^1.14.7",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
@@ -28,45 +30,50 @@
|
||||
"build": "encore production --progress"
|
||||
},
|
||||
"dependencies": {
|
||||
"@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": "^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",
|
||||
"@ckeditor/ckeditor5-alignment": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-autoformat": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-basic-styles": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-block-quote": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-code-block": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-dev-translations": "^38.4.0",
|
||||
"@ckeditor/ckeditor5-dev-utils": "^38.4.0",
|
||||
"@ckeditor/ckeditor5-editor-classic": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-essentials": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-find-and-replace": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-font": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-heading": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-highlight": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-horizontal-line": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-html-embed": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-html-support": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-image": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-indent": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-link": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-list": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-markdown-gfm": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-media-embed": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-paragraph": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-paste-from-office": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-remove-format": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-source-editing": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-special-characters": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-table": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-theme-lark": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-upload": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-watchdog": "^39.0.1",
|
||||
"@ckeditor/ckeditor5-word-count": "^39.0.1",
|
||||
"@jbtronics/bs-treeview": "^1.0.1",
|
||||
"@zxcvbn-ts/core": "^3.0.2",
|
||||
"@zxcvbn-ts/language-common": "^3.0.3",
|
||||
"@zxcvbn-ts/language-de": "^3.0.1",
|
||||
"@zxcvbn-ts/language-en": "^3.0.1",
|
||||
"@zxcvbn-ts/language-fr": "^3.0.1",
|
||||
"@zxcvbn-ts/language-ja": "^3.0.1",
|
||||
"bootbox": "^6.0.0",
|
||||
"bootswatch": "^5.1.3",
|
||||
"bs-custom-file-input": "^1.3.4",
|
||||
"clipboard": "^2.0.4",
|
||||
"compression-webpack-plugin": "^10.0.0",
|
||||
"darkmode-js": "^1.5.0",
|
||||
"datatables.net-bs5": "^1.10.20",
|
||||
"datatables.net-buttons-bs5": "^2.2.2",
|
||||
"datatables.net-colreorder-bs5": "^1.5.1",
|
||||
@@ -74,12 +81,15 @@
|
||||
"datatables.net-responsive-bs5": "^2.2.3",
|
||||
"datatables.net-select-bs5": "^1.2.7",
|
||||
"dompurify": "^3.0.3",
|
||||
"emoji.json": "^14.0.0",
|
||||
"emoji.json": "^15.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.3.0",
|
||||
"marked": "^7.0.4",
|
||||
"marked-gfm-heading-id": "^3.0.4",
|
||||
"marked-mangle": "^1.0.1",
|
||||
"pdfmake": "^0.2.2",
|
||||
"stimulus-use": "^0.52.0",
|
||||
"tom-select": "^2.1.0",
|
||||
|
||||
52
phpstan.neon
52
phpstan.neon
@@ -1,11 +1,55 @@
|
||||
parameters:
|
||||
|
||||
level: 5
|
||||
|
||||
paths:
|
||||
- src
|
||||
# - tests
|
||||
|
||||
excludePaths:
|
||||
- src/DataTables/Adapter/*
|
||||
- src/Configuration/*
|
||||
- src/Doctrine/Purger/*
|
||||
|
||||
|
||||
|
||||
inferPrivatePropertyTypeFromConstructor: true
|
||||
treatPhpDocTypesAsCertain: false
|
||||
|
||||
symfony:
|
||||
container_xml_path: '%rootDir%/../../../var/cache/dev/App_KernelDevDebugContainer.xml'
|
||||
|
||||
excludes_analyse:
|
||||
- src/DataTables/Adapter/*
|
||||
- src/Configuration/*
|
||||
- src/Doctrine/Purger/*
|
||||
checkUninitializedProperties: true
|
||||
|
||||
checkFunctionNameCase: true
|
||||
|
||||
checkAlwaysTrueInstanceof: false
|
||||
checkAlwaysTrueCheckTypeFunctionCall: false
|
||||
checkAlwaysTrueStrictComparison: false
|
||||
reportAlwaysTrueInLastCondition: false
|
||||
|
||||
reportMaybesInPropertyPhpDocTypes: false
|
||||
reportMaybesInMethodSignatures: false
|
||||
|
||||
strictRules:
|
||||
disallowedLooseComparison: false
|
||||
booleansInConditions: false
|
||||
uselessCast: false
|
||||
requireParentConstructorCall: true
|
||||
disallowedConstructs: false
|
||||
overwriteVariablesWithLoop: false
|
||||
closureUsesThis: false
|
||||
matchingInheritedMethodNames: true
|
||||
numericOperandsInArithmeticOperators: true
|
||||
strictCalls: true
|
||||
switchConditionsMatchingType: false
|
||||
noVariableVariables: false
|
||||
|
||||
ignoreErrors:
|
||||
# Ignore errors caused by complex mapping with AbstractStructuralDBElement
|
||||
- '#AbstractStructuralDBElement does not have a field named \$parent#'
|
||||
- '#AbstractStructuralDBElement does not have a field named \$name#'
|
||||
|
||||
# Ignore errors related to the use of the ParametersTrait in Part entity
|
||||
- '#expects .*PartParameter, .*AbstractParameter given.#'
|
||||
- '#Part::getParameters\(\) should return .*AbstractParameter#'
|
||||
@@ -1,20 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="tests/bootstrap.php">
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
convertDeprecationsToExceptions="false"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1"/>
|
||||
<server name="APP_ENV" value="test" force="true"/>
|
||||
<server name="SHELL_VERBOSITY" value="-1"/>
|
||||
<server name="SYMFONY_PHPUNIT_REMOVE" value=""/>
|
||||
<server name="SYMFONY_PHPUNIT_VERSION" value="9"/>
|
||||
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5"/>
|
||||
<ini name="memory_limit" value="512M"/>
|
||||
<ini name="display_errors" value="1"/>
|
||||
</php>
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Project Test Suite">
|
||||
<directory>tests</directory>
|
||||
|
||||
63
rector.php
Normal file
63
rector.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector;
|
||||
use Rector\Config\RectorConfig;
|
||||
use Rector\Doctrine\Set\DoctrineSetList;
|
||||
use Rector\PHPUnit\Rector\ClassMethod\AddDoesNotPerformAssertionToNonAssertingTestRector;
|
||||
use Rector\PHPUnit\Set\PHPUnitLevelSetList;
|
||||
use Rector\PHPUnit\Set\PHPUnitSetList;
|
||||
use Rector\Set\ValueObject\LevelSetList;
|
||||
use Rector\Set\ValueObject\SetList;
|
||||
use Rector\Symfony\Set\SymfonyLevelSetList;
|
||||
use Rector\Symfony\Set\SymfonySetList;
|
||||
use Rector\TypeDeclaration\Rector\StmtsAwareInterface\DeclareStrictTypesRector;
|
||||
|
||||
return static function (RectorConfig $rectorConfig): void {
|
||||
$rectorConfig->symfonyContainerXml(__DIR__ . '/var/cache/dev/App_KernelDevDebugContainer.xml');
|
||||
$rectorConfig->symfonyContainerPhp(__DIR__ . '/tests/symfony-container.php');
|
||||
|
||||
//Import class names instead of using fully qualified class names
|
||||
$rectorConfig->importNames();
|
||||
//But keep the fully qualified class names for classes in the global namespace
|
||||
$rectorConfig->importShortClasses(false);
|
||||
|
||||
$rectorConfig->paths([
|
||||
__DIR__ . '/config',
|
||||
__DIR__ . '/public',
|
||||
__DIR__ . '/src',
|
||||
__DIR__ . '/tests',
|
||||
]);
|
||||
|
||||
// register a single rule
|
||||
//$rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class);
|
||||
|
||||
$rectorConfig->rules([
|
||||
DeclareStrictTypesRector::class,
|
||||
]);
|
||||
|
||||
// define sets of rules
|
||||
$rectorConfig->sets([
|
||||
//PHP rules
|
||||
SetList::CODE_QUALITY,
|
||||
LevelSetList::UP_TO_PHP_81,
|
||||
|
||||
//Symfony rules
|
||||
SymfonyLevelSetList::UP_TO_SYMFONY_62,
|
||||
SymfonySetList::SYMFONY_CODE_QUALITY,
|
||||
|
||||
//Doctrine rules
|
||||
DoctrineSetList::ANNOTATIONS_TO_ATTRIBUTES,
|
||||
DoctrineSetList::DOCTRINE_CODE_QUALITY,
|
||||
|
||||
//PHPUnit rules
|
||||
PHPUnitLevelSetList::UP_TO_PHPUNIT_90,
|
||||
PHPUnitSetList::PHPUNIT_CODE_QUALITY,
|
||||
]);
|
||||
|
||||
$rectorConfig->skip([
|
||||
AddDoesNotPerformAssertionToNonAssertingTestRector::class,
|
||||
CountArrayToEmptyArrayComparisonRector::class,
|
||||
]);
|
||||
};
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Command\Attachments;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Services\Attachments\AttachmentManager;
|
||||
use App\Services\Attachments\AttachmentPathResolver;
|
||||
use App\Services\Attachments\AttachmentReverseSearch;
|
||||
@@ -40,30 +41,21 @@ use function count;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
#[AsCommand('partdb:attachments:clean-unused|app:clean-attachments', 'Lists (and deletes if wanted) attachments files that are not used anymore (abandoned files).')]
|
||||
class CleanAttachmentsCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:attachments:clean-unused|app:clean-attachments';
|
||||
|
||||
protected AttachmentManager $attachment_helper;
|
||||
protected AttachmentReverseSearch $reverseSearch;
|
||||
protected MimeTypes $mimeTypeGuesser;
|
||||
protected AttachmentPathResolver $pathResolver;
|
||||
|
||||
public function __construct(AttachmentManager $attachmentHelper, AttachmentReverseSearch $reverseSearch, AttachmentPathResolver $pathResolver)
|
||||
public function __construct(protected AttachmentManager $attachment_helper, protected AttachmentReverseSearch $reverseSearch, protected AttachmentPathResolver $pathResolver)
|
||||
{
|
||||
$this->attachment_helper = $attachmentHelper;
|
||||
$this->pathResolver = $pathResolver;
|
||||
$this->reverseSearch = $reverseSearch;
|
||||
$this->mimeTypeGuesser = new MimeTypes();
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Lists (and deletes if wanted) attachments files that are not used anymore (abandoned files).')
|
||||
->setHelp('This command allows to find all files in the media folder which are not associated with an attachment anymore.'.
|
||||
' These files are not needed and can eventually deleted.');
|
||||
$this->setHelp('This command allows to find all files in the media folder which are not associated with an attachment anymore.'.
|
||||
' These files are not needed and can eventually deleted.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
@@ -91,7 +83,7 @@ class CleanAttachmentsCommand extends Command
|
||||
|
||||
foreach ($finder as $file) {
|
||||
//If not attachment object uses this file, print it
|
||||
if (0 === count($this->reverseSearch->findAttachmentsByFile($file))) {
|
||||
if ([] === $this->reverseSearch->findAttachmentsByFile($file)) {
|
||||
$file_list[] = $file;
|
||||
$table->addRow([
|
||||
$fs->makePathRelative($file->getPathname(), $mediaPath),
|
||||
@@ -101,14 +93,14 @@ class CleanAttachmentsCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
if (count($file_list) > 0) {
|
||||
if ($file_list !== []) {
|
||||
$table->render();
|
||||
|
||||
$continue = $io->confirm(sprintf('Found %d abandoned files. Do you want to delete them? This can not be undone!', count($file_list)), false);
|
||||
|
||||
if (!$continue) {
|
||||
//We are finished here, when no files should be deleted
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
//Delete the files
|
||||
@@ -121,7 +113,7 @@ class CleanAttachmentsCommand extends Command
|
||||
$io->success('No abandoned files found.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PhpZip\Constants\ZipCompressionMethod;
|
||||
@@ -16,19 +20,11 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('partdb:backup', 'Backup the files and the database of Part-DB')]
|
||||
class BackupCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:backup';
|
||||
protected static $defaultDescription = 'Backup the files and the database of Part-DB';
|
||||
|
||||
private string $project_dir;
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(string $project_dir, EntityManagerInterface $entityManager)
|
||||
public function __construct(private readonly string $project_dir, private readonly EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->project_dir = $project_dir;
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
@@ -71,13 +67,10 @@ class BackupCommand extends Command
|
||||
$io->info('Backup Part-DB to '.$output_filepath);
|
||||
|
||||
//Check if the file already exists
|
||||
if (file_exists($output_filepath)) {
|
||||
//Then ask the user, if he wants to overwrite the file
|
||||
if (!$io->confirm('The file '.realpath($output_filepath).' already exists. Do you want to overwrite it?', false)) {
|
||||
$io->error('Backup aborted!');
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
//Then ask the user, if he wants to overwrite the file
|
||||
if (file_exists($output_filepath) && !$io->confirm('The file '.realpath($output_filepath).' already exists. Do you want to overwrite it?', false)) {
|
||||
$io->error('Backup aborted!');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->note('Starting backup...');
|
||||
@@ -115,8 +108,6 @@ class BackupCommand extends Command
|
||||
/**
|
||||
* Constructs the MySQL PDO DSN.
|
||||
* Taken from https://github.com/doctrine/dbal/blob/3.5.x/src/Driver/PDO/MySQL/Driver.php
|
||||
*
|
||||
* @param array $params
|
||||
*/
|
||||
private function configureDumper(array $params, DbDumper $dumper): void
|
||||
{
|
||||
@@ -166,7 +157,7 @@ class BackupCommand extends Command
|
||||
$io->error('Could not dump database: '.$e->getMessage());
|
||||
$io->error('This can maybe be fixed by installing the mysqldump binary and adding it to the PATH variable!');
|
||||
}
|
||||
} elseif ($connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) {
|
||||
} elseif ($connection->getDatabasePlatform() instanceof SqlitePlatform) {
|
||||
$io->note('SQLite database detected. Copy DB file to ZIP...');
|
||||
$params = $connection->getParams();
|
||||
$zip->addFile($params['path'], 'var/app.db');
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,9 @@
|
||||
* 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\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
@@ -27,23 +30,17 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
|
||||
|
||||
#[AsCommand('partdb:check-requirements', 'Checks if the requirements Part-DB needs or recommends are fulfilled.')]
|
||||
class CheckRequirementsCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:check-requirements';
|
||||
|
||||
protected ContainerBagInterface $params;
|
||||
|
||||
public function __construct(ContainerBagInterface $params)
|
||||
public function __construct(protected ContainerBagInterface $params)
|
||||
{
|
||||
$this->params = $params;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Checks if the requirements Part-DB needs or recommends are fulfilled.')
|
||||
->addOption('only_issues', 'i', InputOption::VALUE_NONE, 'Only show issues, not success messages.')
|
||||
$this->addOption('only_issues', 'i', InputOption::VALUE_NONE, 'Only show issues, not success messages.')
|
||||
;
|
||||
}
|
||||
|
||||
@@ -66,105 +63,124 @@ class CheckRequirementsCommand extends Command
|
||||
|
||||
}
|
||||
|
||||
protected function checkPHP(SymfonyStyle $io, $only_issues = false): void
|
||||
protected function checkPHP(SymfonyStyle $io, bool $only_issues = false): void
|
||||
{
|
||||
//Check PHP versions
|
||||
$io->isVerbose() && $io->comment('Checking PHP version...');
|
||||
if (PHP_VERSION_ID < 80100) {
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking PHP version...');
|
||||
}
|
||||
//We recommend PHP 8.2, but 8.1 is the minimum
|
||||
if (PHP_VERSION_ID < 80200) {
|
||||
$io->warning('You are using PHP '. PHP_VERSION .'. This will work, but a newer version is recommended.');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP version is sufficient.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('PHP version is sufficient.');
|
||||
}
|
||||
|
||||
//Check if opcache is enabled
|
||||
$io->isVerbose() && $io->comment('Checking Opcache...');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking Opcache...');
|
||||
}
|
||||
$opcache_enabled = ini_get('opcache.enable') === '1';
|
||||
if (!$opcache_enabled) {
|
||||
$io->warning('Opcache is not enabled. This will work, but performance will be better with opcache enabled. Set opcache.enable=1 in your php.ini to enable it');
|
||||
} else {
|
||||
!$only_issues && $io->success('Opcache is enabled.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('Opcache is enabled.');
|
||||
}
|
||||
|
||||
//Check if opcache is configured correctly
|
||||
$io->isVerbose() && $io->comment('Checking Opcache configuration...');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking Opcache configuration...');
|
||||
}
|
||||
if ($opcache_enabled && (ini_get('opcache.memory_consumption') < 256 || ini_get('opcache.max_accelerated_files') < 20000)) {
|
||||
$io->warning('Opcache configuration can be improved. See https://symfony.com/doc/current/performance.html for more info.');
|
||||
} else {
|
||||
!$only_issues && $io->success('Opcache configuration is already performance optimized.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('Opcache configuration is already performance optimized.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkPartDBConfig(SymfonyStyle $io, $only_issues = false): void
|
||||
protected function checkPartDBConfig(SymfonyStyle $io, bool $only_issues = false): void
|
||||
{
|
||||
//Check if APP_ENV is set to prod
|
||||
$io->isVerbose() && $io->comment('Checking debug mode...');
|
||||
if($this->params->get('kernel.debug')) {
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking debug mode...');
|
||||
}
|
||||
if ($this->params->get('kernel.debug')) {
|
||||
$io->warning('You have activated debug mode, this is will leak informations in a production environment.');
|
||||
} else {
|
||||
!$only_issues && $io->success('Debug mode disabled.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('Debug mode disabled.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function checkPHPExtensions(SymfonyStyle $io, $only_issues = false): void
|
||||
protected function checkPHPExtensions(SymfonyStyle $io, bool $only_issues = false): void
|
||||
{
|
||||
//Get all installed PHP extensions
|
||||
$extensions = get_loaded_extensions();
|
||||
$io->isVerbose() && $io->comment('Your PHP installation has '. count($extensions) .' extensions installed: '. implode(', ', $extensions));
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Your PHP installation has '. count($extensions) .' extensions installed: '. implode(', ', $extensions));
|
||||
}
|
||||
|
||||
$db_drivers_count = 0;
|
||||
if(!in_array('pdo_mysql', $extensions)) {
|
||||
if(!in_array('pdo_mysql', $extensions, true)) {
|
||||
$io->error('pdo_mysql is not installed. You will not be able to use MySQL databases.');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension pdo_mysql is installed.');
|
||||
if (!$only_issues) {
|
||||
$io->success('PHP extension pdo_mysql is installed.');
|
||||
}
|
||||
$db_drivers_count++;
|
||||
}
|
||||
|
||||
if(!in_array('pdo_sqlite', $extensions)) {
|
||||
if(!in_array('pdo_sqlite', $extensions, true)) {
|
||||
$io->error('pdo_sqlite is not installed. You will not be able to use SQLite. databases');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension pdo_sqlite is installed.');
|
||||
if (!$only_issues) {
|
||||
$io->success('PHP extension pdo_sqlite is installed.');
|
||||
}
|
||||
$db_drivers_count++;
|
||||
}
|
||||
|
||||
$io->isVerbose() && $io->comment('You have '. $db_drivers_count .' database drivers installed.');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('You have '. $db_drivers_count .' database drivers installed.');
|
||||
}
|
||||
if ($db_drivers_count === 0) {
|
||||
$io->error('You have no database drivers installed. You have to install at least one database driver!');
|
||||
}
|
||||
|
||||
if(!in_array('curl', $extensions)) {
|
||||
if (!in_array('curl', $extensions, true)) {
|
||||
$io->warning('curl extension is not installed. Install curl extension for better performance');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension curl is installed.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('PHP extension curl is installed.');
|
||||
}
|
||||
|
||||
$gd_installed = in_array('gd', $extensions);
|
||||
if(!$gd_installed) {
|
||||
$gd_installed = in_array('gd', $extensions, true);
|
||||
if (!$gd_installed) {
|
||||
$io->error('GD is not installed. GD is required for image processing.');
|
||||
} else {
|
||||
!$only_issues && $io->success('PHP extension GD is installed.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('PHP extension GD is installed.');
|
||||
}
|
||||
|
||||
//Check if GD has jpeg support
|
||||
$io->isVerbose() && $io->comment('Checking if GD has jpeg support...');
|
||||
if ($io->isVerbose()) {
|
||||
$io->comment('Checking if GD has jpeg support...');
|
||||
}
|
||||
if ($gd_installed) {
|
||||
$gd_info = gd_info();
|
||||
if($gd_info['JPEG Support'] === false) {
|
||||
if ($gd_info['JPEG Support'] === false) {
|
||||
$io->warning('Your GD does not have jpeg support. You will not be able to generate thumbnails of jpeg images.');
|
||||
} else {
|
||||
!$only_issues && $io->success('GD has jpeg support.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('GD has jpeg support.');
|
||||
}
|
||||
|
||||
if($gd_info['PNG Support'] === false) {
|
||||
if ($gd_info['PNG Support'] === false) {
|
||||
$io->warning('Your GD does not have png support. You will not be able to generate thumbnails of png images.');
|
||||
} else {
|
||||
!$only_issues && $io->success('GD has png support.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('GD has png support.');
|
||||
}
|
||||
|
||||
if($gd_info['WebP Support'] === false) {
|
||||
if ($gd_info['WebP Support'] === false) {
|
||||
$io->warning('Your GD does not have WebP support. You will not be able to generate thumbnails of WebP images.');
|
||||
} else {
|
||||
!$only_issues && $io->success('GD has WebP support.');
|
||||
} elseif (!$only_issues) {
|
||||
$io->success('GD has WebP support.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,4 +189,4 @@ class CheckRequirementsCommand extends Command
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Command\Currencies;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\PriceInformations\Currency;
|
||||
use App\Services\Tools\ExchangeRateUpdater;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -35,30 +36,17 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use function count;
|
||||
use function strlen;
|
||||
|
||||
#[AsCommand('partdb:currencies:update-exchange-rates|partdb:update-exchange-rates|app:update-exchange-rates', 'Updates the currency exchange rates.')]
|
||||
class UpdateExchangeRatesCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:currencies:update-exchange-rates|partdb:update-exchange-rates|app:update-exchange-rates';
|
||||
|
||||
protected string $base_current;
|
||||
protected EntityManagerInterface $em;
|
||||
protected ExchangeRateUpdater $exchangeRateUpdater;
|
||||
|
||||
public function __construct(string $base_current, EntityManagerInterface $entityManager, ExchangeRateUpdater $exchangeRateUpdater)
|
||||
public function __construct(protected string $base_current, protected EntityManagerInterface $em, protected ExchangeRateUpdater $exchangeRateUpdater)
|
||||
{
|
||||
//$this->swap = $swap;
|
||||
$this->base_current = $base_current;
|
||||
|
||||
$this->em = $entityManager;
|
||||
$this->exchangeRateUpdater = $exchangeRateUpdater;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Updates the currency exchange rates.')
|
||||
->addArgument('iso_code', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'The ISO Codes of the currencies that should be updated.');
|
||||
$this->addArgument('iso_code', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, 'The ISO Codes of the currencies that should be updated.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
@@ -69,7 +57,7 @@ class UpdateExchangeRatesCommand extends Command
|
||||
if (3 !== strlen($this->base_current)) {
|
||||
$io->error('Chosen Base current is not valid. Check your settings!');
|
||||
|
||||
return 1;
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->note('Update currency exchange rates with base currency: '.$this->base_current);
|
||||
@@ -78,11 +66,7 @@ class UpdateExchangeRatesCommand extends Command
|
||||
$iso_code = $input->getArgument('iso_code');
|
||||
$repo = $this->em->getRepository(Currency::class);
|
||||
|
||||
if (!empty($iso_code)) {
|
||||
$candidates = $repo->findBy(['iso_code' => $iso_code]);
|
||||
} else {
|
||||
$candidates = $repo->findAll();
|
||||
}
|
||||
$candidates = empty($iso_code) ? $repo->findAll() : $repo->findBy(['iso_code' => $iso_code]);
|
||||
|
||||
$success_counter = 0;
|
||||
|
||||
@@ -106,6 +90,6 @@ class UpdateExchangeRatesCommand extends Command
|
||||
|
||||
$io->success(sprintf('%d (of %d) currency exchange rates were updated.', $success_counter, count($candidates)));
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Command\Logs;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Entity\Base\AbstractNamedDBElement;
|
||||
use App\Entity\LogSystem\AbstractLogEntry;
|
||||
use App\Repository\LogEntryRepository;
|
||||
@@ -36,23 +38,14 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
#[AsCommand('partdb:logs:show|app:show-logs', 'List the last event log entries.')]
|
||||
class ShowEventLogCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:logs:show|app:show-logs';
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected TranslatorInterface $translator;
|
||||
protected ElementTypeNameGenerator $elementTypeNameGenerator;
|
||||
protected LogEntryRepository $repo;
|
||||
protected LogEntryExtraFormatter $formatter;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager,
|
||||
TranslatorInterface $translator, ElementTypeNameGenerator $elementTypeNameGenerator, LogEntryExtraFormatter $formatter)
|
||||
public function __construct(protected EntityManagerInterface $entityManager,
|
||||
protected TranslatorInterface $translator, protected ElementTypeNameGenerator $elementTypeNameGenerator, protected LogEntryExtraFormatter $formatter)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->translator = $translator;
|
||||
$this->elementTypeNameGenerator = $elementTypeNameGenerator;
|
||||
$this->formatter = $formatter;
|
||||
|
||||
$this->repo = $this->entityManager->getRepository(AbstractLogEntry::class);
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -74,7 +67,7 @@ class ShowEventLogCommand extends Command
|
||||
if ($page > $max_page && $max_page > 0) {
|
||||
$io->error("There is no page ${page}! The maximum page is ${max_page}.");
|
||||
|
||||
return 1;
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->note("There are a total of ${total_count} log entries in the DB.");
|
||||
@@ -84,21 +77,19 @@ class ShowEventLogCommand extends Command
|
||||
$this->showPage($output, $desc, $limit, $page, $max_page, $showExtra);
|
||||
|
||||
if ($onePage) {
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$continue = $io->confirm('Do you want to show the next page?');
|
||||
++$page;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('List the last event log entries.')
|
||||
->addOption('count', 'c', InputOption::VALUE_REQUIRED, 'How many log entries should be shown per page.', 50)
|
||||
$this->addOption('count', 'c', InputOption::VALUE_REQUIRED, 'How many log entries should be shown per page.', 50)
|
||||
->addOption('oldest_first', null, InputOption::VALUE_NONE, 'Show older entries first.')
|
||||
->addOption('page', 'p', InputOption::VALUE_REQUIRED, 'Which page should be shown?', 1)
|
||||
->addOption('onePage', null, InputOption::VALUE_NONE, 'Show only one page (dont ask to go to next).')
|
||||
@@ -147,14 +138,12 @@ class ShowEventLogCommand extends Command
|
||||
$target_class = $this->elementTypeNameGenerator->getLocalizedTypeLabel($entry->getTargetClass());
|
||||
}
|
||||
|
||||
if ($entry->getUser()) {
|
||||
if ($entry->getUser() instanceof User) {
|
||||
$user = $entry->getUser()->getFullName(true);
|
||||
} elseif ($entry->isCLIEntry()) {
|
||||
$user = $entry->getCLIUsername() . ' [CLI]';
|
||||
} else {
|
||||
if ($entry->isCLIEntry()) {
|
||||
$user = $entry->getCLIUsername() . ' [CLI]';
|
||||
} else {
|
||||
$user = $entry->getUsername() . ' [deleted]';
|
||||
}
|
||||
$user = $entry->getUsername() . ' [deleted]';
|
||||
}
|
||||
|
||||
$row = [
|
||||
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Command\Migrations;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\Base\AbstractNamedDBElement;
|
||||
use App\Entity\ProjectSystem\Project;
|
||||
@@ -47,6 +48,7 @@ use function count;
|
||||
/**
|
||||
* This command converts the BBCode used by old Part-DB versions (<1.0), to the current used Markdown format.
|
||||
*/
|
||||
#[AsCommand('partdb:migrations:convert-bbcode|app:convert-bbcode', 'Converts BBCode used in old Part-DB versions to newly used Markdown')]
|
||||
class ConvertBBCodeCommand extends Command
|
||||
{
|
||||
/**
|
||||
@@ -57,18 +59,10 @@ class ConvertBBCodeCommand extends Command
|
||||
* @var string The regex (performed in PHP) used to check if a property really contains BBCODE
|
||||
*/
|
||||
protected const BBCODE_REGEX = '/\\[.+\\].*\\[\\/.+\\]/';
|
||||
|
||||
protected static $defaultName = 'partdb:migrations:convert-bbcode|app:convert-bbcode';
|
||||
|
||||
protected EntityManagerInterface $em;
|
||||
protected PropertyAccessorInterface $propertyAccessor;
|
||||
protected BBCodeToMarkdownConverter $converter;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, PropertyAccessorInterface $propertyAccessor)
|
||||
public function __construct(protected EntityManagerInterface $em, protected PropertyAccessorInterface $propertyAccessor)
|
||||
{
|
||||
$this->em = $entityManager;
|
||||
$this->propertyAccessor = $propertyAccessor;
|
||||
|
||||
$this->converter = new BBCodeToMarkdownConverter();
|
||||
|
||||
parent::__construct();
|
||||
@@ -76,9 +70,7 @@ class ConvertBBCodeCommand extends Command
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Converts BBCode used in old Part-DB versions to newly used Markdown')
|
||||
->setHelp('Older versions of Part-DB (<1.0) used BBCode for rich text formatting.
|
||||
$this->setHelp('Older versions of Part-DB (<1.0) used BBCode for rich text formatting.
|
||||
Part-DB now uses Markdown which offers more features but is incompatible with BBCode.
|
||||
When you upgrade from an pre 1.0 version you have to run this command to convert your comment fields');
|
||||
|
||||
@@ -129,25 +121,25 @@ class ConvertBBCodeCommand extends Command
|
||||
|
||||
//Fetch resulting classes
|
||||
$results = $qb->getQuery()->getResult();
|
||||
$io->note(sprintf('Found %d entities, that need to be converted!', count($results)));
|
||||
$io->note(sprintf('Found %d entities, that need to be converted!', is_countable($results) ? count($results) : 0));
|
||||
|
||||
//In verbose mode print the names of the entities
|
||||
foreach ($results as $result) {
|
||||
/** @var AbstractNamedDBElement $result */
|
||||
$io->writeln(
|
||||
'Convert entity: '.$result->getName().' ('.get_class($result).': '.$result->getID().')',
|
||||
'Convert entity: '.$result->getName().' ('.$result::class.': '.$result->getID().')',
|
||||
OutputInterface::VERBOSITY_VERBOSE
|
||||
);
|
||||
foreach ($properties as $property) {
|
||||
//Retrieve bbcode from entity
|
||||
$bbcode = $this->propertyAccessor->getValue($result, $property);
|
||||
//Check if the current property really contains BBCode
|
||||
if (!preg_match(static::BBCODE_REGEX, $bbcode)) {
|
||||
if (!preg_match(static::BBCODE_REGEX, (string) $bbcode)) {
|
||||
continue;
|
||||
}
|
||||
$io->writeln(
|
||||
'BBCode (old): '
|
||||
.str_replace('\n', ' ', substr($bbcode, 0, 255)),
|
||||
.str_replace('\n', ' ', substr((string) $bbcode, 0, 255)),
|
||||
OutputInterface::VERBOSITY_VERY_VERBOSE
|
||||
);
|
||||
$markdown = $this->converter->convert($bbcode);
|
||||
@@ -168,6 +160,6 @@ class ConvertBBCodeCommand extends Command
|
||||
$io->success('Changes saved to DB successfully!');
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,9 @@
|
||||
* 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\Command\Migrations;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Services\ImportExportSystem\PartKeeprImporter\PKDatastructureImporter;
|
||||
use App\Services\ImportExportSystem\PartKeeprImporter\MySQLDumpXMLConverter;
|
||||
use App\Services\ImportExportSystem\PartKeeprImporter\PKImportHelper;
|
||||
@@ -33,34 +36,19 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('partdb:migrations:import-partkeepr', 'Import a PartKeepr database XML dump into Part-DB')]
|
||||
class ImportPartKeeprCommand extends Command
|
||||
{
|
||||
|
||||
protected static $defaultName = 'partdb:migrations:import-partkeepr';
|
||||
|
||||
protected EntityManagerInterface $em;
|
||||
protected MySQLDumpXMLConverter $xml_converter;
|
||||
protected PKDatastructureImporter $datastructureImporter;
|
||||
protected PKImportHelper $importHelper;
|
||||
protected PKPartImporter $partImporter;
|
||||
protected PKOptionalImporter $optionalImporter;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, MySQLDumpXMLConverter $xml_converter,
|
||||
PKDatastructureImporter $datastructureImporter, PKPartImporter $partImporter, PKImportHelper $importHelper,
|
||||
PKOptionalImporter $optionalImporter)
|
||||
public function __construct(protected EntityManagerInterface $em, protected MySQLDumpXMLConverter $xml_converter,
|
||||
protected PKDatastructureImporter $datastructureImporter, protected PKPartImporter $partImporter, protected PKImportHelper $importHelper,
|
||||
protected PKOptionalImporter $optionalImporter)
|
||||
{
|
||||
parent::__construct(self::$defaultName);
|
||||
$this->em = $em;
|
||||
$this->datastructureImporter = $datastructureImporter;
|
||||
$this->importHelper = $importHelper;
|
||||
$this->partImporter = $partImporter;
|
||||
$this->xml_converter = $xml_converter;
|
||||
$this->optionalImporter = $optionalImporter;
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setDescription('Import a PartKeepr database XML dump into Part-DB');
|
||||
$this->setHelp('This command allows you to import a PartKeepr database exported by mysqldump as XML file into Part-DB');
|
||||
|
||||
$this->addArgument('file', InputArgument::REQUIRED, 'The file to which should be imported.');
|
||||
@@ -100,7 +88,7 @@ class ImportPartKeeprCommand extends Command
|
||||
if (!$this->importHelper->checkVersion($data)) {
|
||||
$db_version = $this->importHelper->getDatabaseSchemaVersion($data);
|
||||
$io->error('The version of the imported database is not supported! (Version: '.$db_version.')');
|
||||
return 1;
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
//Import the mandatory data
|
||||
@@ -118,7 +106,7 @@ class ImportPartKeeprCommand extends Command
|
||||
$io->success('Imported '.$count.' users.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function doImport(SymfonyStyle $io, array $data): void
|
||||
@@ -155,4 +143,4 @@ class ImportPartKeeprCommand extends Command
|
||||
$io->success('Imported '.$count.' parts.');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,9 @@
|
||||
* 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\Command\User;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Security\SamlUserFactory;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -30,25 +33,17 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('partdb:user:convert-to-saml-user|partdb:users:convert-to-saml-user', 'Converts a local user to a SAML user (and vice versa)')]
|
||||
class ConvertToSAMLUserCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:user:convert-to-saml-user|partdb:users:convert-to-saml-user';
|
||||
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected bool $saml_enabled;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, bool $saml_enabled)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, protected bool $saml_enabled)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->entityManager = $entityManager;
|
||||
$this->saml_enabled = $saml_enabled;
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Converts a local user to a SAML user (and vice versa)')
|
||||
->setHelp('This converts a local user, which can login via the login form, to a SAML user, which can only login via SAML. This is useful if you want to migrate from a local user system to a SAML user system.')
|
||||
$this->setHelp('This converts a local user, which can login via the login form, to a SAML user, which can only login via SAML. This is useful if you want to migrate from a local user system to a SAML user system.')
|
||||
->addArgument('user', InputArgument::REQUIRED, 'The username (or email) of the user')
|
||||
->addOption('to-local', null, InputOption::VALUE_NONE, 'Converts a SAML user to a local user')
|
||||
;
|
||||
@@ -70,7 +65,7 @@ class ConvertToSAMLUserCommand extends Command
|
||||
if (!$user) {
|
||||
$io->error('User not found!');
|
||||
|
||||
return 1;
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->info('User found: '.$user->getFullName(true) . ': '.$user->getEmail().' [ID: ' . $user->getID() . ']');
|
||||
@@ -87,7 +82,7 @@ class ConvertToSAMLUserCommand extends Command
|
||||
$io->confirm('You are going to convert a SAML user to a local user. This means, that the user can only login via the login form. '
|
||||
. 'The permissions and groups settings of the user will remain unchanged. Do you really want to continue?');
|
||||
|
||||
$user->setSAMLUser(false);
|
||||
$user->setSamlUser(false);
|
||||
$user->setPassword(SamlUserFactory::SAML_PASSWORD_PLACEHOLDER);
|
||||
|
||||
$this->entityManager->flush();
|
||||
@@ -102,7 +97,7 @@ class ConvertToSAMLUserCommand extends Command
|
||||
$io->confirm('You are going to convert a local user to a SAML user. This means, that the user can only login via SAML afterwards. The password in the DB will be removed. '
|
||||
. 'The permissions and groups settings of the user will remain unchanged. Do you really want to continue?');
|
||||
|
||||
$user->setSAMLUser(true);
|
||||
$user->setSamlUser(true);
|
||||
$user->setPassword(SamlUserFactory::SAML_PASSWORD_PLACEHOLDER);
|
||||
|
||||
$this->entityManager->flush();
|
||||
@@ -112,4 +107,4 @@ class ConvertToSAMLUserCommand extends Command
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Command\User;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Events\SecurityEvent;
|
||||
use App\Events\SecurityEvents;
|
||||
@@ -34,28 +35,17 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
|
||||
#[AsCommand('partdb:users:set-password|app:set-password|users:set-password|partdb:user:set-password', 'Sets the password of a user')]
|
||||
class SetPasswordCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:users:set-password|app:set-password|users:set-password|partdb:user:set-password';
|
||||
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected UserPasswordHasherInterface $encoder;
|
||||
protected EventDispatcherInterface $eventDispatcher;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, UserPasswordHasherInterface $passwordEncoder, EventDispatcherInterface $eventDispatcher)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, protected UserPasswordHasherInterface $encoder, protected EventDispatcherInterface $eventDispatcher)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->encoder = $passwordEncoder;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Sets the password of a user')
|
||||
->setHelp('This password allows you to set the password of a user, without knowing the old password.')
|
||||
$this->setHelp('This password allows you to set the password of a user, without knowing the old password.')
|
||||
->addArgument('user', InputArgument::REQUIRED, 'The username or email of the user')
|
||||
;
|
||||
}
|
||||
@@ -67,17 +57,17 @@ class SetPasswordCommand extends Command
|
||||
|
||||
$user = $this->entityManager->getRepository(User::class)->findByEmailOrName($user_name);
|
||||
|
||||
if (!$user) {
|
||||
if (!$user instanceof User) {
|
||||
$io->error(sprintf('No user with the given username %s found in the database!', $user_name));
|
||||
|
||||
return 1;
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->note('User found!');
|
||||
|
||||
if ($user->isSamlUser()) {
|
||||
$io->error('This user is a SAML user, so you can not change the password!');
|
||||
return 1;
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$proceed = $io->confirm(
|
||||
@@ -85,7 +75,7 @@ class SetPasswordCommand extends Command
|
||||
$user->getFullName(true), $user->getID()));
|
||||
|
||||
if (!$proceed) {
|
||||
return 1;
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$success = false;
|
||||
@@ -116,6 +106,6 @@ class SetPasswordCommand extends Command
|
||||
$security_event = new SecurityEvent($user);
|
||||
$this->eventDispatcher->dispatch($security_event, SecurityEvents::PASSWORD_CHANGED);
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,9 @@
|
||||
* 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\Command\User;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\UserSystem\Group;
|
||||
use App\Entity\UserSystem\PermissionData;
|
||||
use App\Entity\UserSystem\User;
|
||||
@@ -31,22 +34,12 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('partdb:users:upgrade-permissions-schema', '(Manually) upgrades the permissions schema of all users to the latest version.')]
|
||||
final class UpgradePermissionsSchemaCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:users:upgrade-permissions-schema';
|
||||
protected static $defaultDescription = '(Manually) upgrades the permissions schema of all users to the latest version.';
|
||||
|
||||
private PermissionSchemaUpdater $permissionSchemaUpdater;
|
||||
private EntityManagerInterface $em;
|
||||
private EventCommentHelper $eventCommentHelper;
|
||||
|
||||
public function __construct(PermissionSchemaUpdater $permissionSchemaUpdater, EntityManagerInterface $entityManager, EventCommentHelper $eventCommentHelper)
|
||||
public function __construct(private readonly PermissionSchemaUpdater $permissionSchemaUpdater, private readonly EntityManagerInterface $em, private readonly EventCommentHelper $eventCommentHelper)
|
||||
{
|
||||
parent::__construct(self::$defaultName);
|
||||
|
||||
$this->permissionSchemaUpdater = $permissionSchemaUpdater;
|
||||
$this->eventCommentHelper = $eventCommentHelper;
|
||||
$this->em = $entityManager;
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
@@ -81,26 +74,22 @@ final class UpgradePermissionsSchemaCommand extends Command
|
||||
}
|
||||
|
||||
$io->info('Found '. count($groups_to_upgrade) .' groups and '. count($users_to_upgrade) .' users that need an update.');
|
||||
if (empty($groups_to_upgrade) && empty($users_to_upgrade)) {
|
||||
if ($groups_to_upgrade === [] && $users_to_upgrade === []) {
|
||||
$io->success('All users and group permissions schemas are up-to-date. No update needed.');
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
//List all users and groups that need an update
|
||||
$io->section('Groups that need an update:');
|
||||
$io->listing(array_map(static function (Group $group) {
|
||||
return $group->getName() . ' (ID: '. $group->getID() .', Current version: ' . $group->getPermissions()->getSchemaVersion() . ')';
|
||||
}, $groups_to_upgrade));
|
||||
$io->listing(array_map(static fn(Group $group): string => $group->getName() . ' (ID: '. $group->getID() .', Current version: ' . $group->getPermissions()->getSchemaVersion() . ')', $groups_to_upgrade));
|
||||
|
||||
$io->section('Users that need an update:');
|
||||
$io->listing(array_map(static function (User $user) {
|
||||
return $user->getUsername() . ' (ID: '. $user->getID() .', Current version: ' . $user->getPermissions()->getSchemaVersion() . ')';
|
||||
}, $users_to_upgrade));
|
||||
$io->listing(array_map(static fn(User $user): string => $user->getUsername() . ' (ID: '. $user->getID() .', Current version: ' . $user->getPermissions()->getSchemaVersion() . ')', $users_to_upgrade));
|
||||
|
||||
if(!$io->confirm('Continue with the update?', false)) {
|
||||
$io->warning('Update aborted.');
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
//Update all users and groups
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,9 @@
|
||||
* 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\Command\User;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\UserSystem\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
@@ -29,24 +32,17 @@ use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('partdb:users:enable|partdb:user:enable', 'Enables/Disable the login of one or more users')]
|
||||
class UserEnableCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:users:enable|partdb:user:enable';
|
||||
|
||||
protected EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, string $name = null)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, string $name = null)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Enables/Disable the login of one or more users')
|
||||
->setHelp('This allows you to allow or prevent the login of certain user. Use the --disable option to disable the login for the given users')
|
||||
$this->setHelp('This allows you to allow or prevent the login of certain user. Use the --disable option to disable the login for the given users')
|
||||
->addArgument('users', InputArgument::IS_ARRAY, 'The usernames of the users to use')
|
||||
->addOption('all', 'a', InputOption::VALUE_NONE, 'Enable/Disable all users')
|
||||
->addOption('disable', 'd', InputOption::VALUE_NONE, 'Disable the login of the given users')
|
||||
@@ -73,7 +69,7 @@ class UserEnableCommand extends Command
|
||||
} else { //Otherwise, fetch the users from DB
|
||||
foreach ($usernames as $username) {
|
||||
$user = $repo->findByEmailOrName($username);
|
||||
if ($user === null) {
|
||||
if (!$user instanceof User) {
|
||||
$io->error('No user found with username: '.$username);
|
||||
return self::FAILURE;
|
||||
}
|
||||
@@ -87,9 +83,7 @@ class UserEnableCommand extends Command
|
||||
$io->note('The following users will be enabled:');
|
||||
}
|
||||
$io->table(['Username', 'Enabled/Disabled'],
|
||||
array_map(static function(User $user) {
|
||||
return [$user->getFullName(true), $user->isDisabled() ? 'Disabled' : 'Enabled'];
|
||||
}, $users));
|
||||
array_map(static fn(User $user) => [$user->getFullName(true), $user->isDisabled() ? 'Disabled' : 'Enabled'], $users));
|
||||
|
||||
if(!$io->confirm('Do you want to continue?')) {
|
||||
$io->warning('Aborting!');
|
||||
@@ -107,4 +101,4 @@ class UserEnableCommand extends Command
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,10 @@
|
||||
* 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\Command\User;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\UserSystem\Group;
|
||||
use App\Entity\UserSystem\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
@@ -28,24 +32,17 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('partdb:users:list|users:list', 'Lists all users')]
|
||||
class UserListCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:users:list|users:list';
|
||||
|
||||
protected EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
public function __construct(protected EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Lists all users')
|
||||
->setHelp('This command lists all users in the database.')
|
||||
$this->setHelp('This command lists all users in the database.')
|
||||
->addOption('local', 'l', null, 'Only list local users')
|
||||
->addOption('saml', 's', null, 'Only list SAML users')
|
||||
;
|
||||
@@ -82,13 +79,13 @@ class UserListCommand extends Command
|
||||
|
||||
foreach ($users as $user) {
|
||||
$table->addRow([
|
||||
$user->getId(),
|
||||
$user->getID(),
|
||||
$user->getUsername(),
|
||||
$user->getFullName(),
|
||||
$user->getEmail(),
|
||||
$user->getGroup() !== null ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group',
|
||||
$user->getGroup() instanceof Group ? $user->getGroup()->getName() . ' (ID: ' . $user->getGroup()->getID() . ')' : 'No group',
|
||||
$user->isDisabled() ? 'Yes' : 'No',
|
||||
$user->isSAMLUser() ? 'SAML' : 'Local',
|
||||
$user->isSamlUser() ? 'SAML' : 'Local',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -98,4 +95,4 @@ class UserListCommand extends Command
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,9 @@
|
||||
* 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\Command\User;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Services\UserSystem\PermissionManager;
|
||||
@@ -34,22 +37,14 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
#[AsCommand('partdb:users:permissions|partdb:user:permissions', 'View and edit the permissions of a given user')]
|
||||
class UsersPermissionsCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:users:permissions|partdb:user:permissions';
|
||||
protected static $defaultDescription = 'View and edit the permissions of a given user';
|
||||
|
||||
protected EntityManagerInterface $entityManager;
|
||||
protected UserRepository $userRepository;
|
||||
protected PermissionManager $permissionResolver;
|
||||
protected TranslatorInterface $translator;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, PermissionManager $permissionResolver, TranslatorInterface $translator)
|
||||
public function __construct(protected EntityManagerInterface $entityManager, protected PermissionManager $permissionResolver, protected TranslatorInterface $translator)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
$this->userRepository = $entityManager->getRepository(User::class);
|
||||
$this->permissionResolver = $permissionResolver;
|
||||
$this->translator = $translator;
|
||||
|
||||
parent::__construct(self::$defaultName);
|
||||
}
|
||||
@@ -73,12 +68,12 @@ class UsersPermissionsCommand extends Command
|
||||
//Find user
|
||||
$io->note('Finding user with username: ' . $username);
|
||||
$user = $this->userRepository->findByEmailOrName($username);
|
||||
if ($user === null) {
|
||||
if (!$user instanceof User) {
|
||||
$io->error('No user found with username: ' . $username);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->note(sprintf('Found user %s with ID %d', $user->getFullName(true), $user->getId()));
|
||||
$io->note(sprintf('Found user %s with ID %d', $user->getFullName(true), $user->getID()));
|
||||
|
||||
$edit_mapping = $this->renderPermissionTable($output, $user, $inherit);
|
||||
|
||||
@@ -102,7 +97,7 @@ class UsersPermissionsCommand extends Command
|
||||
|
||||
|
||||
$new_value_str = $io->ask('Enter the new value for the permission (A = allow, D = disallow, I = inherit)');
|
||||
switch (strtolower($new_value_str)) {
|
||||
switch (strtolower((string) $new_value_str)) {
|
||||
case 'a':
|
||||
case 'allow':
|
||||
$new_value = true;
|
||||
@@ -209,11 +204,11 @@ class UsersPermissionsCommand extends Command
|
||||
|
||||
if ($permission_value === true) {
|
||||
return '<fg=green>Allow</>';
|
||||
} else if ($permission_value === false) {
|
||||
} elseif ($permission_value === false) {
|
||||
return '<fg=red>Disallow</>';
|
||||
} else if ($permission_value === null && !$inherit) {
|
||||
} elseif ($permission_value === null && !$inherit) {
|
||||
return '<fg=blue>Inherit</>';
|
||||
} else if ($permission_value === null && $inherit) {
|
||||
} elseif ($permission_value === null && $inherit) {
|
||||
return '<fg=red>Disallow (Inherited)</>';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
@@ -17,9 +20,9 @@
|
||||
* 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\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use App\Services\Misc\GitVersionInfo;
|
||||
use Shivas\VersioningBundle\Service\VersionManagerInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
@@ -27,25 +30,16 @@ use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand('partdb:version|app:version', 'Shows the currently installed version of Part-DB.')]
|
||||
class VersionCommand extends Command
|
||||
{
|
||||
protected static $defaultName = 'partdb:version|app:version';
|
||||
|
||||
protected VersionManagerInterface $versionManager;
|
||||
protected GitVersionInfo $gitVersionInfo;
|
||||
|
||||
public function __construct(VersionManagerInterface $versionManager, GitVersionInfo $gitVersionInfo)
|
||||
public function __construct(protected VersionManagerInterface $versionManager, protected GitVersionInfo $gitVersionInfo)
|
||||
{
|
||||
$this->versionManager = $versionManager;
|
||||
$this->gitVersionInfo = $gitVersionInfo;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Shows the currently installed version of Part-DB.')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
@@ -66,6 +60,6 @@ class VersionCommand extends Command
|
||||
$io->info('OS: '. php_uname());
|
||||
$io->info('PHP extension: '. implode(', ', get_loaded_extensions()));
|
||||
|
||||
return 0;
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,9 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
||||
/**
|
||||
* @Route("/attachment_type")
|
||||
* @see \App\Tests\Controller\AdminPages\AttachmentTypeControllerTest
|
||||
*/
|
||||
#[Route(path: '/attachment_type')]
|
||||
class AttachmentTypeController extends BaseAdminController
|
||||
{
|
||||
protected string $entity_class = AttachmentType::class;
|
||||
@@ -48,44 +49,34 @@ class AttachmentTypeController extends BaseAdminController
|
||||
protected string $attachment_class = AttachmentTypeAttachment::class;
|
||||
protected ?string $parameter_class = AttachmentTypeParameter::class;
|
||||
|
||||
/**
|
||||
* @Route("/{id}", name="attachment_type_delete", methods={"DELETE"})
|
||||
*/
|
||||
#[Route(path: '/{id}', name: 'attachment_type_delete', methods: ['DELETE'])]
|
||||
public function delete(Request $request, AttachmentType $entity, StructuralElementRecursionHelper $recursionHelper): RedirectResponse
|
||||
{
|
||||
return $this->_delete($request, $entity, $recursionHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/edit/{timestamp}", requirements={"id"="\d+"}, name="attachment_type_edit")
|
||||
* @Route("/{id}", requirements={"id"="\d+"})
|
||||
*/
|
||||
#[Route(path: '/{id}/edit/{timestamp}', requirements: ['id' => '\d+'], name: 'attachment_type_edit')]
|
||||
#[Route(path: '/{id}', requirements: ['id' => '\d+'])]
|
||||
public function edit(AttachmentType $entity, Request $request, EntityManagerInterface $em, ?string $timestamp = null): Response
|
||||
{
|
||||
return $this->_edit($entity, $request, $em, $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/new", name="attachment_type_new")
|
||||
* @Route("/{id}/clone", name="attachment_type_clone")
|
||||
* @Route("/")
|
||||
*/
|
||||
#[Route(path: '/new', name: 'attachment_type_new')]
|
||||
#[Route(path: '/{id}/clone', name: 'attachment_type_clone')]
|
||||
#[Route(path: '/')]
|
||||
public function new(Request $request, EntityManagerInterface $em, EntityImporter $importer, ?AttachmentType $entity = null): Response
|
||||
{
|
||||
return $this->_new($request, $em, $importer, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/export", name="attachment_type_export_all")
|
||||
*/
|
||||
#[Route(path: '/export', name: 'attachment_type_export_all')]
|
||||
public function exportAll(EntityManagerInterface $em, EntityExporter $exporter, Request $request): Response
|
||||
{
|
||||
return $this->_exportAll($em, $exporter, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/export", name="attachment_type_export")
|
||||
*/
|
||||
#[Route(path: '/{id}/export', name: 'attachment_type_export')]
|
||||
public function exportEntity(AttachmentType $entity, EntityExporter $exporter, Request $request): Response
|
||||
{
|
||||
return $this->_exportEntity($entity, $exporter, $request);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user