@@ -18,25 +18,48 @@ const (
1818 SoftaculousScriptIDWordPress = 26
1919)
2020
21- type SoftaculousScript struct {
22- AdminEmail string `url:"admin_email"`
23- AdminPassword string `url:"admin_pass"`
24- AdminUsername string `url:"admin_username"`
25- AutoUpgrade bool `url:"en_auto_upgrade"`
26- AutoUpgradePlugins bool `url:"auto_upgrade_plugins"`
27- AutoUpgradeThemes bool `url:"auto_upgrade_plugins"`
28- DatabaseName string `url:"softdb"`
29- DatabasePrefix string `url:"dbprefix"` // optional
30- Directory string `url:"softdirectory"`
31- Domain string `url:"softdomain"`
32- Language string `url:"language"`
33- NotifyOnInstall bool `url:"noemail"`
34- NotifyOnUpdate bool `url:"disable_notify_update"`
35- OverwriteExisting bool `url:"overwrite_existing"`
36- Protocol string `url:"softproto"`
37- SiteDescription string `url:"site_desc"`
38- SiteName string `json:"site_name"`
39- }
21+ type (
22+ SoftaculousInstallation struct {
23+ ID string `json:"insid"`
24+ ScriptID int `json:"sid"`
25+ Ver string `json:"ver"`
26+ ITime int `json:"itime"`
27+ Path string `json:"softpath"`
28+ URL string `json:"softurl"`
29+ Domain string `json:"softdomain"`
30+ FileIndex any `json:"fileindex"` // Sometimes a string slice, other times a map.
31+ SiteName string `json:"site_name"`
32+ SoftDB string `json:"softdb"`
33+ SoftDBuser string `json:"softdbuser"`
34+ SoftDBhost string `json:"softdbhost"`
35+ SoftDBpass string `json:"softdbpass"`
36+ DBCreated bool `json:"dbcreated"`
37+ DBPrefix string `json:"dbprefix"`
38+ ImportSrc string `json:"import_src"`
39+ DisplaySoftDBPass string `json:"display_softdbpass"`
40+ ScriptName string `json:"script_name"`
41+ }
42+
43+ SoftaculousScript struct {
44+ AdminEmail string `url:"admin_email"`
45+ AdminPassword string `url:"admin_pass"`
46+ AdminUsername string `url:"admin_username"`
47+ AutoUpgrade bool `url:"en_auto_upgrade"`
48+ AutoUpgradePlugins bool `url:"auto_upgrade_plugins"`
49+ AutoUpgradeThemes bool `url:"auto_upgrade_plugins"`
50+ DatabaseName string `url:"softdb"`
51+ DatabasePrefix string `url:"dbprefix"` // Optional.
52+ Directory string `url:"softdirectory"`
53+ Domain string `url:"softdomain"`
54+ Language string `url:"language"`
55+ NotifyOnInstall bool `url:"noemail"`
56+ NotifyOnUpdate bool `url:"disable_notify_update"`
57+ OverwriteExisting bool `url:"overwrite_existing"`
58+ Protocol string `url:"softproto"`
59+ SiteDescription string `url:"site_desc"`
60+ SiteName string `json:"site_name"`
61+ }
62+ )
4063
4164func (s * SoftaculousScript ) Parse () (url.Values , error ) {
4265 if err := s .Validate (); err != nil {
@@ -160,7 +183,7 @@ func (c *UserContext) SoftaculousInstallScript(script *SoftaculousScript, script
160183
161184 body .Set ("softsubmit" , "1" )
162185
163- // Softaculous requires a genuine session ID
186+ // Softaculous requires a genuine session ID.
164187 if c .sessionID == "" {
165188 if err = c .CreateSession (); err != nil {
166189 return fmt .Errorf ("failed to create user session: %w" , err )
@@ -177,3 +200,84 @@ func (c *UserContext) SoftaculousInstallScript(script *SoftaculousScript, script
177200
178201 return nil
179202}
203+
204+ // SoftaculousListInstallations lists all installations accessible to the authenticated user.
205+ func (c * UserContext ) SoftaculousListInstallations () ([]* SoftaculousInstallation , error ) {
206+ response := struct {
207+ Error map [string ]string `json:"error"`
208+ Installations map [string ]map [string ]* SoftaculousInstallation `json:"installations"`
209+ }{
210+ Error : make (map [string ]string ),
211+ Installations : make (map [string ]map [string ]* SoftaculousInstallation ),
212+ }
213+
214+ // Softaculous requires a genuine session ID
215+ if c .sessionID == "" {
216+ if err := c .CreateSession (); err != nil {
217+ return nil , fmt .Errorf ("failed to create user session: %w" , err )
218+ }
219+ }
220+
221+ if _ , err := c .makeRequestOld (http .MethodPost , "PLUGINS/softaculous/index.raw?act=installations&api=json" , nil , & response ); err != nil {
222+ return nil , err
223+ }
224+
225+ if len (response .Error ) > 0 {
226+ return nil , fmt .Errorf ("failed to uninstall script: %v" , response .Error )
227+ }
228+
229+ installations := make ([]* SoftaculousInstallation , 0 , len (response .Installations ))
230+ for _ , userInstallations := range response .Installations {
231+ for _ , installation := range userInstallations {
232+ installations = append (installations , installation )
233+ }
234+ }
235+
236+ return installations , nil
237+ }
238+
239+ // SoftaculousUninstallScript calls Softaculous's install script API endpoint.
240+ //
241+ // Docs: https://www.softaculous.com/docs/api/remote-api/#remove-an-installed-script
242+ func (c * UserContext ) SoftaculousUninstallScript (installID string , deleteFiles bool , deleteDB bool ) error {
243+ if installID == "" {
244+ return errors .New ("missing install id" )
245+ }
246+
247+ response := struct {
248+ Error map [string ]string `json:"error"`
249+ }{
250+ Error : make (map [string ]string ),
251+ }
252+
253+ body := url.Values {}
254+ body .Set ("noemail" , "1" )
255+ body .Set ("removeins" , "1" )
256+
257+ if deleteFiles {
258+ body .Set ("remove_dir" , "1" )
259+ body .Set ("remove_datadir" , "1" )
260+ }
261+
262+ if deleteDB {
263+ body .Set ("remove_db" , "1" )
264+ body .Set ("remove_dbuser" , "1" )
265+ }
266+
267+ // Softaculous requires a genuine session ID
268+ if c .sessionID == "" {
269+ if err := c .CreateSession (); err != nil {
270+ return fmt .Errorf ("failed to create user session: %w" , err )
271+ }
272+ }
273+
274+ if _ , err := c .makeRequestOld (http .MethodPost , "PLUGINS/softaculous/index.raw?act=remove&insid=" + installID + "&api=json" , body , & response ); err != nil {
275+ return err
276+ }
277+
278+ if len (response .Error ) > 0 {
279+ return fmt .Errorf ("failed to uninstall script: %v" , response .Error )
280+ }
281+
282+ return nil
283+ }
0 commit comments