# Qual: Correct language detection in moderation workflow
Fix "TypeError: franc is not a function"
- Converting language detection to an async function
- Adding Scottish language detection (locally, an English sentence was detected as Scottish)
Co-authored-by: Alexandre SPANGARO <alexandre.spangaro@gmail.com>
* Merging company children on company merge
BugFix : When we merge two companies with children companies linked to them, we loose the children of the origin (incoming) company.
This approach allows children to be merged as well
* Remove orphan translation
* Update societe.class.php
---------
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
The AI module currently has no declared rights ($this->rights stays
empty), so per-user/group attribution of "who is allowed to talk to
the LLM" is not possible. Assistant access is gated only by
isModEnabled('ai'), meaning any authenticated user on an AI-enabled
install can send organisational data to the configured LLM provider
-- which is a GDPR / EU AI Act concern (see issue #38331).
This patch introduces ONE proper Dolibarr right that admins can
attribute per user/group via the standard permission UI
(Users -> Permissions):
ai/assistant/use -> right to use the AI Assistant page
NOT granted by default; admins must
explicitly assign it to authorized users
Per the feedback from @sonikf and @eldy on PR #38312:
- Setup access intentionally stays a hard-coded $user->admin check.
The technical setup of the AI module (API keys, provider URLs) is
an admin task in line with how every other Dolibarr module is
configured -- a dedicated 'ai/setup/write' right would only
duplicate responsibility that admins already hold.
- ai/assistant/use defaults to OFF (not granted) so that, on a
fresh install or after enabling the module, no user can talk to
the LLM until the admin explicitly authorises them. This matches
the EU AI Act expectation that AI usage is an opt-in per-user
decision owned by the GDPR DPO / AI module DPA.
Access checks added:
- htdocs/ai/assistant/index.php
+ if (!$user->hasRight('ai','assistant','use')) accessforbidden();
Added after the existing isModEnabled('ai') / AI_MCP_ENABLED gate.
- htdocs/ai/assistant/parse_intent.php
+ if (!$user->hasRight('ai','assistant','use')) accessforbidden();
Defence in depth: the AJAX endpoint that actually talks to the LLM
cannot be reached by a user who lacks the right, even via direct
call bypassing the Assistant page.
- htdocs/ai/admin/setup.php
Unchanged behaviour: $user->admin check stays (just a comment
clarifying the reason).
The right is declared between the existing MODULEBUILDER PERMISSIONS
placeholders in modAi.class.php so the standard right-installation
flow applies: after applying this change, administrators must
disable/re-enable the AI module once to register the new right in
llx_rights_def (existing Dolibarr mechanism, no migration script
needed).
Tested:
- Fresh non-admin user (no extra right granted) -> Assistant page
shows accessforbidden; parse_intent.php also blocks direct call.
- Same user with 'ai/assistant/use' granted by an admin ->
Assistant accessible, LLM round-trip works.
- Admin user -> Assistant accessible transparently (admins hold
every declared right by definition); Setup accessible via the
unchanged $user->admin check.
- Module disabled -> both still blocked by the existing
isModEnabled gate.
Refs: #38331 (EU AI Act / GDPR for the AI module).
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
* Fix inverted conf
* add show discount amout on PDF conf for einstein
* Add conf order granularity
---------
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
GET /api/index.php/members/{id}/subscriptions returned the raw
Subscription object fields (dateh, datef, note_public, amount) while
POST /api/index.php/members/{id}/subscriptions takes start_date,
end_date, amount, label. A client that fetches existing subscriptions
to push them back has to translate the field names by hand.
Per @eldy review on PR #38556, address this with the renaming that
fits the rest of the codebase:
- Add date_start / date_end aliases on the Subscription class. The
date_start / date_end naming convention is already used by other
objects (task, expense, holiday), so the alias matches the existing
contract instead of inventing a new pair of names.
- Do not introduce a 'label' alias. note_public is already the
documented field on v24; declare it as a real property so phpstan
stops flagging the dynamic-property write.
- _cleanObjectDatas on the Subscription branch now sets only
date_start and date_end. note_public is left as the existing
property name. dateh / datef stay populated for backward
compatibility with existing consumers.
Develop-branch version of PR #38556 (closed).
Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
# Fix: Update comment moderation logic
Inspired by #38450 to help fix/complete the moderation script,
this updates the moderation script to:
- Add language detection for non-English comments
- Implement profanity filtering
- Check for off-topic content
- Improve forbidden link detection
- Add owner exemption logic
- Enhance error handling and logging
- Add a message indicating why the comment was deleted.
*To configure the moderation lists:*
- Go to repository Settings > Secrets > Actions
- Add `MODERATION_PROFANITY` secret containing a JSON array of terms
- Add `MODERATION_OFFTOPIC` secret containing a JSON array of phrases
- Example format for each: `["term1","term2","term3"]`
Resources for priming the PROFANITY and OFFTOPIC lists:
- https://www.cs.cmu.edu/~biglou/resources/ (first link)
- https://github.com/OOPSpam/spam-words/blob/main/spam-words-EN.txt
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
It was asked to me to fix the head of main projects table list
Without adding thead's markups it's impossible to achieve this in css, because the're 2 tr head's lines
* TODO
* Add test on server port for smtp
---------
Co-authored-by: Hystepik <lmarcouiller@dolicloud.com>
Co-authored-by: Alexandre SPANGARO <alexandre.spangaro@gmail.com>
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
* Fix langs cache reload spam
* Fix langs cache reload spam
* Fix UI font size auto resize
* Patch UI for memo and add setup options
* remove useless var
* fix var type
* fix php stan error
* fix php stan error
* fix php stan error
The modules list is a setup hub but it never declares its own menu
context, so loadMenu in core/menus/standard/eldy_menu.php falls back
to whatever value is still in $_SESSION["mainmenu"]. After opening
a module's config page the session keeps that module's mainmenu;
clicking "Back to list of modules" then leaves the previous module
highlighted on the list, and clicking the gear icon of another
module inherits the same stale value until that next page sets its
own context.
Force $_GET["mainmenu"] = "home" at the very top of modules.php when
the caller did not provide a mainmenu, before main.inc.php is loaded.
loadMenu then sees the GET value, writes "home" into the session and
the top menu reflects the setup hub. An explicit mainmenu in the URL
(for example the "?mainmenu=home" links emitted by admin/index.php
and the SetupIsReadyForUse string in modules.php itself) keeps full
precedence.
Reported by @ccrica.
Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
`getOnlineSignatureUrl()` ends each public signature URL with
`&securekey=` followed by the output of `dol_hash(..., '0')`. With the
default `MAIN_SECURITY_HASH_ALGO = password_hash`, that output is a
bcrypt string whose alphabet is `[./A-Za-z0-9]`, so a non-trivial share
of generated URLs legitimately end with `.` or `/`.
Gmail and several mobile mail clients autolink plain-text URLs but
drop trailing punctuation, so the recipient clicks on a URL with the
last character missing and gets a securekey mismatch error
(`Bad value for securitykey`). The user-facing symptom is exactly the
one in #31464.
When multicompany is enabled, the URL already ends with `&entity=N`,
which sidesteps the issue. For installations without multicompany,
append a stable trailing `&_=1` so the URL never ends with the hash.
The receiver in `public/onlinesign/newonlinesign.php` does not read
`_`, only `source`, `ref`, `securekey` and (when multicompany) `entity`,
so adding the parameter has no behavior impact and existing links keep
verifying as before. Only the real URL (mode 0) is affected, not the
mode 1 preview shown in the admin setup.
Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
The minimum-price guard on the customer invoice, customer order and
customer proposal forms compares the entered unit price to the
product's price_min. When the document is in a foreign currency the
unit price is provided in the foreign currency ($pu_ht_devise), so
it must first be converted back to the base (company) currency before
the comparison.
card.php was multiplying by $currency_tx:
$pu_equivalent = (float) $pu_ht_devise * $currency_tx;
but multicurrency_tx is defined as 'units of foreign currency per
1 unit of base', exactly as price.lib.php uses it
(calcul_price_total at line 181):
$pu = $pu_devise / $multicurrency_tx;
With the reporter's example (1 MXN = 0.055 USD, so tx = 0.055,
product min price = 1000 MXN, entered 55 USD), the wrong direction
gives 55 * 0.055 = 3.025 MXN < 1000 MXN and the form errors out with
'CantBeLessThanMinPrice', even though 55 USD is exactly 1000 MXN.
Dividing yields 55 / 0.055 = 1000 MXN and the check passes.
Mirror calcul_price_total's direction at all four invoice sites
(htdocs/compta/facture/card.php lines 2503/2506 and 2684/2687) plus
the corresponding sites in htdocs/commande/card.php and
htdocs/comm/propal/card.php. Documents in the base currency
($pu_ht_devise empty) are not affected because the conversion
branch is gated on $pu_ht_devise being non-empty.
Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>