From 5d5d1f94d78248283d35035f8a5f12dcb852694d Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Sat, 18 Oct 2025 12:19:15 +0200 Subject: [PATCH 01/20] The login component is an authentication form for users of an application. --- .../sqlpage/migrations/68_login.sql | 52 +++++++++++ .../99_shared_id_class_attributes.sql | 6 +- sqlpage/templates/login.handlebars | 89 +++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 examples/official-site/sqlpage/migrations/68_login.sql create mode 100644 sqlpage/templates/login.handlebars diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql new file mode 100644 index 00000000..7230f759 --- /dev/null +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -0,0 +1,52 @@ +INSERT INTO component(name, icon, description, introduced_in_version) VALUES + ('login', 'password-user', ' +The login component is an authentication form for users of an application. + +It allows the entry of a user account consisting of a username and a password. + +It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); + +INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES + ('title','Title of the authentication form.','TEXT',TRUE,TRUE), + ('enctype','Form data encoding.','TEXT',TRUE,TRUE), + ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), + ('username','User account identifier.','TEXT',TRUE,FALSE), + ('password','User password.','TEXT',TRUE,FALSE), + ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), + ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), + ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), + ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), + ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), + ('validate_color','The color of the button at the bottom of the form that submits the values. Omit this property to use the default color.','COLOR',TRUE,TRUE), + ('validate_shape','The shape of the validation button.','TEXT',TRUE,TRUE), + ('validate_outline','A color to outline the validation button.','COLOR',TRUE,TRUE), + ('validate_size','The size of the validation button.','TEXT',TRUE,TRUE) +) x; + +-- Insert example(s) for the component +INSERT INTO example(component, description, properties) +VALUES ( + 'login', + 'Using the main options of the login component', + JSON( + '[ + { + "component": "login", + "action": "login.sql", + "image": "../assets/icon.webp", + "title": "Please login to your account", + "username": "Username", + "password": "Password", + "forgot_password_text": "Forgot your password?", + "forgot_password_link": "reset_password.sql", + "remember_me_text": "Remember me", + "footer_md": "Don''t have an account? [Register here](register.sql)", + "validate": "Sign in" + } + ]' + ) + ); + +-- 265707.png \ No newline at end of file diff --git a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql index 47e66576..df054541 100644 --- a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql +++ b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql @@ -18,7 +18,8 @@ FROM (VALUES ('title', TRUE), ('tracking', TRUE), ('text', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); INSERT INTO parameter(component, top_level, name, description, type, optional) @@ -49,6 +50,7 @@ FROM (VALUES ('timeline', FALSE), ('title', TRUE), ('tracking', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars new file mode 100644 index 00000000..f292a18d --- /dev/null +++ b/sqlpage/templates/login.handlebars @@ -0,0 +1,89 @@ +
+
+
+
+ {{#if image}} +
+ +
+ {{/if}} + {{#if title}} +

{{title}}

+ {{/if}} + +
+ + + + + + + + +
+ +
+ + + + + + + + + +
+ {{#if remember_me_text}} + + {{/if}} +
+ +
+ {{#if (or footer footer_md)}} +
+
+ + {{#if footer}} + {{footer}} + {{else}} + {{#if footer_md}} + {{{markdown footer_md}}} + {{/if}} + {{/if}} + +
+ {{/if}} +
+
+
+
From b356cc8904d94ea6f9c462a92f66646c8b480a82 Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:04:39 +0200 Subject: [PATCH 02/20] username_icon and password_icon attributes --- .../sqlpage/migrations/68_login.sql | 6 ++-- sqlpage/templates/login.handlebars | 28 +++++-------------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 7230f759..dad03a8e 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -12,6 +12,8 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), ('username','User account identifier.','TEXT',TRUE,FALSE), ('password','User password.','TEXT',TRUE,FALSE), + ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), + ('password_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), @@ -39,6 +41,8 @@ VALUES ( "title": "Please login to your account", "username": "Username", "password": "Password", + "username_icon": "user", + "password_icon": "lock", "forgot_password_text": "Forgot your password?", "forgot_password_link": "reset_password.sql", "remember_me_text": "Remember me", @@ -48,5 +52,3 @@ VALUES ( ]' ) ); - --- 265707.png \ No newline at end of file diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index f292a18d..258622a8 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
{{username}}
- - - - - - - + {{#if username_icon}} + {{icon_img username_icon}} + {{/if}}
- - - - - - - - + {{#if password_icon}} + {{~icon_img password_icon~}} + {{/if}}
{{#if remember_me_text}} From cb8fa2dc16e454e7068e6723912ed3c34267a3bc Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:09:32 +0200 Subject: [PATCH 03/20] Fixing a regression with the class attribute. --- sqlpage/templates/login.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index 258622a8..a664e0cc 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
Date: Fri, 24 Oct 2025 08:29:35 +0200 Subject: [PATCH 04/20] Documentation improved --- .../official-site/sqlpage/migrations/68_login.sql | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index dad03a8e..1cbed299 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -1,10 +1,15 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES ('login', 'password-user', ' -The login component is an authentication form for users of an application. +The login component is an authentication form with numerous customization options. +It offers the main functionalities for this type of form. +The user can enter their username and password. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. -It allows the entry of a user account consisting of a username and a password. +This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). +It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. -It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); +', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES ('title','Title of the authentication form.','TEXT',TRUE,TRUE), From ce4ffd33940362efa2da07d6e87282adff149827 Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:45:57 +0200 Subject: [PATCH 05/20] Documentation improved --- examples/official-site/sqlpage/migrations/68_login.sql | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 1cbed299..6d906ae5 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -3,12 +3,17 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES The login component is an authentication form with numerous customization options. It offers the main functionalities for this type of form. The user can enter their username and password. -There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s identity via a cookie. It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. +A few things to know : +- The form uses the POST method to transmit information to the destination page, +- The user''s username and password are entered into fields with the names `username` and `password`, +- To obtain the values of username and password, you must use the variables `:username` and `:password`, +- To know if the user wants their identity to be remembered, you must read the value of the variable `:remember`. ', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES @@ -22,7 +27,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), - ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their identity. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), From 4dba824727751bd4ccf68badeea2f65c5bf3963d Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 14:56:17 +0100 Subject: [PATCH 06/20] Enhance ODBC support for Debian-based systems by setting the library search path in build.rs. Update CI configuration to use the correct PostgreSQL driver name. Document changes in CHANGELOG.md. --- .github/workflows/ci.yml | 2 +- CHANGELOG.md | 1 + build.rs | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20485478..47625c5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: db_url: "mssql://root:Password123!@127.0.0.1/sqlpage" - database: odbc container: postgres - db_url: "Driver=/usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!" + db_url: "Driver=PostgreSQL Unicode;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!" setup_odbc: true steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index ccf8bc1b..a4e00999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - SQLPage now sets the [`Server-Timing` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing) in development. So when you have a page that loads slowly, you can open your browser's network inspector, click on the slow request, then open the timing tab to understand where it's spending its time. - image - Fixed a memory corruption issue in the builtin odbc driver manager + - ODBC: fix using globally installed system drivers by their name in debian-based linux distributions. ## v0.38.0 diff --git a/build.rs b/build.rs index a39ea959..2b99740c 100644 --- a/build.rs +++ b/build.rs @@ -29,6 +29,7 @@ async fn main() { ] { h.await.unwrap(); } + set_odbc_rpath(); } fn make_client() -> awc::Client { @@ -171,3 +172,14 @@ fn make_url_path(url: &str) -> PathBuf { ); sqlpage_artefacts.join(filename) } + +/// On debian-based linux distributions, odbc drivers are installed in /usr/lib/-linux-gnu/odbc +/// which is not in the default library search path. +fn set_odbc_rpath() { + if cfg!(all(target_os = "linux", feature = "odbc-static")) { + println!( + "cargo:rustc-link-arg=-Wl,-rpath,/usr/lib/{}-linux-gnu/odbc", + std::env::var("TARGET").unwrap().split('-').next().unwrap() + ); + } +} \ No newline at end of file From afde9e1f09d5159c9bc42289fecb73fd29d2ff16 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 15:12:39 +0100 Subject: [PATCH 07/20] fmt --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 2b99740c..ed14c612 100644 --- a/build.rs +++ b/build.rs @@ -182,4 +182,4 @@ fn set_odbc_rpath() { std::env::var("TARGET").unwrap().split('-').next().unwrap() ); } -} \ No newline at end of file +} From 74a2c8b1e70db851fe0692e134dd14c6257f4e20 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 18:13:36 +0100 Subject: [PATCH 08/20] Fix docker image references in README Update docker image names from sqlpage/SQLPage to lovasoa/sqlpage and update example port mapping to use port 80 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b4c99c33..d1692f5d 100644 --- a/README.md +++ b/README.md @@ -164,12 +164,12 @@ To run on a server, you can use [the docker image](https://hub.docker.com/r/lova custom components, and migrations (see [configuration.md](./configuration.md)) to `/etc/sqlpage` in the container. - For instance, you can use: - - `docker run -it --name sqlpage -p 8080:8080 --volume "$(pwd)/source:/var/www" --volume "$(pwd)/configuration:/etc/sqlpage:ro" --rm sqlpage/SQLPage` + - `docker run -it --name sqlpage -p 80:8080 --volume "$(pwd)/source:/var/www" --volume "$(pwd)/configuration:/etc/sqlpage:ro" --rm lovasoa/sqlpage` - And place your website in a folder named `source` and your `sqlpage.json` in a folder named `configuration`. - If you want to build your own docker image, taking the raw sqlpage image as a base is not recommended, since it is extremely stripped down and probably won't contain the dependencies you need. Instead, you can take debian as a base and simply copy the sqlpage binary from the official image to your own image: - ```Dockerfile FROM debian:stable-slim - COPY --from=sqlpage/SQLPage:main /usr/local/bin/sqlpage /usr/local/bin/sqlpage + COPY --from=lovasoa/sqlpage:main /usr/local/bin/sqlpage /usr/local/bin/sqlpage ``` We provide compiled binaries only for the x86_64 architecture, but provide docker images for other architectures, including arm64 and armv7. If you want to run SQLPage on a Raspberry Pi or @@ -359,4 +359,4 @@ Check out our [Contributing Guide](./CONTRIBUTING.md) for detailed instructions Our windows binaries are digitally signed, so they should be recognized as safe by Windows. Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/). [Contributors](https://github.com/sqlpage/SQLPage/graphs/contributors), [Owners](https://github.com/orgs/sqlpage/people?query=role%3Aowner). -This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it \ No newline at end of file +This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it From 7f7fdd6f576be199aad73c3877453240b51f9715 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 22:49:28 +0100 Subject: [PATCH 09/20] update deps --- Cargo.lock | 48 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b4b1df95..96f46222 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2431,9 +2431,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -3852,9 +3852,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "zeroize", ] @@ -4914,9 +4914,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -4925,25 +4925,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -4954,9 +4940,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4964,31 +4950,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", From 722dc740fa9df5cd34b8d5e2b2907d2cf8776a45 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 23:07:57 +0100 Subject: [PATCH 10/20] add an error_message property to the login component - Updated SQL queries in `create_session_token.sql` and `login.sql` to use consistent parameter naming conventions. - Enhanced the login form in `login.sql` to include an error message for failed login attempts. - Added a new parameter `error_message` in the migration file for better user feedback. - Modified the Handlebars template to display the error message when applicable, improving user experience during authentication. --- .../authentication/create_session_token.sql | 6 +++--- .../examples/authentication/login.sql | 17 +++++++++++------ .../sqlpage/migrations/68_login.sql | 1 + sqlpage/templates/login.handlebars | 12 +++++++++++- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/examples/official-site/examples/authentication/create_session_token.sql b/examples/official-site/examples/authentication/create_session_token.sql index 645fedc4..8ea8cd19 100644 --- a/examples/official-site/examples/authentication/create_session_token.sql +++ b/examples/official-site/examples/authentication/create_session_token.sql @@ -4,12 +4,12 @@ delete from user_sessions where created_at < datetime('now', '-1 day'); -- check that the SELECT 'authentication' AS component, 'login.sql?failed' AS link, -- redirect to the login page on error - (SELECT password_hash FROM users WHERE username = :Username) AS password_hash, -- this is a hash of the password 'admin' - :Password AS password; -- this is the password that the user sent through our form in 'index.sql' + (SELECT password_hash FROM users WHERE username = :username) AS password_hash, -- this is a hash of the password 'admin' + :password AS password; -- this is the password that the user sent through our form in 'index.sql' -- if we haven't been redirected, then the password is correct -- create a new session -insert into user_sessions (session_token, username) values (sqlpage.random_string(32), :Username) +insert into user_sessions (session_token, username) values (sqlpage.random_string(32), :username) returning 'cookie' as component, 'session_token' as name, session_token as value; -- redirect to the authentication example home page diff --git a/examples/official-site/examples/authentication/login.sql b/examples/official-site/examples/authentication/login.sql index b634de30..264bbc4a 100644 --- a/examples/official-site/examples/authentication/login.sql +++ b/examples/official-site/examples/authentication/login.sql @@ -1,10 +1,15 @@ select 'dynamic' as component, properties FROM example WHERE component = 'shell' LIMIT 1; -select 'form' as component, 'Authentication' as title, 'Log in' as validate, 'create_session_token.sql' as action; -select 'Username' as name, 'user' as prefix_icon, 'admin' as placeholder; -select 'Password' as name, 'lock' as prefix_icon, 'admin' as placeholder, 'password' as type; - -select 'alert' as component, 'danger' as color, 'Invalid username or password' as title where $failed is not null; +select + 'login' as component, + 'create_session_token.sql' as action, + '/assets/icon.webp' as image, + 'Demo Login Form' as title, + 'Username' as username, + 'Password' as password, + case when $failed is not null then 'Invalid username or password. In this demo, you can log in with admin / admin.' end as error_message, + 'In this demo, the username is "admin" and the password is "admin".' as footer_md, + 'Sign in' as validate; select 'text' as component, ' @@ -12,7 +17,7 @@ select 'text' as component, ' This is a simple example of an authentication form. It uses - - the [`form`](/documentation.sql?component=form#component) component to create a login form + - the [`login`](/documentation.sql?component=login#component) component to create a login form - the [`authentication`](/documentation.sql?component=authentication#component) component to check the user password - the [`cookie`](/documentation.sql?component=cookie#component) component to store a unique session token in the user browser - the [`redirect`](/documentation.sql?component=redirect#component) component to redirect the user to the login page if they are not logged in diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 6d906ae5..522c8672 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -20,6 +20,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('title','Title of the authentication form.','TEXT',TRUE,TRUE), ('enctype','Form data encoding.','TEXT',TRUE,TRUE), ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), + ('error_message','An error message to display above the form, typically shown after a failed login attempt.','TEXT',TRUE,TRUE), ('username','User account identifier.','TEXT',TRUE,FALSE), ('password','User password.','TEXT',TRUE,FALSE), ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index a664e0cc..54808bfa 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -13,13 +13,23 @@ {{/if}} > {{#if image}} -
+
{{/if}} {{#if title}}

{{title}}

{{/if}} + {{#if error_message}} + + {{/if}}
{{#if username_icon}} From cfea904e5d30d50494c100515b744802501b883d Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Sat, 18 Oct 2025 12:19:15 +0200 Subject: [PATCH 11/20] The login component is an authentication form for users of an application. --- .../sqlpage/migrations/68_login.sql | 52 +++++++++++ .../99_shared_id_class_attributes.sql | 6 +- sqlpage/templates/login.handlebars | 89 +++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 examples/official-site/sqlpage/migrations/68_login.sql create mode 100644 sqlpage/templates/login.handlebars diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql new file mode 100644 index 00000000..7230f759 --- /dev/null +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -0,0 +1,52 @@ +INSERT INTO component(name, icon, description, introduced_in_version) VALUES + ('login', 'password-user', ' +The login component is an authentication form for users of an application. + +It allows the entry of a user account consisting of a username and a password. + +It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); + +INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES + ('title','Title of the authentication form.','TEXT',TRUE,TRUE), + ('enctype','Form data encoding.','TEXT',TRUE,TRUE), + ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), + ('username','User account identifier.','TEXT',TRUE,FALSE), + ('password','User password.','TEXT',TRUE,FALSE), + ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), + ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), + ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), + ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), + ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), + ('validate_color','The color of the button at the bottom of the form that submits the values. Omit this property to use the default color.','COLOR',TRUE,TRUE), + ('validate_shape','The shape of the validation button.','TEXT',TRUE,TRUE), + ('validate_outline','A color to outline the validation button.','COLOR',TRUE,TRUE), + ('validate_size','The size of the validation button.','TEXT',TRUE,TRUE) +) x; + +-- Insert example(s) for the component +INSERT INTO example(component, description, properties) +VALUES ( + 'login', + 'Using the main options of the login component', + JSON( + '[ + { + "component": "login", + "action": "login.sql", + "image": "../assets/icon.webp", + "title": "Please login to your account", + "username": "Username", + "password": "Password", + "forgot_password_text": "Forgot your password?", + "forgot_password_link": "reset_password.sql", + "remember_me_text": "Remember me", + "footer_md": "Don''t have an account? [Register here](register.sql)", + "validate": "Sign in" + } + ]' + ) + ); + +-- 265707.png \ No newline at end of file diff --git a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql index 47e66576..df054541 100644 --- a/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql +++ b/examples/official-site/sqlpage/migrations/99_shared_id_class_attributes.sql @@ -18,7 +18,8 @@ FROM (VALUES ('title', TRUE), ('tracking', TRUE), ('text', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); INSERT INTO parameter(component, top_level, name, description, type, optional) @@ -49,6 +50,7 @@ FROM (VALUES ('timeline', FALSE), ('title', TRUE), ('tracking', TRUE), - ('carousel', TRUE) + ('carousel', TRUE), + ('login', TRUE) ); diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars new file mode 100644 index 00000000..f292a18d --- /dev/null +++ b/sqlpage/templates/login.handlebars @@ -0,0 +1,89 @@ +
+
+
+ + {{#if image}} +
+ +
+ {{/if}} + {{#if title}} +

{{title}}

+ {{/if}} + +
+ + + + + + + + +
+ +
+ + + + + + + + + +
+ {{#if remember_me_text}} + + {{/if}} +
+ +
+ {{#if (or footer footer_md)}} +
+
+ + {{#if footer}} + {{footer}} + {{else}} + {{#if footer_md}} + {{{markdown footer_md}}} + {{/if}} + {{/if}} + +
+ {{/if}} + +
+
+
From eb1f43c6e1567104a4ce81d605404c37c78b7177 Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:04:39 +0200 Subject: [PATCH 12/20] username_icon and password_icon attributes --- .../sqlpage/migrations/68_login.sql | 6 ++-- sqlpage/templates/login.handlebars | 28 +++++-------------- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 7230f759..dad03a8e 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -12,6 +12,8 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), ('username','User account identifier.','TEXT',TRUE,FALSE), ('password','User password.','TEXT',TRUE,FALSE), + ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), + ('password_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), @@ -39,6 +41,8 @@ VALUES ( "title": "Please login to your account", "username": "Username", "password": "Password", + "username_icon": "user", + "password_icon": "lock", "forgot_password_text": "Forgot your password?", "forgot_password_link": "reset_password.sql", "remember_me_text": "Remember me", @@ -48,5 +52,3 @@ VALUES ( ]' ) ); - --- 265707.png \ No newline at end of file diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index f292a18d..258622a8 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
{{username}}
- - - - - - - + {{#if username_icon}} + {{icon_img username_icon}} + {{/if}}
- - - - - - - - + {{#if password_icon}} + {{~icon_img password_icon~}} + {{/if}}
{{#if remember_me_text}} From 36ab34f827fe7cfaf761f86c8752e861539eca2c Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:09:32 +0200 Subject: [PATCH 13/20] Fixing a regression with the class attribute. --- sqlpage/templates/login.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index 258622a8..a664e0cc 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -1,4 +1,4 @@ -
+
Date: Fri, 24 Oct 2025 08:29:35 +0200 Subject: [PATCH 14/20] Documentation improved --- .../official-site/sqlpage/migrations/68_login.sql | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index dad03a8e..1cbed299 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -1,10 +1,15 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES ('login', 'password-user', ' -The login component is an authentication form for users of an application. +The login component is an authentication form with numerous customization options. +It offers the main functionalities for this type of form. +The user can enter their username and password. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. -It allows the entry of a user account consisting of a username and a password. +This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). +It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. -It offers additional features such as the ability to request session persistence or to reset the password.', '0.39.0'); +', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES ('title','Title of the authentication form.','TEXT',TRUE,TRUE), From 3d7f780fbd3002b930745b229f0b78bcb6768e2f Mon Sep 17 00:00:00 2001 From: Olivier Auverlot Date: Fri, 24 Oct 2025 08:45:57 +0200 Subject: [PATCH 15/20] Documentation improved --- examples/official-site/sqlpage/migrations/68_login.sql | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 1cbed299..6d906ae5 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -3,12 +3,17 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES The login component is an authentication form with numerous customization options. It offers the main functionalities for this type of form. The user can enter their username and password. -There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s session via a cookie. +There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s identity via a cookie. It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. +A few things to know : +- The form uses the POST method to transmit information to the destination page, +- The user''s username and password are entered into fields with the names `username` and `password`, +- To obtain the values of username and password, you must use the variables `:username` and `:password`, +- To know if the user wants their identity to be remembered, you must read the value of the variable `:remember`. ', '0.39.0'); INSERT INTO parameter(component, name, description, type, top_level, optional) SELECT 'login', * FROM (VALUES @@ -22,7 +27,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), ('forgot_password_text','A text for the link allowing the user to reset their password. If the text is empty, the link is not displayed.','TEXT',TRUE,TRUE), ('forgot_password_link','The link to the page allowing the user to reset their password.','TEXT',TRUE,TRUE), - ('remember_me_text','A text for the option allowing the user to request the preservation of their work session. The name of the field is remember. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), + ('remember_me_text','A text for the option allowing the user to request the preservation of their identity. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), From cc95ae25dee3e671c6f604268d9bd1ebe7e90c98 Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 18:13:52 +0100 Subject: [PATCH 16/20] Improve login component documentation and usability Add complete example with database schema, credential processing, and page protection. Update authentication migration to reference new login component. Enhance login template with default icons and autocomplete attributes. Make validate parameter optional with sensible default. --- .../sqlpage/migrations/07_authentication.sql | 8 +- .../sqlpage/migrations/68_login.sql | 78 +++++++++++++++---- sqlpage/templates/login.handlebars | 14 ++-- 3 files changed, 71 insertions(+), 29 deletions(-) diff --git a/examples/official-site/sqlpage/migrations/07_authentication.sql b/examples/official-site/sqlpage/migrations/07_authentication.sql index fd342fc6..c759dee8 100644 --- a/examples/official-site/sqlpage/migrations/07_authentication.sql +++ b/examples/official-site/sqlpage/migrations/07_authentication.sql @@ -14,7 +14,7 @@ you have two main options: - does not require any external service - gives you fine-grained control over - which pages and actions are protected - - the look of the login form + - the look of the [login form](?component=login) - the duration of the session - the permissions of each user 2. [**Single sign-on**](/sso) @@ -128,12 +128,10 @@ Then, in all the pages that require authentication, you check if the cookie is p You can check if the user has sent the correct password in a form, and if not, redirect them to a login page. -Create a login form in a file called `login.sql`: +Create a login form in a file called `login.sql` that uses the [login component](?component=login): ```sql -select ''form'' as component, ''Authentication'' as title, ''Log in'' as validate, ''create_session_token.sql'' as action; -select ''Username'' as name, ''admin'' as placeholder; -select ''Password'' as name, ''admin'' as placeholder, ''password'' as type; +select ''login'' as component; ``` And then, in `create_session_token.sql` : diff --git a/examples/official-site/sqlpage/migrations/68_login.sql b/examples/official-site/sqlpage/migrations/68_login.sql index 6d906ae5..a8a18c60 100644 --- a/examples/official-site/sqlpage/migrations/68_login.sql +++ b/examples/official-site/sqlpage/migrations/68_login.sql @@ -1,13 +1,15 @@ INSERT INTO component(name, icon, description, introduced_in_version) VALUES ('login', 'password-user', ' The login component is an authentication form with numerous customization options. -It offers the main functionalities for this type of form. -The user can enter their username and password. +The user enters their username and password, +and is then redirected to another page, where you can use the [authentication](?component=authentication) component +to check the credentials. + There are many optional attributes such as the use of icons on input fields, the insertion of a link to a page to reset the password, an option for the application to maintain the user''s identity via a cookie. It is also possible to set the title of the form, display the company logo, or customize the appearance of the form submission button. -This component should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie). -It does not implement any logic and simply collects the username and password to pass them to the code responsible for authentication. +This component does not implement any logic. It simply collects the username and password to pass them to the code responsible for authentication. +It should be used in conjunction with other components such as [authentication](component.sql?component=authentication) and [cookie](component.sql?component=cookie) to actually allow or deny access. A few things to know : - The form uses the POST method to transmit information to the destination page, @@ -20,8 +22,8 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('title','Title of the authentication form.','TEXT',TRUE,TRUE), ('enctype','Form data encoding.','TEXT',TRUE,TRUE), ('action','An optional link to a target page that will handle the results of the form. ','TEXT',TRUE,TRUE), - ('username','User account identifier.','TEXT',TRUE,FALSE), - ('password','User password.','TEXT',TRUE,FALSE), + ('username','Label and placeholder for the user account identifier text field.','TEXT',TRUE,FALSE), + ('password','Label and placeholder for the password field.','TEXT',TRUE,FALSE), ('username_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('password_icon','Icon to display on the left side of the input field, on the same line.','ICON',TRUE,TRUE), ('image','The URL of an centered image displayed before the title.','URL',TRUE,TRUE), @@ -30,7 +32,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S ('remember_me_text','A text for the option allowing the user to request the preservation of their identity. If the text is empty, the option is not displayed.','TEXT',TRUE,TRUE), ('footer','A text placed at the bottom of the authentication form.','TEXT',TRUE,TRUE), ('footer_md','A markdown text placed at the bottom of the authentication form. Useful for creating links to other pages (creating a new account, contacting technical support, etc.).','TEXT',TRUE,TRUE), - ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,FALSE), + ('validate','The text to display in the button at the bottom of the form that submits the values.','TEXT',TRUE,TRUE), ('validate_color','The color of the button at the bottom of the form that submits the values. Omit this property to use the default color.','COLOR',TRUE,TRUE), ('validate_shape','The shape of the validation button.','TEXT',TRUE,TRUE), ('validate_outline','A color to outline the validation button.','COLOR',TRUE,TRUE), @@ -41,10 +43,57 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S INSERT INTO example(component, description, properties) VALUES ( 'login', - 'Using the main options of the login component', - JSON( - '[ - { + 'This example shows how to implement a complete custom login system in your SQLPage app. + +### Database schema + +`sqlpage/migrations/001_users.sql` + +```sql +create table account ( + username TEXT PRIMARY KEY, + password_hash TEXT NOT NULL +); + +create table session ( + id TEXT PRIMARY KEY, + username TEXT REFERENCES account(username) + -- you could add more fields for session expiration, session metadata tracking... +); +``` + +### Process user credentials + +Create a file named `login.sql`: + +```sql +SELECT ''authentication'' AS component, + ''/'' AS link, -- redirect the user to the homepage if the password is incorrect + (SELECT password_hash FROM account WHERE username = :username) AS password_hash, + :password AS password; + +-- The code after this point is only executed if the user has sent the correct password + +-- Generate a random session token +INSERT INTO session (id, username) +VALUES (sqlpage.random_string(32), :username) +RETURNING ''cookie'' AS component, ''session_token'' AS name, id AS value, +case when :remember is null then 3600*24*365 else 3600*4 end as max_age; + +select ''redirect'' as component, ''protected.sql'' as link; -- once logged in, redirect to the protected page +``` + +### Protect pages + +Start all protected pages with + +```sql +select ''redirect'' as component, ''/'' as link where not exists (select 1 from session where id=sqlpage.cookie(''session_token'')); +``` + +### Login form on the home page +', + JSON('[{ "component": "login", "action": "login.sql", "image": "../assets/icon.webp", @@ -58,7 +107,6 @@ VALUES ( "remember_me_text": "Remember me", "footer_md": "Don''t have an account? [Register here](register.sql)", "validate": "Sign in" - } - ]' - ) - ); + }]') +), + ('login', 'Most basic login form', JSON('[{"component": "login"}]')); diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index a664e0cc..723fdb87 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -22,10 +22,8 @@ {{/if}}
- {{#if username_icon}} - {{icon_img username_icon}} - {{/if}} - + {{icon_img (default username_icon 'user-circle')}} +
- {{#if password_icon}} - {{~icon_img password_icon~}} - {{/if}} - + {{~icon_img (default password_icon 'key')~}} +
{{#if remember_me_text}}
{{#if (or footer footer_md)}}
From d542a8ae79e1ffe7bc83838cf1ea7c5a286c784a Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 23:23:44 +0100 Subject: [PATCH 17/20] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4e00999..ccb59417 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - image - Fixed a memory corruption issue in the builtin odbc driver manager - ODBC: fix using globally installed system drivers by their name in debian-based linux distributions. + - New [login](https://sql-page.com/component.sql?component=table) component. ## v0.38.0 From 5ee781cf40950890f53c94218bde20e4378977fd Mon Sep 17 00:00:00 2001 From: lovasoa Date: Mon, 27 Oct 2025 23:36:29 +0100 Subject: [PATCH 18/20] use the login component in the user auth example --- .../user-authentication/docker-compose.yml | 2 ++ examples/user-authentication/signin.sql | 21 +++++++------------ sqlpage/templates/login.handlebars | 7 ++++--- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/examples/user-authentication/docker-compose.yml b/examples/user-authentication/docker-compose.yml index 5108ac1e..7738221d 100644 --- a/examples/user-authentication/docker-compose.yml +++ b/examples/user-authentication/docker-compose.yml @@ -1,6 +1,8 @@ services: web: image: lovasoa/sqlpage:main # main is cutting edge, use sqlpage/SQLPage:latest for the latest stable version + build: + context: ".." ports: - "8080:8080" volumes: diff --git a/examples/user-authentication/signin.sql b/examples/user-authentication/signin.sql index 4057e44d..bab0e883 100644 --- a/examples/user-authentication/signin.sql +++ b/examples/user-authentication/signin.sql @@ -1,14 +1,9 @@ -SELECT 'form' AS component, +SELECT 'login' AS component, + 'login.sql' AS action, 'Sign in' AS title, - 'Sign in' AS validate, - 'login.sql' AS action; - -SELECT 'username' AS name; -SELECT 'password' AS name, 'password' AS type; - -SELECT 'alert' as component, - 'Sorry' as title, - 'We could not authenticate you. Please log in or [create an account](signup.sql).' as description_md, - 'alert-circle' as icon, - 'red' as color -WHERE $error IS NOT NULL; \ No newline at end of file + 'Username' AS username, + 'Password' AS password, + 'user' AS username_icon, + 'lock' AS password_icon, + case when $error is not null then 'We could not authenticate you. Please log in or [create an account](signup.sql).' end as error_message_md, + 'Sign in' AS validate; \ No newline at end of file diff --git a/sqlpage/templates/login.handlebars b/sqlpage/templates/login.handlebars index 18c9bbb0..28e1666c 100644 --- a/sqlpage/templates/login.handlebars +++ b/sqlpage/templates/login.handlebars @@ -20,13 +20,14 @@ {{#if title}}

{{title}}

{{/if}} - {{#if error_message}} + {{#if (or error_message error_message_md)}}
{{/if}} - +
{{icon_img (default username_icon 'user-circle')}}
-