44
55import argparse
66from dataclasses import dataclass , field
7- from typing import List , Optional
7+ from typing import List , Optional , Set
88
99# Category page titles of the target item types (see opensemantic.base.v1).
1010USER_CATEGORY = "Category:OSWd9aa0bca9b0040d8af6f5c091bf9eec7"
1717# All are standard MediaWiki groups, so this is not a per-instance skip-list.
1818SYSTEM_GROUPS = ["bot" , "sysop" , "bureaucrat" , "interface-admin" ]
1919
20+ # User fields the script must never write and must remove from existing items
21+ # (data protection).
22+ PROTECTED_FIELDS = ("employment_contract_status" ,)
23+
2024
2125@dataclass
2226class SyncConfig :
@@ -25,16 +29,30 @@ class SyncConfig:
2529 domain : Optional [str ] = None
2630 cred_filepath : Optional [str ] = None
2731 dry_run : bool = False
28- assume_yes : bool = False
32+ auto_apply : bool = False
2933 limit : Optional [int ] = None
34+ include_orcid : bool = True
3035 include_non_orcid : bool = True
3136 exclude_bot_group : bool = True
3237 exclude_system_usernames : bool = True
3338 create_redirects : bool = True
34- link_organizations : bool = True
39+ # Optional enrichment beyond core identity, opt-in (off by default).
40+ # Email is not optional: it is always attempted, and missing emails are
41+ # reported as warnings rather than failing the run.
42+ include_websites : bool = False
43+ link_organizations : bool = False
3544 orcid_api_base : str = ORCID_API_BASE_DEFAULT
3645 excluded_groups : List [str ] = field (default_factory = lambda : list (SYSTEM_GROUPS ))
3746
47+ def enabled_optional_fields (self ) -> Set [str ]:
48+ """Reconcile field names for the enabled optional data."""
49+ enabled : Set [str ] = set ()
50+ if self .include_websites :
51+ enabled .add ("websites" )
52+ if self .link_organizations :
53+ enabled .add ("organizations" )
54+ return enabled
55+
3856
3957def build_arg_parser () -> argparse .ArgumentParser :
4058 """Build the argument parser used by the example wrapper."""
@@ -53,10 +71,10 @@ def build_arg_parser() -> argparse.ArgumentParser:
5371 help = "Show the preview only; do not write anything." ,
5472 )
5573 parser .add_argument (
56- "--yes " ,
57- dest = "assume_yes " ,
74+ "--auto-apply " ,
75+ dest = "auto_apply " ,
5876 action = "store_true" ,
59- help = "Non-interactive: apply new items and gap-fills, keep existing on conflicts." ,
77+ help = "Non-interactive: apply creates, gap-fills and removals; keep existing on conflicts." ,
6078 )
6179 parser .add_argument (
6280 "--limit" ,
@@ -70,24 +88,36 @@ def build_arg_parser() -> argparse.ArgumentParser:
7088 help = "Do not create User: redirect pages." ,
7189 )
7290 parser .add_argument (
73- "--no-organizations " ,
74- dest = "link_organizations " ,
75- action = "store_false " ,
76- help = "Do not resolve or link ORCID affiliations to Organization items ." ,
91+ "--with-websites " ,
92+ dest = "include_websites " ,
93+ action = "store_true " ,
94+ help = "Also store ORCID researcher URLs on the user item (opt-in) ." ,
7795 )
7896 parser .add_argument (
79- "--include-non-orcid " ,
80- dest = "include_non_orcid " ,
97+ "--with-organizations " ,
98+ dest = "link_organizations " ,
8199 action = "store_true" ,
82- default = True ,
83- help = "Also sync non-bot accounts without an ORCID username (default)." ,
100+ help = "Also resolve ORCID affiliations to Organization items and link them." ,
84101 )
85102 parser .add_argument (
103+ "--with-extras" ,
104+ dest = "with_extras" ,
105+ action = "store_true" ,
106+ help = "Enable all optional data: websites and organizations." ,
107+ )
108+ account_scope = parser .add_mutually_exclusive_group ()
109+ account_scope .add_argument (
86110 "--orcid-only" ,
87111 dest = "include_non_orcid" ,
88112 action = "store_false" ,
89113 help = "Sync only accounts whose username is an ORCID iD." ,
90114 )
115+ account_scope .add_argument (
116+ "--mw-only" ,
117+ dest = "include_orcid" ,
118+ action = "store_false" ,
119+ help = "Sync only non-ORCID (MediaWiki-native) accounts." ,
120+ )
91121 parser .add_argument (
92122 "--include-system" ,
93123 dest = "exclude_system_usernames" ,
@@ -104,10 +134,12 @@ def config_from_args(argv: Optional[List[str]] = None) -> SyncConfig:
104134 domain = args .domain ,
105135 cred_filepath = args .cred_filepath ,
106136 dry_run = args .dry_run ,
107- assume_yes = args .assume_yes ,
137+ auto_apply = args .auto_apply ,
108138 limit = args .limit ,
139+ include_orcid = args .include_orcid ,
109140 include_non_orcid = args .include_non_orcid ,
110141 exclude_system_usernames = args .exclude_system_usernames ,
111142 create_redirects = args .create_redirects ,
112- link_organizations = args .link_organizations ,
143+ include_websites = args .include_websites or args .with_extras ,
144+ link_organizations = args .link_organizations or args .with_extras ,
113145 )
0 commit comments