2323# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2424# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525
26+ from __future__ import annotations
2627import json
2728from typing import Union
2829from ansible_collections .nextcloud .admin .plugins .module_utils .exceptions import (
2930 OccExceptions ,
3031 AppExceptions ,
32+ PhpInlineExceptions ,
33+ PhpResultJsonException ,
34+ AppPSR4InfosNotReadable ,
35+ AppPSR4InfosUnavailable ,
3136)
32- from ansible_collections .nextcloud .admin .plugins .module_utils .nc_tools import run_occ # type: ignore
37+ from ansible_collections .nextcloud .admin .plugins .module_utils .nc_tools import run_occ , run_php_inline # type: ignore
3338
3439
3540class app :
36- _update_version_available = "unchecked "
41+ _update_version_available = ""
3742 _path = None
43+ _autoloaded_infos = None
44+ _current_settings = None
3845
3946 def __init__ (self , module , app_name : str ):
4047 self .module = module
@@ -62,14 +69,14 @@ def __init__(self, module, app_name: str):
6269
6370 @property
6471 def update_version_available (self ) -> Union [str , None ]:
65- if self ._update_version_available == "unchecked " :
72+ if self ._update_version_available == "" :
6673 _check_app_update = run_occ (
6774 self .module , ["app:update" , "--showonly" , self .app_name ]
6875 )[1 ]
69- if _check_app_update != "" :
70- result = _check_app_update .split ()[- 1 ]
71- else :
76+ if _check_app_update == "" or "up-to-date" in _check_app_update :
7277 result = None
78+ else :
79+ result = _check_app_update .split ()[- 1 ]
7380 self ._update_version_available = result
7481 return self ._update_version_available
7582
@@ -84,18 +91,105 @@ def path(self) -> str:
8491 self ._path = result
8592 return self ._path
8693
87- def infos (self ):
88- result = dict (
89- name = self .app_name ,
94+ def get_facts (self ) -> dict [str , any ]:
95+ facts = dict (
9096 state = self .state ,
9197 is_shipped = self .shipped ,
9298 )
9399 if self .state != "absent" :
94- result .update (update_available = self .update_available )
95- result .update (version = self .version )
96- result .update (version_available = self .update_version_available )
97- result .update (app_path = self .path )
98- return result
100+ facts .update (update_available = self .update_available )
101+ facts .update (version = self .version )
102+ facts .update (version_available = self .update_version_available )
103+ facts .update (app_path = self .path )
104+ return facts
105+
106+ @property
107+ def autoloaded_infos (self ) -> dict :
108+ if self ._autoloaded_infos is None :
109+ self ._autoloaded_infos = self ._get_autoloaded_infos ()
110+ return self ._autoloaded_infos
111+
112+ @property
113+ def infos (self ) -> dict :
114+ return self .autoloaded_infos .get ("appInfo" )
115+
116+ @property
117+ def default_settings (self ) -> dict :
118+ return self .autoloaded_infos ["settings" ]
119+
120+ def _get_autoloaded_infos (self ) -> dict :
121+ """
122+ Run inline php script that use the server autoloading system to inspect the app.
123+ return a dict that contains keys: appInfo, settings.
124+ setting can contain admin and personal default settings if any is available.
125+ """
126+ php_script = f"""
127+ $appId = '{ self .app_name } ';
128+ // Get App PSR-4 infos
129+ $appManager = \\ OC::$server->getAppManager();
130+ $appInfo = $appManager->getAppInfo($appId);
131+ $result = array(
132+ 'appInfo' => $appInfo,
133+ 'settings' => array()
134+ );
135+ foreach (['admin', 'personal'] as $section) {{
136+ if (!empty($appInfo['settings'][$section])) {{
137+ $className = $appInfo['settings'][$section][0];
138+ if (class_exists($className)) {{
139+ $settingsInstance = \\ OC::$server->get($className);
140+ $form = $settingsInstance->getForm();
141+
142+ if (method_exists($form, 'getParams')) {{
143+ $result['settings'][$section] = $form->getParams();
144+ }} else {{
145+ $result['settings'][$section] = 'Unavailable';
146+ }}
147+ }} else {{
148+ $result['settings'][$section] = 'Settings not currently loaded';
149+ }}
150+ }}
151+ }}
152+ """
153+ try :
154+ result = run_php_inline (self .module , php_script )
155+ # force the 'settings' key to be dict if it is empty
156+ if isinstance (result ["settings" ], list ) and not result ["settings" ]:
157+ result ["settings" ] = {}
158+ return result
159+ except PhpResultJsonException as e :
160+ raise AppPSR4InfosNotReadable (app_name = self .app_name , ** e .__dict__ )
161+ except PhpInlineExceptions as e :
162+ raise AppPSR4InfosUnavailable (app_name = self .app_name , ** e .__dict__ )
163+
164+ @property
165+ def current_settings (self ) -> dict [str , any ]:
166+ if self ._current_settings is None :
167+ self ._current_settings = self ._get_current_settings ()
168+ return self ._current_settings
169+
170+ def _get_current_settings (self ) -> dict [str , any ]:
171+ """
172+ Returns the current configured settings for the app, using `occ config:list <app>`.
173+ """
174+ non_informative = ["installed_version" , "enabled" , "types" ]
175+ try :
176+ raw_config = run_occ (self .module , ["config:list" , self .app_name ])[1 ]
177+ occ_config = json .loads (raw_config ).get ("apps" , {}).get (self .app_name , {})
178+ if isinstance (occ_config , list ) and not occ_config :
179+ return {}
180+ else :
181+ return {k : v for k , v in occ_config .items () if k not in non_informative }
182+ except OccExceptions as e :
183+ self .module .warn (
184+ f"Failed to get current config for { self .app_name } : { e .stderr } "
185+ )
186+ return {}
187+ except Exception as e :
188+ raise AppExceptions (
189+ msg = f"Unexpected error in reading configured values. { str (e )} " ,
190+ app_name = self .app_name ,
191+ ** e .__dict__ ,
192+ )
99193
100194 def install (self , enable : bool = True ):
101195 occ_args = ["app:install" , self .app_name ]
0 commit comments