diff --git a/gitea-issues/project_config.py b/gitea-issues/project_config.py index 177dfd6..eafebe9 100644 --- a/gitea-issues/project_config.py +++ b/gitea-issues/project_config.py @@ -107,8 +107,37 @@ def list_project_ids() -> list[str]: return [d.name for d in projects_dir.iterdir() if d.is_dir() and (d / "conf.json").is_file()] +def _normalize_conf_to_addresses(auth_to: object) -> set[str]: + """Return set of normalized (lowercase) email addresses from authorized_emails.to. + Supports: str (single address), list of str, or list of dict with env keys (e.g. test, pprod, prod). + Address pattern AI..@4nkweb.com; project_id and env may be uppercase.""" + out: set[str] = set() + if not auth_to: + return out + if isinstance(auth_to, str): + a = auth_to.strip().lower() + if a: + out.add(a) + return out + if isinstance(auth_to, list): + for item in auth_to: + if isinstance(item, str): + a = item.strip().lower() + if a: + out.add(a) + elif isinstance(item, dict): + for v in item.values(): + if isinstance(v, str): + a = v.strip().lower() + if a: + out.add(a) + return out + + def resolve_project_id_by_email_to(to_address: str) -> str | None: - """Find project id whose tickets.authorized_emails.to matches the given address (case-insensitive).""" + """Find project id whose tickets.authorized_emails.to matches the given address (case-insensitive). + authorized_emails.to may be a single string or a list of objects { test, pprod, prod } with addresses + AI..@4nkweb.com (project_id and env may be uppercase).""" if not to_address or not to_address.strip(): return None to_normalized = to_address.strip().lower() @@ -121,8 +150,8 @@ def resolve_project_id_by_email_to(to_address: str) -> str | None: continue tickets = conf.get("tickets") or {} auth = tickets.get("authorized_emails") or {} - conf_to = (auth.get("to") or "").strip().lower() - if conf_to == to_normalized: + conf_to_set = _normalize_conf_to_addresses(auth.get("to")) + if to_normalized in conf_to_set: return pid return None diff --git a/projects/README.md b/projects/README.md index dbae473..a6dd0a1 100644 --- a/projects/README.md +++ b/projects/README.md @@ -35,7 +35,7 @@ One JSON file per project: `projects//conf.json` (e.g. `projects/lecoffreio/ | `version.splash_app_name` | no | App name used in splash message template | | `mail` | no | Mail/imap bridge config | | `git` | no | Git hosting: `wiki_url`, `token_file` (path relative to repo root for token file). Ticketing URL is under `tickets`, not `git`. | -| `tickets` | no | Ticketing: `ticketing_url` (Gitea issues URL), `authorized_emails` (`to`: alias, `from`: list of allowed sender addresses for mail-based ticketing). The **to** address is used to resolve the project id when processing mails. See projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md. | +| `tickets` | no | Ticketing: `ticketing_url` (Gitea issues URL), `authorized_emails` (`to`: alias or list of env-keyed objects, `from`: list of allowed sender addresses). **to** resolves the project id when processing mails. It may be a single string or a list of one object with env keys: `[{ "test": "AI..TEST@4nkweb.com", "pprod": "...", "prod": "..." }]`. Pattern: `AI..@4nkweb.com` (`project_id` and `env` may be uppercase). See projects/ia_dev/docs/TICKETS_SPOOL_FORMAT.md. | The API token for ai_working_help is **not** in conf.json. It is found by scanning all projects and all envs (as described above): each file `projects//.secrets//ia_token` is read and the Bearer is compared to the file content or to (file content + env). Token value is **base** + **env**; **env** is the environment name (test, pprod, prod), to be adapted per environment. The first match gives project id and env. diff --git a/projects/algo/conf.json b/projects/algo/conf.json index bbc04cb..e2247da 100644 --- a/projects/algo/conf.json +++ b/projects/algo/conf.json @@ -30,7 +30,13 @@ "tickets": { "ticketing_url": "https://git.4nkweb.com/nicolas.cantu/algo/issues", "authorized_emails": { - "to": "ai.support.algo@4nkweb.com", + "to": [ + { + "test": "AI.ALGO.TEST@4nkweb.com", + "pprod": "AI.ALGO.PPROD@4nkweb.com", + "prod": "AI.ALGO.PROD@4nkweb.com" + } + ], "from": [] } } diff --git a/projects/enso/conf.json b/projects/enso/conf.json index 6ca95ae..a5ad168 100644 --- a/projects/enso/conf.json +++ b/projects/enso/conf.json @@ -20,7 +20,6 @@ "splash_app_name": "enso" }, "mail": { - "email": "ai.support.enso@4nkweb.com", "imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env" }, "git": { @@ -30,7 +29,13 @@ "tickets": { "ticketing_url": "https://git.4nkweb.com/nicolas.cantu/enso/issues", "authorized_emails": { - "to": "ai.support.enso@4nkweb.com", + "to": [ + { + "test": "AI.ENSO.TEST@4nkweb.com", + "pprod": "AI.ENSO.PPROD@4nkweb.com", + "prod": "AI.ENSO.PROD@4nkweb.com" + } + ], "from": [] } } diff --git a/projects/ia_dev/conf.json b/projects/ia_dev/conf.json index 63f0029..b571558 100644 --- a/projects/ia_dev/conf.json +++ b/projects/ia_dev/conf.json @@ -1,8 +1,7 @@ { "id": "ia_dev", "name": "ia_dev", - "project_path": "../", - "base_path": "ia_dev", + "project_path": "home/desk/code/ia_dev", "build_dirs": [], "deploy": {}, "version": { @@ -10,7 +9,6 @@ "splash_app_name": "ia_dev" }, "mail": { - "email": "ai.support.ia_dev@4nkweb.com", "imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env" }, "git": { @@ -20,7 +18,13 @@ "tickets": { "ticketing_url": "https://git.4nkweb.com/4nk/ia_dev/issues", "authorized_emails": { - "to": "ai.support.ia_dev@4nkweb.com", + "to": [ + { + "test": "AI.IA_DEV.TEST@4nkweb.com", + "pprod": "AI.IA_DEV.PPROD@4nkweb.com", + "prod": "AI.IA_DEV.PROD@4nkweb.com" + } + ], "from": ["nicolas.cantu@pm.me"] } } diff --git a/projects/lecoffreio/conf.json b/projects/lecoffreio/conf.json index 7089542..a48f2f0 100644 --- a/projects/lecoffreio/conf.json +++ b/projects/lecoffreio/conf.json @@ -30,7 +30,13 @@ "tickets": { "ticketing_url": "https://git.4nkweb.com/4nk/lecoffre_ng/issues", "authorized_emails": { - "to": "ai.support.lecoffreio@4nkweb.com", + "to": [ + { + "test": "AI.LECOFFREIO.TEST@4nkweb.com", + "pprod": "AI.LECOFFREIO.PPROD@4nkweb.com", + "prod": "AI.LECOFFREIO.PROD@4nkweb.com" + } + ], "from": [ "laurence@lecoffre.io", "gwendal@lecoffre.io"