From a80fe4ecbe6bf7bb7af3d3f4f46d7bb87834c154 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:28:45 +0100
Subject: [PATCH 01/20] [enh] New config panel

---
 config_panel.toml | 66 +++++++++++++++++++++++++++++++++++++++
 scripts/config    | 78 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+)
 create mode 100644 config_panel.toml
 create mode 100644 scripts/config

diff --git a/config_panel.toml b/config_panel.toml
new file mode 100644
index 0000000..d1b143f
--- /dev/null
+++ b/config_panel.toml
@@ -0,0 +1,66 @@
+version = "0.1"
+name = "APP configuration panel"
+
+[main]
+name = "Main configuration"
+
+    [main.config_file]
+    name = ""
+        
+        [main.config_file.warning]
+        ask = "Here you can display a warning to user."
+        type = "warning"
+        
+        [main.config_file.outgoing_email]
+        ask = "Outgoing email From"
+        type = "string"
+        help = "Email from which comes email from this app"
+        
+        [main.config_file.expiration]
+        ask = "Default expiration"
+        type = "date"
+        
+        [main.config_file.logo]
+        ask = "Outgoing email From"
+        type = "file"
+        default = ""
+        optional = true
+        help = "You should upload a CA certificate to start"
+        source="__FINALPATH__/img/logo.png"
+
+    [main.auth]
+    name = "Authentication"
+        
+        [main.auth.user]
+        ask = "Username"
+        type = "string"
+        default = ""
+        optional = true
+        pattern = "^[^/ ]+$"
+        
+        [main.auth.passphrase]
+        ask = "Password"
+        type = "password"
+        default = ""
+        optional = true
+
+        
+[advanced]
+name = "Advanced configuration"
+
+    [manual.dns]
+    name = "DNS"
+
+        [manual.dns.dns0]
+        ask = "First resolver"
+        type = "string"
+        default = ""
+        optional = true
+        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
+
+        [manual.dns.dns1]
+        ask = "Second resolver"
+        type = "string"
+        default = ""
+        optional = true
+        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
diff --git a/scripts/config b/scripts/config
new file mode 100644
index 0000000..4f6f300
--- /dev/null
+++ b/scripts/config
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+#=================================================
+# GENERIC STARTING
+#=================================================
+# IMPORT GENERIC HELPERS
+#=================================================
+
+source _common.sh
+source /usr/share/yunohost/helpers
+
+#=================================================
+# RETRIEVE ARGUMENTS
+#=================================================
+
+app=$YNH_APP_INSTANCE_NAME
+final_path=$(ynh_app_setting_get $app final_path)
+
+#=================================================
+# SPECIFIC GETTERS FOR TOML SHORT KEY
+#=================================================
+get__user() {
+    if [ -s $final_path/keys/credentials ]
+    then
+        sed -n 1p $final_path/keys/credentials 
+    fi
+}
+
+get__passphrase() {
+    if [ -s $final_path/keys/credentials ]
+    then
+        sed -n 2p $final_path/keys/credentials 
+    fi
+}
+
+
+#=================================================
+# SPECIFIC VALIDATORS FOR TOML SHORT KEYS
+#=================================================
+validate__user() {
+    [[ -n "$passphrase" && -z "$user" ]] &&
+        echo 'A Username is needed when you suggest a Password'
+}
+
+validate__passphrase() {
+    [[ -n "$user" && -z "$passphrase" ]] &&
+        echo 'A Password is needed when you suggest a Username'
+}
+
+#=================================================
+# SPECIFIC SETTERS FOR TOML SHORT KEYS
+#=================================================
+set__user() {
+    if [ -z "$user" ]
+    then
+        echo "$user\n$passphrase" > $final_path/keys/credentials 
+    else
+        echo "" > $final_path/keys/credentials
+    fi
+}
+
+set__passphrase() {
+    :
+}
+
+
+#=================================================
+# OVERWRITING APPLY STEP 
+#=================================================
+ynh_panel_apply() {
+    
+    _ynh_panel_apply
+
+    # Start vpn client
+    systemctl reload APP
+
+}
+

From 3051124936f3d74048746c60f130a7840f490844 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:38:15 +0100
Subject: [PATCH 02/20] [enh] New config panel

---
 config_panel.toml | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/config_panel.toml b/config_panel.toml
index d1b143f..406b842 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -11,14 +11,18 @@ name = "Main configuration"
         ask = "Here you can display a warning to user."
         type = "warning"
         
-        [main.config_file.outgoing_email]
+        [main.config_file.from_email]
         ask = "Outgoing email From"
         type = "string"
         help = "Email from which comes email from this app"
+        pattern = "^[^@]+@[^@]+$"
+        source = "__FINALPATH__/conf/config.php"
         
         [main.config_file.expiration]
         ask = "Default expiration"
         type = "date"
+        pattern = "^\d\d\d\d-\d\d-\d\d$"
+        source = "__FINALPATH__/conf/config.php"
         
         [main.config_file.logo]
         ask = "Outgoing email From"
@@ -48,7 +52,7 @@ name = "Main configuration"
 [advanced]
 name = "Advanced configuration"
 
-    [manual.dns]
+    [advanced.dns]
     name = "DNS"
 
         [manual.dns.dns0]

From 6718f6403eed13e2321d2fc50ecf399c707df239 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:40:15 +0100
Subject: [PATCH 03/20] [enh] Remove uneeded title

---
 config_panel.toml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/config_panel.toml b/config_panel.toml
index 406b842..03f9cf4 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -1,5 +1,4 @@
 version = "0.1"
-name = "APP configuration panel"
 
 [main]
 name = "Main configuration"

From 0864c8b525c596f5beb104a2ac6581549739d28d Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:42:27 +0100
Subject: [PATCH 04/20] [enh] Upgrade version config panel

---
 config_panel.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config_panel.toml b/config_panel.toml
index 03f9cf4..b459c71 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -1,4 +1,4 @@
-version = "0.1"
+version = "1.0"
 
 [main]
 name = "Main configuration"

From 1dc8e862a6390c812556cfd65d43f277aee39706 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:48:58 +0100
Subject: [PATCH 05/20] [enh] Some doc about config panel

---
 scripts/config | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/scripts/config b/scripts/config
index 4f6f300..bc1e6c6 100644
--- a/scripts/config
+++ b/scripts/config
@@ -1,20 +1,16 @@
 #!/bin/bash
 
-#=================================================
-# GENERIC STARTING
-#=================================================
-# IMPORT GENERIC HELPERS
-#=================================================
+# In most simple cases, you don't need a config script (or just to reload services). 
+
+# With a simple config_panel.toml, you can write in the app settings, in the 
+# upstream config file or replace complete files (logo ...).
+
+# The config scripts allows you to go further, to handle specific cases 
+# (validation of several interdependent fields, specific getter/setter for a value,
+# pre-loading of config type .cube ).
 
-source _common.sh
-source /usr/share/yunohost/helpers
 
-#=================================================
-# RETRIEVE ARGUMENTS
-#=================================================
 
-app=$YNH_APP_INSTANCE_NAME
-final_path=$(ynh_app_setting_get $app final_path)
 
 #=================================================
 # SPECIFIC GETTERS FOR TOML SHORT KEY
@@ -71,7 +67,7 @@ ynh_panel_apply() {
     
     _ynh_panel_apply
 
-    # Start vpn client
+    # Reload app service
     systemctl reload APP
 
 }

From 6431e1eaff5bf4290b7ce47f14afe597d509884f Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)" <zamentur@users.noreply.github.com>
Date: Tue, 1 Jun 2021 01:26:50 +0200
Subject: [PATCH 06/20] [enh] Update config panel example

---
 config_panel.toml | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/config_panel.toml b/config_panel.toml
index b459c71..1a0a23c 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -12,21 +12,21 @@ name = "Main configuration"
         
         [main.config_file.from_email]
         ask = "Outgoing email From"
-        type = "string"
+        type = "email"
         help = "Email from which comes email from this app"
         pattern = "^[^@]+@[^@]+$"
-        source = "__FINALPATH__/conf/config.php"
+        source = "email:__FINALPATH__/conf/config.php"
         
         [main.config_file.expiration]
         ask = "Default expiration"
         type = "date"
         pattern = "^\d\d\d\d-\d\d-\d\d$"
-        source = "__FINALPATH__/conf/config.php"
+        source = ":__FINALPATH__/conf/config.php"
         
         [main.config_file.logo]
-        ask = "Outgoing email From"
+        ask = "Logo"
         type = "file"
-        default = ""
+        accept = ".png"
         optional = true
         help = "You should upload a CA certificate to start"
         source="__FINALPATH__/img/logo.png"
@@ -37,19 +37,20 @@ name = "Main configuration"
         [main.auth.user]
         ask = "Username"
         type = "string"
-        default = ""
+        example = "camille"
         optional = true
         pattern = "^[^/ ]+$"
         
         [main.auth.passphrase]
         ask = "Password"
         type = "password"
-        default = ""
         optional = true
+        visibleIf = "user"
 
         
 [advanced]
 name = "Advanced configuration"
+collapsed = true
 
     [advanced.dns]
     name = "DNS"
@@ -57,13 +58,11 @@ name = "Advanced configuration"
         [manual.dns.dns0]
         ask = "First resolver"
         type = "string"
-        default = ""
         optional = true
         pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
 
         [manual.dns.dns1]
         ask = "Second resolver"
         type = "string"
-        default = ""
         optional = true
         pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"

From 471d9abf2b054fcf73e299988c28a65d56f34c88 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:28:45 +0100
Subject: [PATCH 07/20] [enh] New config panel

---
 config_panel.toml | 66 +++++++++++++++++++++++++++++++++++++++
 scripts/config    | 78 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+)
 create mode 100644 config_panel.toml
 create mode 100644 scripts/config

diff --git a/config_panel.toml b/config_panel.toml
new file mode 100644
index 0000000..d1b143f
--- /dev/null
+++ b/config_panel.toml
@@ -0,0 +1,66 @@
+version = "0.1"
+name = "APP configuration panel"
+
+[main]
+name = "Main configuration"
+
+    [main.config_file]
+    name = ""
+        
+        [main.config_file.warning]
+        ask = "Here you can display a warning to user."
+        type = "warning"
+        
+        [main.config_file.outgoing_email]
+        ask = "Outgoing email From"
+        type = "string"
+        help = "Email from which comes email from this app"
+        
+        [main.config_file.expiration]
+        ask = "Default expiration"
+        type = "date"
+        
+        [main.config_file.logo]
+        ask = "Outgoing email From"
+        type = "file"
+        default = ""
+        optional = true
+        help = "You should upload a CA certificate to start"
+        source="__FINALPATH__/img/logo.png"
+
+    [main.auth]
+    name = "Authentication"
+        
+        [main.auth.user]
+        ask = "Username"
+        type = "string"
+        default = ""
+        optional = true
+        pattern = "^[^/ ]+$"
+        
+        [main.auth.passphrase]
+        ask = "Password"
+        type = "password"
+        default = ""
+        optional = true
+
+        
+[advanced]
+name = "Advanced configuration"
+
+    [manual.dns]
+    name = "DNS"
+
+        [manual.dns.dns0]
+        ask = "First resolver"
+        type = "string"
+        default = ""
+        optional = true
+        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
+
+        [manual.dns.dns1]
+        ask = "Second resolver"
+        type = "string"
+        default = ""
+        optional = true
+        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
diff --git a/scripts/config b/scripts/config
new file mode 100644
index 0000000..4f6f300
--- /dev/null
+++ b/scripts/config
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+#=================================================
+# GENERIC STARTING
+#=================================================
+# IMPORT GENERIC HELPERS
+#=================================================
+
+source _common.sh
+source /usr/share/yunohost/helpers
+
+#=================================================
+# RETRIEVE ARGUMENTS
+#=================================================
+
+app=$YNH_APP_INSTANCE_NAME
+final_path=$(ynh_app_setting_get $app final_path)
+
+#=================================================
+# SPECIFIC GETTERS FOR TOML SHORT KEY
+#=================================================
+get__user() {
+    if [ -s $final_path/keys/credentials ]
+    then
+        sed -n 1p $final_path/keys/credentials 
+    fi
+}
+
+get__passphrase() {
+    if [ -s $final_path/keys/credentials ]
+    then
+        sed -n 2p $final_path/keys/credentials 
+    fi
+}
+
+
+#=================================================
+# SPECIFIC VALIDATORS FOR TOML SHORT KEYS
+#=================================================
+validate__user() {
+    [[ -n "$passphrase" && -z "$user" ]] &&
+        echo 'A Username is needed when you suggest a Password'
+}
+
+validate__passphrase() {
+    [[ -n "$user" && -z "$passphrase" ]] &&
+        echo 'A Password is needed when you suggest a Username'
+}
+
+#=================================================
+# SPECIFIC SETTERS FOR TOML SHORT KEYS
+#=================================================
+set__user() {
+    if [ -z "$user" ]
+    then
+        echo "$user\n$passphrase" > $final_path/keys/credentials 
+    else
+        echo "" > $final_path/keys/credentials
+    fi
+}
+
+set__passphrase() {
+    :
+}
+
+
+#=================================================
+# OVERWRITING APPLY STEP 
+#=================================================
+ynh_panel_apply() {
+    
+    _ynh_panel_apply
+
+    # Start vpn client
+    systemctl reload APP
+
+}
+

From 17fe3b1f26acde0592a10524522117db873d4d21 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:38:15 +0100
Subject: [PATCH 08/20] [enh] New config panel

---
 config_panel.toml | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/config_panel.toml b/config_panel.toml
index d1b143f..406b842 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -11,14 +11,18 @@ name = "Main configuration"
         ask = "Here you can display a warning to user."
         type = "warning"
         
-        [main.config_file.outgoing_email]
+        [main.config_file.from_email]
         ask = "Outgoing email From"
         type = "string"
         help = "Email from which comes email from this app"
+        pattern = "^[^@]+@[^@]+$"
+        source = "__FINALPATH__/conf/config.php"
         
         [main.config_file.expiration]
         ask = "Default expiration"
         type = "date"
+        pattern = "^\d\d\d\d-\d\d-\d\d$"
+        source = "__FINALPATH__/conf/config.php"
         
         [main.config_file.logo]
         ask = "Outgoing email From"
@@ -48,7 +52,7 @@ name = "Main configuration"
 [advanced]
 name = "Advanced configuration"
 
-    [manual.dns]
+    [advanced.dns]
     name = "DNS"
 
         [manual.dns.dns0]

From 5017bf8e0d777aed876cf7d577a5b2c7b5399fb7 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:40:15 +0100
Subject: [PATCH 09/20] [enh] Remove uneeded title

---
 config_panel.toml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/config_panel.toml b/config_panel.toml
index 406b842..03f9cf4 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -1,5 +1,4 @@
 version = "0.1"
-name = "APP configuration panel"
 
 [main]
 name = "Main configuration"

From 47d426be05492aa09e5d14eac47beb1b502ec93d Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:42:27 +0100
Subject: [PATCH 10/20] [enh] Upgrade version config panel

---
 config_panel.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config_panel.toml b/config_panel.toml
index 03f9cf4..b459c71 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -1,4 +1,4 @@
-version = "0.1"
+version = "1.0"
 
 [main]
 name = "Main configuration"

From 01d79fbaeebce398a400c9220a451cb6912ddfe3 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 3 Nov 2020 21:48:58 +0100
Subject: [PATCH 11/20] [enh] Some doc about config panel

---
 scripts/config | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/scripts/config b/scripts/config
index 4f6f300..bc1e6c6 100644
--- a/scripts/config
+++ b/scripts/config
@@ -1,20 +1,16 @@
 #!/bin/bash
 
-#=================================================
-# GENERIC STARTING
-#=================================================
-# IMPORT GENERIC HELPERS
-#=================================================
+# In most simple cases, you don't need a config script (or just to reload services). 
+
+# With a simple config_panel.toml, you can write in the app settings, in the 
+# upstream config file or replace complete files (logo ...).
+
+# The config scripts allows you to go further, to handle specific cases 
+# (validation of several interdependent fields, specific getter/setter for a value,
+# pre-loading of config type .cube ).
 
-source _common.sh
-source /usr/share/yunohost/helpers
 
-#=================================================
-# RETRIEVE ARGUMENTS
-#=================================================
 
-app=$YNH_APP_INSTANCE_NAME
-final_path=$(ynh_app_setting_get $app final_path)
 
 #=================================================
 # SPECIFIC GETTERS FOR TOML SHORT KEY
@@ -71,7 +67,7 @@ ynh_panel_apply() {
     
     _ynh_panel_apply
 
-    # Start vpn client
+    # Reload app service
     systemctl reload APP
 
 }

From a58978c4e52fc08a34db6d8206d7362df0aed653 Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)" <zamentur@users.noreply.github.com>
Date: Tue, 1 Jun 2021 01:26:50 +0200
Subject: [PATCH 12/20] [enh] Update config panel example

---
 config_panel.toml | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/config_panel.toml b/config_panel.toml
index b459c71..1a0a23c 100644
--- a/config_panel.toml
+++ b/config_panel.toml
@@ -12,21 +12,21 @@ name = "Main configuration"
         
         [main.config_file.from_email]
         ask = "Outgoing email From"
-        type = "string"
+        type = "email"
         help = "Email from which comes email from this app"
         pattern = "^[^@]+@[^@]+$"
-        source = "__FINALPATH__/conf/config.php"
+        source = "email:__FINALPATH__/conf/config.php"
         
         [main.config_file.expiration]
         ask = "Default expiration"
         type = "date"
         pattern = "^\d\d\d\d-\d\d-\d\d$"
-        source = "__FINALPATH__/conf/config.php"
+        source = ":__FINALPATH__/conf/config.php"
         
         [main.config_file.logo]
-        ask = "Outgoing email From"
+        ask = "Logo"
         type = "file"
-        default = ""
+        accept = ".png"
         optional = true
         help = "You should upload a CA certificate to start"
         source="__FINALPATH__/img/logo.png"
@@ -37,19 +37,20 @@ name = "Main configuration"
         [main.auth.user]
         ask = "Username"
         type = "string"
-        default = ""
+        example = "camille"
         optional = true
         pattern = "^[^/ ]+$"
         
         [main.auth.passphrase]
         ask = "Password"
         type = "password"
-        default = ""
         optional = true
+        visibleIf = "user"
 
         
 [advanced]
 name = "Advanced configuration"
+collapsed = true
 
     [advanced.dns]
     name = "DNS"
@@ -57,13 +58,11 @@ name = "Advanced configuration"
         [manual.dns.dns0]
         ask = "First resolver"
         type = "string"
-        default = ""
         optional = true
         pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
 
         [manual.dns.dns1]
         ask = "Second resolver"
         type = "string"
-        default = ""
         optional = true
         pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"

From 62c97c223b563008b89671322f9cf3dcc73b9b84 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 28 Sep 2021 17:06:01 +0200
Subject: [PATCH 13/20] [enh] Rename to avoid bad config panel in real apps

---
 config_panel.toml | 68 -----------------------------------------------
 1 file changed, 68 deletions(-)
 delete mode 100644 config_panel.toml

diff --git a/config_panel.toml b/config_panel.toml
deleted file mode 100644
index 1a0a23c..0000000
--- a/config_panel.toml
+++ /dev/null
@@ -1,68 +0,0 @@
-version = "1.0"
-
-[main]
-name = "Main configuration"
-
-    [main.config_file]
-    name = ""
-        
-        [main.config_file.warning]
-        ask = "Here you can display a warning to user."
-        type = "warning"
-        
-        [main.config_file.from_email]
-        ask = "Outgoing email From"
-        type = "email"
-        help = "Email from which comes email from this app"
-        pattern = "^[^@]+@[^@]+$"
-        source = "email:__FINALPATH__/conf/config.php"
-        
-        [main.config_file.expiration]
-        ask = "Default expiration"
-        type = "date"
-        pattern = "^\d\d\d\d-\d\d-\d\d$"
-        source = ":__FINALPATH__/conf/config.php"
-        
-        [main.config_file.logo]
-        ask = "Logo"
-        type = "file"
-        accept = ".png"
-        optional = true
-        help = "You should upload a CA certificate to start"
-        source="__FINALPATH__/img/logo.png"
-
-    [main.auth]
-    name = "Authentication"
-        
-        [main.auth.user]
-        ask = "Username"
-        type = "string"
-        example = "camille"
-        optional = true
-        pattern = "^[^/ ]+$"
-        
-        [main.auth.passphrase]
-        ask = "Password"
-        type = "password"
-        optional = true
-        visibleIf = "user"
-
-        
-[advanced]
-name = "Advanced configuration"
-collapsed = true
-
-    [advanced.dns]
-    name = "DNS"
-
-        [manual.dns.dns0]
-        ask = "First resolver"
-        type = "string"
-        optional = true
-        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
-
-        [manual.dns.dns1]
-        ask = "Second resolver"
-        type = "string"
-        optional = true
-        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"

From 1a1a2c49898ae85404ec03c09839af2f29921b85 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Tue, 28 Sep 2021 17:07:02 +0200
Subject: [PATCH 14/20] [enh] Rename to avoid bad config panel in real apps

---
 config_panel.toml.example | 68 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 config_panel.toml.example

diff --git a/config_panel.toml.example b/config_panel.toml.example
new file mode 100644
index 0000000..1a0a23c
--- /dev/null
+++ b/config_panel.toml.example
@@ -0,0 +1,68 @@
+version = "1.0"
+
+[main]
+name = "Main configuration"
+
+    [main.config_file]
+    name = ""
+        
+        [main.config_file.warning]
+        ask = "Here you can display a warning to user."
+        type = "warning"
+        
+        [main.config_file.from_email]
+        ask = "Outgoing email From"
+        type = "email"
+        help = "Email from which comes email from this app"
+        pattern = "^[^@]+@[^@]+$"
+        source = "email:__FINALPATH__/conf/config.php"
+        
+        [main.config_file.expiration]
+        ask = "Default expiration"
+        type = "date"
+        pattern = "^\d\d\d\d-\d\d-\d\d$"
+        source = ":__FINALPATH__/conf/config.php"
+        
+        [main.config_file.logo]
+        ask = "Logo"
+        type = "file"
+        accept = ".png"
+        optional = true
+        help = "You should upload a CA certificate to start"
+        source="__FINALPATH__/img/logo.png"
+
+    [main.auth]
+    name = "Authentication"
+        
+        [main.auth.user]
+        ask = "Username"
+        type = "string"
+        example = "camille"
+        optional = true
+        pattern = "^[^/ ]+$"
+        
+        [main.auth.passphrase]
+        ask = "Password"
+        type = "password"
+        optional = true
+        visibleIf = "user"
+
+        
+[advanced]
+name = "Advanced configuration"
+collapsed = true
+
+    [advanced.dns]
+    name = "DNS"
+
+        [manual.dns.dns0]
+        ask = "First resolver"
+        type = "string"
+        optional = true
+        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
+
+        [manual.dns.dns1]
+        ask = "Second resolver"
+        type = "string"
+        optional = true
+        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"

From 8afe35a53a03615e4ce89b62300f7441db6dcf1e Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Wed, 29 Sep 2021 01:51:43 +0200
Subject: [PATCH 15/20] [enh] Add config panel doc

---
 config_panel.toml.example | 300 ++++++++++++++++++++++++++++++++------
 1 file changed, 252 insertions(+), 48 deletions(-)

diff --git a/config_panel.toml.example b/config_panel.toml.example
index 1a0a23c..81dfeac 100644
--- a/config_panel.toml.example
+++ b/config_panel.toml.example
@@ -1,27 +1,236 @@
+
+## Config panel are available from webadmin > Apps > YOUR_APP > Config Panel Button
+## Those panels let user configure some params on there apps to avoid them to change
+## its by hand in configuration file and be abliged to reapply their changes at each 
+## app upgrade.
+ 
+## -----------------------------------------------------------------------------
+## IMPORTANT: YunoHost spirits is simplicity, please don't expose here tons of 
+## misunderstanble app settings or not really useful feature.
+## -----------------------------------------------------------------------------
+
+## The top level describe the entire config panels screen.
+
+## The version is a required property. 
+## Here a small reminder to associate config panel version with YunoHost version
+## | Config | YNH    | Config panel small change log                           |
+## | ------ | ---    | ------------------------------------------------------- |
+## | 0.1    | 3.x    | 0.1 config script not compatible with YNH >= 4.3        |
+## | 1.0    | 4.3.x  | The new config panel system with 'bind' property        |
 version = "1.0"
 
+## (optional) i18n property let you internationalize questions, however this feature 
+## is only available in core configuration panel (like yunohost domain config).
+## So in app config panel this key is ignored for now, but you can internationalize
+## by using a lang dictionary (see property name bellow)
+# i18n = "prefix_translation_key"
+
+################################################################################
+#### ABOUT PANELS
+################################################################################
+
+## The next level describes web admin panels
+## You have to choose an ID for each panel, in this example the ID is "main"
+## Keep in mind this id will be used in cli to refer to your question, so choose
+## something short and meaningfull.
+## Note: each panel is a distinct HTML form.
 [main]
+
+## (recommended) You should define the label of your panel (and associated tab) 
+## If you don't define it, the ID will be used as title
 name = "Main configuration"
 
-    [main.config_file]
+## To internationalize the name, and other textual properties you can suggest
+## translation like this:
+# name.en = "Main configuration"
+# name.fr = "Configuration principale"
+
+## (optional) If you need to trigger a service reload-or-restart after the user
+## change a question in this panel, you can add your service in the list.
+services = ["nginx", "__APP__"]
+
+## (optional) This help properties is a short help displayed on the same line
+## than the panel title but not displayed in the tab.
+# help = ""
+    
+    ############################################################################
+    #### ABOUT SECTIONS
+    ############################################################################
+
+    ## A panel is compound of one or several sections.
+    ## You have to choose an ID for your section and prefix it with the panel ID
+    ## Be sure to not make a typo in panel prefix, or you will get an unwanted 
+    ## panel in more.
+    ## For this example we imagine, we package the pepettes_ynh app. 
+    ## It's a really simple donation form without administration panel, so we 
+    ## want to expose some settings
+    [main.customization]
+
+    ## (optional) A section could have a title, or not. It depends of what you
+    ## are doing exactly. In web admin it will display an <h3> title.
     name = ""
+
+    ## (optional) This help properties is a short help displayed on the same line
+    ## than the section title.
+    # help = ""
+    
+    ## (optional) As for panel, you can specify to trigger a service 
+    ## reload-or-restart after the user change a question in this section.
+    ## This property is added to the panel property, it doesn't deactivate it.
+    ## So no need to replicate, the service list from panel services property.
+    # services = []
+    
+    ## (optional) By default all questions are optionals, but you can specify a
+    ## default behaviour for question in the section
+    # optional = true
         
-        [main.config_file.warning]
-        ask = "Here you can display a warning to user."
-        type = "warning"
+    ## (optional) It's also possible with the 'visible' property to display the
+    ## question only if the user answer the form in a specific way.
+    ## However, you should not refer to questions after the point where you put
+    ## the visible property. SO the first section should never have a visible
+    ## property
+    ## In more this feature is available in webadmin but not in cli, so keep in
+    ## mind cli user could be prompted for the question...
+    # visible = true
+
+        ########################################################################
+        #### ABOUT QUESTIONS
+        ########################################################################
+
+        ## A section is compound of one or several questions.
+
+        ## ---------------------------------------------------------------------
+        ## IMPORTANT: as for panel and section you have to choose an ID, but this
+        ## one should be unique in all this document, even if the question is in
+        ## an other panel.
+        ## ---------------------------------------------------------------------
         
-        [main.config_file.from_email]
-        ask = "Outgoing email From"
-        type = "email"
-        help = "Email from which comes email from this app"
-        pattern = "^[^@]+@[^@]+$"
-        source = "email:__FINALPATH__/conf/config.php"
+        ## You can use same questions types and properties than in manifest.yml 
+        ## install part. However, in YNH 4.3, a lot of change has been made to
+        ## extend availables questions types list.
+        ## See: TODO DOC LINK
         
-        [main.config_file.expiration]
-        ask = "Default expiration"
-        type = "date"
-        pattern = "^\d\d\d\d-\d\d-\d\d$"
-        source = ":__FINALPATH__/conf/config.php"
+        [main.customization.project_name]
+        
+        ## (required) The ask property is equivalent to the ask property in 
+        ## manifest.yml. However, in config panel questions are displayed on the
+        ## left. So, it's more a label than a complete question, make short.
+        ask = "Name of the project"
+
+        ## (required) The type property indicates how the question should be 
+        ## displayed, validated and managed. Some types have specific properties.
+        ## 
+        ## Types available: string, boolean, number, range, text, password, path
+        ## email, url, date, time, color, select, domain, user, tags, file.
+        ##
+        ## For a complete list with specific properties, see: TODO DOC LINK
+        type = "string"
+        
+        ########################################################################
+        #### ABOUT THE BIND PROPERTY
+        ########################################################################
+
+        ## (recommended) 'bind' property is a powerful feature that let you 
+        ## configure how the data will be read, validated and write. 
+
+        ## By default, 'bind property is in "settings" mode, it means it will 
+        ## read / write the value in application settings file.
+        ## bind = "settings"
+
+        ## But in general, you prefer use the ":FILE" mode to read/write a 
+        ## specific variable in a file. 
+
+        ## Configuration file format supported: yaml, toml, json, ini, env, php,
+        ## python. The feature probably works with others formats, but you need
+        ## to test it carefully.
+
+        ## Unsupported: XML format, custom config function call, php define(), 
+        ## array/list on several lines.
+
+        ## More info on TODO
+        # bind = ":/var/www/__APP__/settings.py"
+
+        ## NOTE: in pepettes, the python variable is called 'name' and not 
+        ## 'project_name', wo here we need to specify the variable name by hand
+        ## before columns
+        ## Here pepettes config file to understand: https://github.com/YunoHost-Apps/pepettes_ynh/blob/5cc2d3ffd6529cc7356ff93af92dbb6785c3ab9a/conf/settings.py##L11
+        
+        bind = "name:/var/www/__APP__/settings.py"
+
+        ## ---------------------------------------------------------------------
+        ## IMPORTANT: other 'bind' mode exists:
+        ## 
+        ## The null mode, to explicitly disable default read / write in settings.
+        #  bind = "null"
+        ##
+        ## Without columns before the path it means all the file will be replaced
+        ## by the value (reserved for file and multiline text question):
+        #  bind = "/var/www/__APP__/img/logo.png"
+        ## 
+        ## Finally, if you define a custom getter, setter or validator in config
+        ## script it will use it instead of apply default bind behaviour.
+        ## getter: get__PROPERTY()
+        ## setter: set__PROPERTY()
+        ## validator: validate__PROPERTY()
+        ## You can also specify a common getter / setter / validator, with the 
+        ## function 'bind' mode, for example here it will try to run 
+        ## get__array_settings() first.
+        #  bind = "array_settings()"
+        ## ---------------------------------------------------------------------
+        
+        ## ---------------------------------------------------------------------
+        ## IMPORTANT: during install/upgrade you should save a first value in 
+        ## the source of the bind key and in app settings.
+        ## During upgrade you should reset values in template files based on 
+        ## value saved in app settings.
+        ## ---------------------------------------------------------------------
+
+        ########################################################################
+        #### OTHER GENERIC PROPERTY FOR QUESTIONS
+        ########################################################################
+        
+        ## (optional) An help text for the question
+        help = "Fill the name of the project which will received donation"
+
+        ## (optional) An example display as placeholder in web form
+        # example = "YunoHost"
+
+        ## (optional) set to true in order to redact the value in operation logs
+        # redact = false
+
+        ## (optional) A validation pattern
+        ## ---------------------------------------------------------------------
+        ## IMPORTANT: your pattern should be between simple quote, not double.
+        ## ---------------------------------------------------------------------
+        pattern.regexp = '^\w{3,30}$'
+        pattern.error = "The name should be at least 3 chars and less than 30 chars. Alphanumeric chars are accepted"
+
+        ## Note: visible and optional properties are also available for questions
+
+
+        [main.customization.contact_url]
+        ask = "Contact url"
+        type = "url"
+        example = "mailto: contact@example.org"
+        help = "mailto: accepted"
+        pattern.regexp = "^mailto:[^@]+@[^@]+|https://$"
+        pattern.error = "Should be https or mailto:"
+        bind = ":/var/www/__APP__/settings.py"
+
+        [main.customization.logo]
+        ask = "Logo"
+        type = "file"
+        accept = ".png"
+        help = "Fill with an already resized logo"
+        source="__FINALPATH__/img/logo.png"
+        
+        [main.customization.favicon]
+        ask = "Favicon"
+        type = "file"
+        accept = ".png"
+        help = "Fill with an already sized favicon"
+        source="__FINALPATH__/img/favicon.png"
+
         
         [main.config_file.logo]
         ask = "Logo"
@@ -29,40 +238,35 @@ name = "Main configuration"
         accept = ".png"
         optional = true
         help = "You should upload a CA certificate to start"
-        source="__FINALPATH__/img/logo.png"
 
-    [main.auth]
-    name = "Authentication"
-        
-        [main.auth.user]
-        ask = "Username"
+    [main.stripe]
+    name = "Stripe general info"
+
+        [main.stripe.publishable_key]
+        ask = "Publishable key"
         type = "string"
-        example = "camille"
-        optional = true
-        pattern = "^[^/ ]+$"
-        
-        [main.auth.passphrase]
-        ask = "Password"
-        type = "password"
-        optional = true
-        visibleIf = "user"
+        redact = true
+        help = "Indicate here the stripe publishable key"
+        bind = ":/var/www/__APP__/settings.py"
 
-        
-[advanced]
-name = "Advanced configuration"
-collapsed = true
-
-    [advanced.dns]
-    name = "DNS"
-
-        [manual.dns.dns0]
-        ask = "First resolver"
+        [main.stripe.secret_key]
+        ask = "Secret key"
         type = "string"
-        optional = true
-        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
-
-        [manual.dns.dns1]
-        ask = "Second resolver"
-        type = "string"
-        optional = true
-        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
+        redact = true
+        help = "Indicate here the stripe secret key"
+        bind = ":/var/www/__APP__/settings.py"
+        
+        [main.stripe.prices]
+        ask = "Prices ID"
+        type = "tags"
+        help = """\
+        Indicates here the prices ID of donation products you created in stripe interfaces. \
+        Go on [Stripe products](https://dashboard.stripe.com/products) to create those donation products. \
+        Fill it tag with 'FREQUENCY/CURRENCY/PRICE_ID' \
+        FREQUENCY: 'one_time' or 'recuring' \
+        CURRENCY: 'EUR' or 'USD' \
+        PRICE_ID: ID from stripe interfaces starting with 'price_' \
+        """
+        pattern.regexp = '^(one_time|recuring)/(EUR|USD)/price_.*$'
+        pattern.error = "Please respect the format describe in help text for each price ID"
+        bind = ":/var/www/__APP__/settings.py"

From 8e21cb4df3986e6266bdfbf00b3e596b849627b4 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Wed, 29 Sep 2021 02:41:30 +0200
Subject: [PATCH 16/20] [enh] A small config script

---
 scripts/config | 104 +++++++++++++++++++++++++++++++------------------
 1 file changed, 66 insertions(+), 38 deletions(-)

diff --git a/scripts/config b/scripts/config
index bc1e6c6..b9e79f8 100644
--- a/scripts/config
+++ b/scripts/config
@@ -1,31 +1,64 @@
 #!/bin/bash
-
-# In most simple cases, you don't need a config script (or just to reload services). 
+# In simple cases, you don't need a config script. 
 
 # With a simple config_panel.toml, you can write in the app settings, in the 
-# upstream config file or replace complete files (logo ...).
+# upstream config file or replace complete files (logo ...) and restart services.
 
 # The config scripts allows you to go further, to handle specific cases 
 # (validation of several interdependent fields, specific getter/setter for a value,
-# pre-loading of config type .cube ).
+# display dynamic informations or choices, pre-loading of config type .cube... ).
 
+#=================================================
+# GENERIC STARTING
+#=================================================
+# IMPORT GENERIC HELPERS
+#=================================================
 
+source /usr/share/yunohost/helpers
 
+ynh_abort_if_errors
+
+#=================================================
+# RETRIEVE ARGUMENTS
+#=================================================
+
+final_path=$(ynh_app_setting_get $app final_path)
 
 #=================================================
 # SPECIFIC GETTERS FOR TOML SHORT KEY
 #=================================================
-get__user() {
-    if [ -s $final_path/keys/credentials ]
+
+get__amount() {
+    # Here we can imagine to have an API call to stripe to know the amount of donation during a month
+    local amount = 200
+
+    # It's possible to change some properties of the question by overriding it:
+    if [ $amount -gt 100 ]
     then
-        sed -n 1p $final_path/keys/credentials 
+    cat << EOF
+style: success
+value: $amount
+ask:
+  en: A lot of donation this month: **$amount €**
+EOF
+    else
+    cat << EOF
+style: danger
+value: $amount
+ask:
+  en: Not so much donation this month: $amount €
+EOF
     fi
 }
 
-get__passphrase() {
-    if [ -s $final_path/keys/credentials ]
+get__prices() {
+    local prices = "$(grep "DONATION\['" "$final_path/settings.py" | sed -r "s@^DONATION\['([^']*)'\]\['([^']*)'\] = '([^']*)'@\1/\2/\3@g" | sed -z 's/\n/,/g;s/,$/\n/')"
+    if [ "$prices" == "," ];
     then
-        sed -n 2p $final_path/keys/credentials 
+        # Return YNH_NULL if you prefer to not return a value at all.
+        echo YNH_NULL
+    else
+        echo $prices
     fi
 }
 
@@ -33,42 +66,37 @@ get__passphrase() {
 #=================================================
 # SPECIFIC VALIDATORS FOR TOML SHORT KEYS
 #=================================================
-validate__user() {
-    [[ -n "$passphrase" && -z "$user" ]] &&
-        echo 'A Username is needed when you suggest a Password'
-}
+validate__publishable_key() {
 
-validate__passphrase() {
-    [[ -n "$user" && -z "$passphrase" ]] &&
-        echo 'A Password is needed when you suggest a Username'
+    # We can imagine here we test if the key is really a publisheable key
+    (is_secret_key $publishable_key) &&
+        echo 'This key seems to be a secret key'
 }
 
 #=================================================
 # SPECIFIC SETTERS FOR TOML SHORT KEYS
 #=================================================
-set__user() {
-    if [ -z "$user" ]
-    then
-        echo "$user\n$passphrase" > $final_path/keys/credentials 
-    else
-        echo "" > $final_path/keys/credentials
-    fi
-}
+set__prices() {
 
-set__passphrase() {
-    :
-}
+    #---------------------------------------------
+    # IMPORTANT: setter are trigger only if a change is detected
+    #---------------------------------------------
+    for price in $(echo $prices | sed "s/,/ /"); do
+        frequency=$(echo $price | cut -d/ -f1)
+        currency=$(echo $price | cut -d/ -f2)
+        price_id=$(echo $price | cut -d/ -f3)
+        sed "d/DONATION\['$frequency'\]\['$currency'\]" "$final_path/settings.py"
 
-
-#=================================================
-# OVERWRITING APPLY STEP 
-#=================================================
-ynh_panel_apply() {
+        echo "DONATION['$frequency']['$currency'] = '$price_id'" >> "$final_path/settings.py"
+    done
     
-    _ynh_panel_apply
-
-    # Reload app service
-    systemctl reload APP
-
+    #---------------------------------------------
+    # IMPORTANT: to be able to upgrade properly, you have to saved the value in settings too
+    #---------------------------------------------
+    ynh_app_setting_set $app prices $prices
 }
 
+#=================================================
+# GENERIC FINALIZATION
+#=================================================
+ynh_app_config_run $1

From b89af4b7b0509b4dd5464651f9fc8f0a00cf46f6 Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Wed, 29 Sep 2021 02:42:19 +0200
Subject: [PATCH 17/20] [fix] bind key not needed

---
 config_panel.toml.example | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/config_panel.toml.example b/config_panel.toml.example
index 81dfeac..588a3ef 100644
--- a/config_panel.toml.example
+++ b/config_panel.toml.example
@@ -82,7 +82,7 @@ services = ["nginx", "__APP__"]
     
     ## (optional) By default all questions are optionals, but you can specify a
     ## default behaviour for question in the section
-    # optional = true
+    optional = false
         
     ## (optional) It's also possible with the 'visible' property to display the
     ## question only if the user answer the form in a specific way.
@@ -232,15 +232,15 @@ services = ["nginx", "__APP__"]
         source="__FINALPATH__/img/favicon.png"
 
         
-        [main.config_file.logo]
-        ask = "Logo"
-        type = "file"
-        accept = ".png"
-        optional = true
-        help = "You should upload a CA certificate to start"
-
     [main.stripe]
     name = "Stripe general info"
+    optional = false
+
+        # The next alert is overwrited with a getter from the config script
+        [main.stripe.amount]
+        ask = "Donation in the month : XX €
+        type = "alert"
+        style = "success"
 
         [main.stripe.publishable_key]
         ask = "Publishable key"
@@ -269,4 +269,3 @@ services = ["nginx", "__APP__"]
         """
         pattern.regexp = '^(one_time|recuring)/(EUR|USD)/price_.*$'
         pattern.error = "Please respect the format describe in help text for each price ID"
-        bind = ":/var/www/__APP__/settings.py"

From 12eb08b590f76fdc8f9a6a9edde8c8c24c4df99e Mon Sep 17 00:00:00 2001
From: ljf <ljf+git@grimaud.me>
Date: Wed, 29 Sep 2021 02:45:44 +0200
Subject: [PATCH 18/20] [fix] Remove not wanted panel

---
 config_panel.toml | 68 -----------------------------------------------
 1 file changed, 68 deletions(-)
 delete mode 100644 config_panel.toml

diff --git a/config_panel.toml b/config_panel.toml
deleted file mode 100644
index 1a0a23c..0000000
--- a/config_panel.toml
+++ /dev/null
@@ -1,68 +0,0 @@
-version = "1.0"
-
-[main]
-name = "Main configuration"
-
-    [main.config_file]
-    name = ""
-        
-        [main.config_file.warning]
-        ask = "Here you can display a warning to user."
-        type = "warning"
-        
-        [main.config_file.from_email]
-        ask = "Outgoing email From"
-        type = "email"
-        help = "Email from which comes email from this app"
-        pattern = "^[^@]+@[^@]+$"
-        source = "email:__FINALPATH__/conf/config.php"
-        
-        [main.config_file.expiration]
-        ask = "Default expiration"
-        type = "date"
-        pattern = "^\d\d\d\d-\d\d-\d\d$"
-        source = ":__FINALPATH__/conf/config.php"
-        
-        [main.config_file.logo]
-        ask = "Logo"
-        type = "file"
-        accept = ".png"
-        optional = true
-        help = "You should upload a CA certificate to start"
-        source="__FINALPATH__/img/logo.png"
-
-    [main.auth]
-    name = "Authentication"
-        
-        [main.auth.user]
-        ask = "Username"
-        type = "string"
-        example = "camille"
-        optional = true
-        pattern = "^[^/ ]+$"
-        
-        [main.auth.passphrase]
-        ask = "Password"
-        type = "password"
-        optional = true
-        visibleIf = "user"
-
-        
-[advanced]
-name = "Advanced configuration"
-collapsed = true
-
-    [advanced.dns]
-    name = "DNS"
-
-        [manual.dns.dns0]
-        ask = "First resolver"
-        type = "string"
-        optional = true
-        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"
-
-        [manual.dns.dns1]
-        ask = "Second resolver"
-        type = "string"
-        optional = true
-        pattern = "^([0-9.]{8,16}|[0-9a-fA-F:]+)$"

From 2c2ebd5ec15c317c0702f789927681e2146e8549 Mon Sep 17 00:00:00 2001
From: "ljf (zamentur)" <zamentur@users.noreply.github.com>
Date: Thu, 30 Sep 2021 19:11:39 +0200
Subject: [PATCH 19/20] [enh] Apply suggestions from code review

Co-authored-by: Alexandre Aubin <alex.aubin@mailoo.org>
---
 config_panel.toml.example | 150 ++++++++++++++++++++++----------------
 1 file changed, 87 insertions(+), 63 deletions(-)

diff --git a/config_panel.toml.example b/config_panel.toml.example
index 588a3ef..ea8fefc 100644
--- a/config_panel.toml.example
+++ b/config_panel.toml.example
@@ -1,12 +1,16 @@
 
 ## Config panel are available from webadmin > Apps > YOUR_APP > Config Panel Button
-## Those panels let user configure some params on there apps to avoid them to change
-## its by hand in configuration file and be abliged to reapply their changes at each 
-## app upgrade.
+## Those panels let user configure some params on their apps using a friendly interface,
+## and remove the need to manually edit files from the command line.
+ 
+## From a packager perspective, this .toml is coupled to the scripts/config script,
+## which may be used to define custom getters/setters. However, most use cases
+## should be covered automagically by the core, thus it may not be necessary
+## to define a scripts/config at all!
  
 ## -----------------------------------------------------------------------------
-## IMPORTANT: YunoHost spirits is simplicity, please don't expose here tons of 
-## misunderstanble app settings or not really useful feature.
+## IMPORTANT: In accordance with YunoHost's spirit, please keep things simple and 
+## do not overwhelm the admin with tons of misunderstandable or advanced settings.
 ## -----------------------------------------------------------------------------
 
 ## The top level describe the entire config panels screen.
@@ -33,21 +37,18 @@ version = "1.0"
 ## You have to choose an ID for each panel, in this example the ID is "main"
 ## Keep in mind this id will be used in cli to refer to your question, so choose
 ## something short and meaningfull.
-## Note: each panel is a distinct HTML form.
+## In the webadmin, each panel corresponds to a distinct tab / form
 [main]
 
-## (recommended) You should define the label of your panel (and associated tab) 
-## If you don't define it, the ID will be used as title
-name = "Main configuration"
-
-## To internationalize the name, and other textual properties you can suggest
-## translation like this:
+## Define the label for your panel
+## Internationalization works similarly to the 'description' and 'ask' questions in the manifest
 # name.en = "Main configuration"
 # name.fr = "Configuration principale"
 
 ## (optional) If you need to trigger a service reload-or-restart after the user
 ## change a question in this panel, you can add your service in the list.
-services = ["nginx", "__APP__"]
+services = ["__APP__"]
+# or services = ["nginx", "__APP__"] to also reload-or-restart nginx
 
 ## (optional) This help properties is a short help displayed on the same line
 ## than the panel title but not displayed in the tab.
@@ -57,21 +58,27 @@ services = ["nginx", "__APP__"]
     #### ABOUT SECTIONS
     ############################################################################
 
-    ## A panel is compound of one or several sections.
-    ## You have to choose an ID for your section and prefix it with the panel ID
-    ## Be sure to not make a typo in panel prefix, or you will get an unwanted 
-    ## panel in more.
-    ## For this example we imagine, we package the pepettes_ynh app. 
-    ## It's a really simple donation form without administration panel, so we 
-    ## want to expose some settings
+    ## A panel is composed of one or several sections.
+    ##
+    ## Sections are meant to group questions together when they correspond to
+    ## a same subtopic. This impacts the rendering in terms of CLI prompts
+    ## and HTML forms
+    ##
+    ## You should choose an ID for your section, and prefix it with the panel ID
+    ## (Be sure to not make a typo in the panel ID, which would implicitly create
+    ## an other entire panel)
+    ##
+    ## We use the context of pepettes_ynh as an example,
+    ## which is a simple donation form app written in python,
+    ## and for which the admin will want to edit the configuration
     [main.customization]
 
-    ## (optional) A section could have a title, or not. It depends of what you
-    ## are doing exactly. In web admin it will display an <h3> title.
+    ## (optional) Defining a proper title for sections is not mandatory
+    ## and depends on the exact rendering you're aiming for the CLI / webadmin
     name = ""
 
     ## (optional) This help properties is a short help displayed on the same line
-    ## than the section title.
+    ## than the section title, meant to provide additional details
     # help = ""
     
     ## (optional) As for panel, you can specify to trigger a service 
@@ -84,13 +91,14 @@ services = ["nginx", "__APP__"]
     ## default behaviour for question in the section
     optional = false
         
-    ## (optional) It's also possible with the 'visible' property to display the
-    ## question only if the user answer the form in a specific way.
-    ## However, you should not refer to questions after the point where you put
-    ## the visible property. SO the first section should never have a visible
-    ## property
-    ## In more this feature is available in webadmin but not in cli, so keep in
-    ## mind cli user could be prompted for the question...
+    ## (optional) It's also possible with the 'visible' property to only
+    ## display the section depending on the user's answers to previous questions.
+    ##
+    ## Be careful that the 'visible' property should only refer to **previous** questions
+    ## Hence, it should not make sense to have a "visible" property on the very first section.
+    ##
+    ## Also, keep in mind that this feature only works in the webadmin and not in CLI
+    ## (therefore a user could be prompted in CLI for a question that may not be relevant)
     # visible = true
 
         ########################################################################
@@ -113,9 +121,11 @@ services = ["nginx", "__APP__"]
         [main.customization.project_name]
         
         ## (required) The ask property is equivalent to the ask property in 
-        ## manifest.yml. However, in config panel questions are displayed on the
-        ## left. So, it's more a label than a complete question, make short.
-        ask = "Name of the project"
+        ## the manifest. However, in config panels, questions are displayed on the
+        ## left side and therefore have less space to be rendered. Therefore, 
+        ## it is better to use a short question, and use the "help" property to
+        ## provide additional details if necessary.
+        ask.en = "Name of the project"
 
         ## (required) The type property indicates how the question should be 
         ## displayed, validated and managed. Some types have specific properties.
@@ -131,47 +141,60 @@ services = ["nginx", "__APP__"]
         ########################################################################
 
         ## (recommended) 'bind' property is a powerful feature that let you 
-        ## configure how the data will be read, validated and write. 
+        ## configure how and where the data will be read, validated and written. 
 
         ## By default, 'bind property is in "settings" mode, it means it will 
-        ## read / write the value in application settings file.
+        ## **only** read and write the value in application settings file.
         ## bind = "settings"
 
-        ## But in general, you prefer use the ":FILE" mode to read/write a 
-        ## specific variable in a file. 
+        ## However, settings usually correspond to key/values in actual app configurations
+        ## Hence, a more useful mode is to have bind = ":FILENAME". In that case, YunoHost
+        ## will automagically find a line with "KEY=VALUE" in FILENAME
+        ## (with the adequate separator between KEY and VALUE)
+        ##
+        ## YunoHost will then use this value for the read/get operation.
+        ## During write/set operations, YunoHost will overwrite the value
+        ## in **both** FILENAME and in the app's settings.yml
 
         ## Configuration file format supported: yaml, toml, json, ini, env, php,
-        ## python. The feature probably works with others formats, but you need
-        ## to test it carefully.
+        ## python. The feature probably works with others formats, but should be tested carefully.
 
-        ## Unsupported: XML format, custom config function call, php define(), 
-        ## array/list on several lines.
+        ## Note that this feature only works with relatively simple cases
+        ## such as `KEY: VALUE`, but won't properly work with
+        ## complex data structures like multilin array/lists or dictionnaries.
+        ## It also doesn't work with XML format, custom config function call, php define(), ...
 
         ## More info on TODO
         # bind = ":/var/www/__APP__/settings.py"
 
-        ## NOTE: in pepettes, the python variable is called 'name' and not 
-        ## 'project_name', wo here we need to specify the variable name by hand
-        ## before columns
-        ## Here pepettes config file to understand: https://github.com/YunoHost-Apps/pepettes_ynh/blob/5cc2d3ffd6529cc7356ff93af92dbb6785c3ab9a/conf/settings.py##L11
+
+        ## By default, bind = ":FILENAME" will use the question ID as KEY
+        ## ... but the question ID may sometime not be the exact KEY name in the configuration file.
+        ## 
+        ## In particular, in pepettes, the python variable is 'name' and not 'project_name'
+        ## (c.f. https://github.com/YunoHost-Apps/pepettes_ynh/blob/5cc2d3ffd6529cc7356ff93af92dbb6785c3ab9a/conf/settings.py##L11 )
+        ##
+        ## In that case, the key name can be specified before the column ':'
         
         bind = "name:/var/www/__APP__/settings.py"
 
         ## ---------------------------------------------------------------------
         ## IMPORTANT: other 'bind' mode exists:
         ## 
-        ## The null mode, to explicitly disable default read / write in settings.
-        #  bind = "null"
+        ## bind = "FILENAME" (with no column character before FILENAME)
+        ## may be used to bind to the **entire file content** (instead of a single KEY/VALUE)
+        ## This could be used to expose an entire configuration file, or binary files such as images
+        ## For example:
+        ## bind = "/var/www/__APP__/img/logo.png"
+        ##
+        ## bind = "null" can be used to disable reading / writing in settings.
+        ## This creates sort of a "virtual" or "ephemeral" question which is not related to any actual setting
+        ## In this mode, you are expected to define custom getter/setters/validators in scripts/config:
+        ##
+        ## getter: get__QUESTIONID()
+        ## setter: set__QUESTIONID()
+        ## validator: validate__QUESTIONID()
         ##
-        ## Without columns before the path it means all the file will be replaced
-        ## by the value (reserved for file and multiline text question):
-        #  bind = "/var/www/__APP__/img/logo.png"
-        ## 
-        ## Finally, if you define a custom getter, setter or validator in config
-        ## script it will use it instead of apply default bind behaviour.
-        ## getter: get__PROPERTY()
-        ## setter: set__PROPERTY()
-        ## validator: validate__PROPERTY()
         ## You can also specify a common getter / setter / validator, with the 
         ## function 'bind' mode, for example here it will try to run 
         ## get__array_settings() first.
@@ -179,10 +202,11 @@ services = ["nginx", "__APP__"]
         ## ---------------------------------------------------------------------
         
         ## ---------------------------------------------------------------------
-        ## IMPORTANT: during install/upgrade you should save a first value in 
-        ## the source of the bind key and in app settings.
-        ## During upgrade you should reset values in template files based on 
-        ## value saved in app settings.
+        ## IMPORTANT: with the exception of bind=null questions,
+        ## question IDs should almost **always** correspond to an app setting
+        ## initialized / reused during install/upgrade.
+        ## Not doing so may result in inconsistencies between the config panel mechanism
+        ## and the use of ynh_add_config
         ## ---------------------------------------------------------------------
 
         ########################################################################
@@ -213,7 +237,7 @@ services = ["nginx", "__APP__"]
         type = "url"
         example = "mailto: contact@example.org"
         help = "mailto: accepted"
-        pattern.regexp = "^mailto:[^@]+@[^@]+|https://$"
+        pattern.regexp = '^mailto:[^@]+@[^@]+|https://$'
         pattern.error = "Should be https or mailto:"
         bind = ":/var/www/__APP__/settings.py"
 
@@ -222,14 +246,14 @@ services = ["nginx", "__APP__"]
         type = "file"
         accept = ".png"
         help = "Fill with an already resized logo"
-        source="__FINALPATH__/img/logo.png"
+        bind = "__FINALPATH__/img/logo.png"
         
         [main.customization.favicon]
         ask = "Favicon"
         type = "file"
         accept = ".png"
         help = "Fill with an already sized favicon"
-        source="__FINALPATH__/img/favicon.png"
+        bind = "__FINALPATH__/img/favicon.png"
 
         
     [main.stripe]

From ad14cc664b58d1cdd1fe9796298f663200417649 Mon Sep 17 00:00:00 2001
From: ericgaspar <junk.eg@free.fr>
Date: Wed, 6 Oct 2021 19:51:34 +0200
Subject: [PATCH 20/20] Update config_panel.toml.example

---
 config_panel.toml.example | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config_panel.toml.example b/config_panel.toml.example
index ea8fefc..c6bccd8 100644
--- a/config_panel.toml.example
+++ b/config_panel.toml.example
@@ -35,7 +35,7 @@ version = "1.0"
 
 ## The next level describes web admin panels
 ## You have to choose an ID for each panel, in this example the ID is "main"
-## Keep in mind this id will be used in cli to refer to your question, so choose
+## Keep in mind this ID will be used in CLI to refer to your question, so choose
 ## something short and meaningfull.
 ## In the webadmin, each panel corresponds to a distinct tab / form
 [main]