diff --git a/dockerize/docker/REQUIREMENTS.txt b/dockerize/docker/REQUIREMENTS.txt index 1d22d6f4..aaf086ba 100644 --- a/dockerize/docker/REQUIREMENTS.txt +++ b/dockerize/docker/REQUIREMENTS.txt @@ -1,71 +1,48 @@ +bandit~=1.9 +beautifulsoup4~=4.12 +celery~=5.3 +cryptography~=46.0.6 +detect-secrets~=1.5 django~=4.2 -django-auth-ldap~=4.6 -python-ldap~=3.4 -django-taggit~=5.0 -django-tinymce==4.1.0 -psycopg2-binary~=2.9 -# Updates for Django 2 -git+https://github.com/metamatik/django-templatetag-sugar.git -# Updates for Django 4 -git+https://github.com/Xpirix/django-ratings.git@modernize -django-taggit-autosuggest~=0.4 +django-allauth~=65.15 django-annoying~=0.10 - -# Updates for Django 2 -# git+https://github.com/elpaso/rpc4django.git@modernize -rpc4django~=0.6 -Pillow~=10.1 -django-taggit-templatetags -# Updates for Django 4 -git+https://github.com/Xpirix/django-simplemenu.git@modernize +django-auth-ldap~=4.6 django-bootstrap-pagination-forked~=1.7 -django-sortable-listview~=0.43 -sorl-thumbnail~=12.10 -django-extensions~=3.2 django-debug-toolbar~=4.2 -whoosh~=2.7 +django-extensions~=3.2 django-haystack~=3.2 - -feedparser~=6.0 -celery~=5.3 - -# pin due to issues with a breaking change -# https://github.com/celery/celery/issues/7783 -importlib_metadata<5 - -requests~=2.31 - -markdown~=3.5 - +django-matomo==0.1.6 +django-preferences==1.0.0 +django-rest-auth==0.9.5 +django-rest-multiple-models==2.1.3 +django-sortable-listview~=0.43 +django-taggit~=5.0 +django-taggit-autosuggest~=0.4 +django-taggit-templatetags +django-tinymce==4.1.0 +django-webpack-loader~=3.1 djangorestframework~=3.14 -pyjwt~=2.8 djangorestframework-simplejwt~=5.3 -sorl-thumbnail-serializer-field==0.2.1 -django-rest-auth==0.9.5 drf-yasg~=1.21 -django-rest-multiple-models==2.1.3 - -django-preferences==1.0.0 -geoip2==4.5.0 -django-matomo==0.1.6 -uwsgi~=2.0 +feedparser~=6.0 +flake8~=7.3 +flake8-json~=24.4 freezegun~=1.4 - +geoip2==4.5.0 +git+https://github.com/Xpirix/django-ratings.git@modernize +git+https://github.com/Xpirix/django-simplemenu.git@modernize +git+https://github.com/metamatik/django-templatetag-sugar.git +importlib_metadata<5 +markdown~=3.5 +oauthlib~=3.2 +Pillow~=10.1 +psycopg2-binary~=2.9 +pyjwt~=2.8 +requests~=2.31 +rpc4django~=0.6 sentry-sdk~=2.2 -django-webpack-loader~=3.1 - -beautifulsoup4~=4.12 setuptools~=75.1 - -# Security scanning tools for QGIS Plugin analysis (invoked via subprocess) -# Bandit - Security vulnerability scanner for Python code -bandit~=1.9 - -# detect-secrets - Finds hardcoded secrets in code -detect-secrets~=1.5 - -# flake8 for code quality -flake8~=7.3 - -# flake8-json for structured output (optional but recommended) -flake8-json~=24.4 +sorl-thumbnail~=12.10 +sorl-thumbnail-serializer-field==0.2.1 +uwsgi~=2.0 +whoosh~=2.7 diff --git a/docs/oauth-setup.md b/docs/oauth-setup.md new file mode 100644 index 00000000..08d2a7a3 --- /dev/null +++ b/docs/oauth-setup.md @@ -0,0 +1,236 @@ +# OAuth Provider Setup + +Each provider needs a **SocialApp** entry in the Django Admin. +Go to: **Admin → Social Accounts → Social applications → Add social application** + +Fields to fill: +- **Provider** — select from the dropdown +- **Name** — any label (e.g. "GitHub") +- **Client ID** — the OAuth App ID / Client ID from the provider +- **Secret key** — the OAuth Secret from the provider +- **Key** — only required for Apple (the Key ID, see below) +- **Settings** — optional JSON for provider-specific options (e.g. Apple's `certificate_key`) +- **Sites** — move your site (e.g. `example.com`) from "Available" to "Chosen" + +--- + +## GitHub + +1. Go to → **OAuth Apps** → **New OAuth App** +2. Fill in: + - **Application name**: QGIS Plugins (or any label) + - **Homepage URL**: `https://plugins.qgis.org` + - **Authorization callback URL**: `https://plugins.qgis.org/accounts/github/login/callback/` +3. Click **Register application**, then **Generate a new client secret**. +4. In Django Admin: + - Provider: `GitHub` + - Client ID: the **Client ID** shown on the app page + - Secret key: the **Client secret** you just generated + +--- + +## Google + +1. Go to → Select or create a project. +2. Navigate to **APIs & Services → Credentials → Create Credentials → OAuth client ID**. +3. Set **Application type** to **Web application**. +4. Add to **Authorized redirect URIs**: + ``` + https://plugins.qgis.org/accounts/google/login/callback/ + ``` +5. Click **Create**. Note the **Client ID** and **Client secret**. +6. In Django Admin: + - Provider: `Google` + - Client ID: the Client ID + - Secret key: the Client secret + +> You may also need to enable the **Google People API** under **APIs & Services → Library**. + +--- + +## GitLab + +### GitLab.com (default) + +1. Go to → **Add new application**. +2. Fill in: + - **Name**: QGIS Plugins + - **Redirect URI**: `https://plugins.qgis.org/accounts/gitlab/login/callback/` + - **Scopes**: check `read_user` +3. Click **Save application**. Note the **Application ID** and **Secret**. +4. In Django Admin: + - Provider: `GitLab` + - Client ID: the Application ID + - Secret key: the Secret + +### Self-hosted GitLab instance + +Uncomment and edit the `gitlab` section in `qgis-app/settings_local.py` +(copy from `settings_local.py.templ`): + +```python +SOCIALACCOUNT_PROVIDERS = { + "gitlab": { + "GITLAB_URL": "https://your-gitlab.example.com", + "SCOPE": ["read_user"], + }, +} +``` + +Then create the OAuth application on your self-hosted instance at +`https://your-gitlab.example.com/-/profile/applications`. + +--- + +## OpenStreetMap + +1. Go to + (replace `YOUR_USERNAME` with your OSM username). +2. Fill in: + - **Name**: QGIS Plugins + - **Main Application URL**: `https://plugins.qgis.org` + - **Callback URL**: `https://plugins.qgis.org/accounts/openstreetmap/login/callback/` + - **Permissions**: check **Read user preferences** +3. Click **Register**. Note the **Consumer Key** and **Consumer Secret**. +4. In Django Admin: + - Provider: `OpenStreetMap` + - Client ID: the Consumer Key + - Secret key: the Consumer Secret + +> OSM uses OAuth 1.0a — django-allauth handles this transparently. + +--- + +## Microsoft + +1. Go to → **Microsoft Entra ID → App registrations → New registration**. +2. Fill in: + - **Name**: QGIS Plugins + - **Supported account types**: *Accounts in any organizational directory and personal Microsoft accounts* (for `"tenant": "common"`) + - **Redirect URI**: Web — `https://plugins.qgis.org/accounts/microsoft/login/callback/` +3. Click **Register**. Note the **Application (client) ID**. +4. Go to **Certificates & secrets → New client secret**. Note the **Value** (only shown once). +5. Go to **API permissions → Add a permission → Microsoft Graph → Delegated → User.Read** → Grant admin consent. +6. In Django Admin: + - Provider: `Microsoft` + - Client ID: the Application (client) ID + - Secret key: the client secret Value + +> To restrict to a specific tenant (organisation), change `"tenant": "common"` to your **Directory (tenant) ID** in `settings_local.py`. + +--- + +## Apple + +Apple Sign In requires extra steps compared to other providers. + +### Prerequisites +You need an Apple Developer account (). + +### Steps + +1. **Create an App ID**: + - Go to **Certificates, Identifiers & Profiles → Identifiers → +** + - Type: **App IDs** → **App** + - Enable **Sign In with Apple** + - Note the **Bundle ID** (e.g. `org.qgis.plugins`) + +2. **Create a Services ID** (this is the OAuth client): + - Go to **Identifiers → +** → **Services IDs** + - Description: QGIS Plugins + - Identifier: e.g. `org.qgis.plugins.web` (must be unique, different from Bundle ID) + - Enable **Sign In with Apple → Configure**: + - Primary App ID: select the App ID from step 1 + - Domains: `plugins.qgis.org` + - Return URLs: `https://plugins.qgis.org/accounts/apple/login/callback/` + - Note the **Services ID** identifier — this is your **Client ID** + +3. **Create a Key**: + - Go to **Keys → +** + - Enable **Sign In with Apple → Configure** → select your Primary App ID + - Click **Register** and **Download** the `.p8` file (only downloadable once) + - Note the **Key ID** + +4. In Django Admin: + - Provider: `Apple` + - Client ID: the **Services ID** identifier (e.g. `org.qgis.plugins.web`) + - Secret key: your **Team ID** (found top-right in the developer portal, 10 chars) + - Key: paste the full content of the downloaded `.p8` file + + django-allauth uses the Team ID + Key ID + `.p8` content to generate a JWT client secret dynamically. You also need to set **Key ID** in `qgis-app/settings_local.py` (copy from `settings_local.py.templ`): + + ```python + SOCIALACCOUNT_PROVIDERS = { + "apple": { + "APP": { + "client_id": "org.qgis.plugins.web", + "secret": "TEAM_ID", + "key": "KEY_ID", + "settings": { + "certificate_key": """-----BEGIN PRIVATE KEY----- + ...your .p8 content here... + -----END PRIVATE KEY-----""" + } + } + }, + } + ``` + + The other fields (Client ID = Services ID, Secret key = Team ID) can also be stored in the DB via Admin as a fallback, but the `certificate_key` must be in settings. + +--- + +## LinkedIn + +1. Go to → Create an app. +2. Fill in the required fields (App name, LinkedIn Page, logo). +3. After creation, go to the **Auth** tab: + - Note the **Client ID** and **Client Secret** + - Add to **Authorized redirect URLs for your app**: + ``` + https://plugins.qgis.org/accounts/linkedin_oauth2/login/callback/ + ``` +4. Go to the **Products** tab → Request access to **Sign In with LinkedIn using OpenID Connect**. +5. In Django Admin: + - Provider: `LinkedIn` + - Client ID: the Client ID + - Secret key: the Client Secret + +> The `openid`, `profile`, and `email` scopes configured in settings require the **OpenID Connect** product to be approved. Standard OAuth2 (`r_liteprofile`, `r_emailaddress`) also works but uses the legacy `linkedin` provider. + +--- + +## Telegram + +Telegram uses a **Login Widget** rather than standard OAuth. There is no redirect URI. + +1. Open Telegram and message **[@BotFather](https://t.me/BotFather)**. +2. Send `/newbot` and follow the prompts to create a bot. Note the **bot token** (format: `123456789:ABC-...`). +3. Send `/setdomain` to BotFather, select your bot, and enter your domain: `plugins.qgis.org`. +4. In Django Admin: + - Provider: `Telegram` + - Client ID: your **bot username** (without `@`, e.g. `QGISPluginsBot`) + - Secret key: the **bot token** (e.g. `123456789:ABC-...`) + +> The Telegram provider works via a login widget that calls back to +> `https://plugins.qgis.org/accounts/telegram/login/callback/`. +> No client secret registration on a portal is needed — the bot token itself signs the payload. + +--- + +## Callback URLs Summary + +| Provider | Callback URL | +|---|---| +| GitHub | `/accounts/github/login/callback/` | +| Google | `/accounts/google/login/callback/` | +| GitLab | `/accounts/gitlab/login/callback/` | +| OpenStreetMap | `/accounts/openstreetmap/login/callback/` | +| Microsoft | `/accounts/microsoft/login/callback/` | +| Apple | `/accounts/apple/login/callback/` | +| LinkedIn | `/accounts/linkedin_oauth2/login/callback/` | +| Telegram | `/accounts/telegram/login/callback/` | + +Prepend your domain, e.g. `https://plugins.qgis.org/accounts/github/login/callback/`. + +For local development replace the domain with `http://localhost:8000` and register a separate OAuth app (or add `localhost` as an allowed redirect on the existing one). diff --git a/qgis-app/plugins/templates/plugins/plugin_detail.html b/qgis-app/plugins/templates/plugins/plugin_detail.html index 3dd8feb4..6d8f34a4 100644 --- a/qgis-app/plugins/templates/plugins/plugin_detail.html +++ b/qgis-app/plugins/templates/plugins/plugin_detail.html @@ -171,47 +171,6 @@ {{ block.super }} -{% endblock %} {% block extrajs %} +{{ block.super }} {% endblock %} \ No newline at end of file diff --git a/qgis-app/settings.py b/qgis-app/settings.py index fc8e69df..4e491dfe 100644 --- a/qgis-app/settings.py +++ b/qgis-app/settings.py @@ -260,7 +260,7 @@ USER_MAP = { "project_name": "QGIS", "favicon_file": "/static/images/qgis-icon-32x32.png", - "login_view": "login", + "login_view": "account_login", "marker": { "iconUrl": "/static/images/qgis-icon-32x32.png", "iconSize": [32, 32], diff --git a/qgis-app/settings_auth.py b/qgis-app/settings_auth.py index 6c2dd8f2..5e79a015 100644 --- a/qgis-app/settings_auth.py +++ b/qgis-app/settings_auth.py @@ -10,6 +10,7 @@ AUTHENTICATION_BACKENDS = ( "django.contrib.auth.backends.ModelBackend", "django.contrib.auth.backends.RemoteUserBackend", + "allauth.account.auth_backends.AuthenticationBackend", ) if ast.literal_eval(os.environ.get("ENABLE_LDAP", "False")): diff --git a/qgis-app/settings_docker.py b/qgis-app/settings_docker.py index d4ccf92c..887f4552 100644 --- a/qgis-app/settings_docker.py +++ b/qgis-app/settings_docker.py @@ -79,6 +79,18 @@ "matomo", # Webpack "webpack_loader", + # Social authentication + "allauth", + "allauth.account", + "allauth.socialaccount", + "allauth.socialaccount.providers.google", + "allauth.socialaccount.providers.github", + "allauth.socialaccount.providers.gitlab", + "allauth.socialaccount.providers.openstreetmap", + "allauth.socialaccount.providers.microsoft", + "allauth.socialaccount.providers.apple", + "allauth.socialaccount.providers.linkedin_oauth2", + "allauth.socialaccount.providers.telegram", ] DATABASES = { @@ -99,6 +111,44 @@ PAGINATION_DEFAULT_PAGINATION_HUB = 30 LOGIN_REDIRECT_URL = "/" LOGOUT_REDIRECT_URL = "/" + +# django-allauth configuration +AUTHENTICATION_BACKENDS = [ + "django.contrib.auth.backends.ModelBackend", + "allauth.account.auth_backends.AuthenticationBackend", +] + +ACCOUNT_SIGNUP_FIELDS = ['email', 'username*', 'password1*', 'password2*'] +ACCOUNT_LOGIN_METHODS = {'username'} +ACCOUNT_EMAIL_VERIFICATION = "none" +ACCOUNT_SIGNUP_ENABLED = False + +SOCIALACCOUNT_PROVIDERS = { + "google": { + "SCOPE": ["profile", "email"], + "AUTH_PARAMS": {"access_type": "online"}, + }, + "github": { + "SCOPE": ["user:email"], + }, + "gitlab": { + "SCOPE": ["read_user"], + }, + "openstreetmap": {}, + "microsoft": { + "tenant": "common", + "SCOPE": ["User.Read"], + }, + "apple": {}, + "linkedin_oauth2": { + "SCOPE": ["openid", "profile", "email"], + }, + "telegram": {}, +} + +SOCIALACCOUNT_AUTO_SIGNUP = False +SOCIALACCOUNT_LOGIN_ON_GET = True +SOCIALACCOUNT_FORMS = {"signup": "social_forms.SocialSignupForm"} SERVE_STATIC_MEDIA = DEBUG DEFAULT_PLUGINS_SITE = os.environ.get( "DEFAULT_PLUGINS_SITE", "https://plugins.qgis.org/" @@ -170,6 +220,9 @@ # Default primary key type DEFAULT_AUTO_FIELD = "django.db.models.AutoField" +# allauth requires its AccountMiddleware +MIDDLEWARE.append("allauth.account.middleware.AccountMiddleware") + # Set the maximum PLUGIN_MAX_UPLOAD_SIZE size to 25MB # When changing this, make sure to also change the diff --git a/qgis-app/settings_local.py.templ b/qgis-app/settings_local.py.templ index 109c21ce..8ffc4e8e 100644 --- a/qgis-app/settings_local.py.templ +++ b/qgis-app/settings_local.py.templ @@ -7,3 +7,44 @@ EMAIL_HOST_USER = "resend" EMAIL_HOST_PASSWORD = "" EMAIL_SUBJECT_PREFIX = '[QGIS Plugins] ' DEFAULT_FROM_EMAIL = 'no-reply-plugins@qgis.org' + +# ----------------------------------------------------------------------------- +# Social authentication — provider overrides +# Only add the sections for providers you are configuring. +# Credentials (Client ID / Secret) are stored in Django Admin, not here. +# See docs/oauth-setup.md for full setup instructions. +# ----------------------------------------------------------------------------- + +SOCIALACCOUNT_PROVIDERS = { + + # GitLab — only needed when connecting to a self-hosted instance. + # Remove or leave commented out to use gitlab.com (the default). + "gitlab": { + "GITLAB_URL": "https://your-gitlab.example.com", + "SCOPE": ["read_user"], + }, + + # Microsoft — set a specific tenant ID to restrict login to one + # organisation. Use "common" (default) to allow any Microsoft account. + "microsoft": { + "tenant": "common", # or your Directory (tenant) ID + "SCOPE": ["User.Read"], + }, + + # Apple — certificate_key is the content of the .p8 file downloaded + # from the Apple Developer portal. key is the Key ID (10 chars). + # client_id and secret (Team ID) are stored in Django Admin. + "apple": { + "APP": { + "client_id": "org.your.bundle.web", + "secret": "TEAM_ID_10CHARS", + "key": "KEY_ID_10CHARS", + "settings": { + "certificate_key": """-----BEGIN PRIVATE KEY----- + +-----END PRIVATE KEY-----""" + }, + } + }, +} + diff --git a/qgis-app/social_forms.py b/qgis-app/social_forms.py new file mode 100644 index 00000000..1c8e88b1 --- /dev/null +++ b/qgis-app/social_forms.py @@ -0,0 +1,15 @@ +from allauth.socialaccount.forms import SignupForm as AllauthSocialSignupForm + + +class SocialSignupForm(AllauthSocialSignupForm): + """ + Extends allauth's social signup form to make the email field non-editable + server-side. Setting disabled=True causes Django to ignore any submitted + value and use the form's initial value (from the OAuth provider) instead, + preventing users from bypassing the readonly attribute via DevTools. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if "email" in self.fields: + self.fields["email"].disabled = True diff --git a/qgis-app/static/style/scss/style.scss b/qgis-app/static/style/scss/style.scss index 7a9edd65..dbda50aa 100644 --- a/qgis-app/static/style/scss/style.scss +++ b/qgis-app/static/style/scss/style.scss @@ -4,6 +4,7 @@ @import "sustaining_members.scss"; @import "security_scan.scss"; @import "file_upload_widget.scss"; +@import "tooltip.scss"; html { @@ -225,6 +226,10 @@ p { .content > .columns .content { width: 100%; } + .login-container { + max-width: 100%; + min-width: 40dvw; + } } @media screen and (min-width: 1024px) { @@ -238,6 +243,9 @@ p { .container { max-width: unset; } + .login-container { + width: 650px !important; + } } a.is-active > span { @@ -245,8 +253,9 @@ a.is-active > span { } .login-container { - max-width: 100%; - min-width: 40dvw; + border-radius: 20px; + border: #ffffff1c solid; + backdrop-filter: blur(8px); } .login-container hr { @@ -266,6 +275,25 @@ a.is-active > span { opacity: 0.9; } +.login-divider { + display: flex; + align-items: center; + margin: 1.25rem 0; + + &::before, + &::after { + content: ""; + flex: 1; + border-bottom: 1px solid #dbdbdb; + } + + span { + padding: 0 0.75rem; + color: #7a7a7a; + font-size: 0.875rem; + } +} + .form-error { color: red; font-size: 10pt; diff --git a/qgis-app/static/style/scss/tooltip.scss b/qgis-app/static/style/scss/tooltip.scss new file mode 100644 index 00000000..0374413c --- /dev/null +++ b/qgis-app/static/style/scss/tooltip.scss @@ -0,0 +1,48 @@ +// ------------------------------------------------------- +// Tooltip component +// Used across plugin_detail, plugin_token_detail, login +// ------------------------------------------------------- +.tooltip { + position: relative; + display: inline-flex; + align-items: center; + opacity: 1 !important; + + .tooltiptext { + visibility: hidden; + width: max-content; + max-width: 220px; + background-color: #363636; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 6px 10px; + font-size: 0.875rem; + line-height: 1.4; + position: absolute; + z-index: 1000; + bottom: calc(100% + 8px); + left: 50%; + transform: translateX(-50%); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + white-space: normal; + + &::after { + content: ""; + position: absolute; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: #363636 transparent transparent transparent; + } + } + + &:hover .tooltiptext { + visibility: visible; + opacity: 1; + } +} diff --git a/qgis-app/templates/account/login.html b/qgis-app/templates/account/login.html new file mode 100644 index 00000000..8b2df52d --- /dev/null +++ b/qgis-app/templates/account/login.html @@ -0,0 +1,206 @@ +{% extends "base.html" %} +{% load i18n static socialaccount %} + +{% block pagetitle %} +{% get_providers as socialaccount_providers %} +
+
+
+
+ +
+
+
+
+{% endblock %} + +{% block extrajs %} +{{ block.super }} + +{% endblock %} diff --git a/qgis-app/templates/account/logout.html b/qgis-app/templates/account/logout.html new file mode 100644 index 00000000..3a945934 --- /dev/null +++ b/qgis-app/templates/account/logout.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} +{% load i18n static %} + +{% block pagetitle %} +
+
+
+
+ +
+
+
+
+{% endblock %} diff --git a/qgis-app/templates/account/signup.html b/qgis-app/templates/account/signup.html new file mode 100644 index 00000000..7a743849 --- /dev/null +++ b/qgis-app/templates/account/signup.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% load i18n static %} + +{% block pagetitle %} +
+
+
+
+ +
+
+
+
+{% endblock %} diff --git a/qgis-app/templates/account/signup_closed.html b/qgis-app/templates/account/signup_closed.html new file mode 100644 index 00000000..7a743849 --- /dev/null +++ b/qgis-app/templates/account/signup_closed.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% load i18n static %} + +{% block pagetitle %} +
+
+
+
+ +
+
+
+
+{% endblock %} diff --git a/qgis-app/templates/base.html b/qgis-app/templates/base.html index abd7a799..f2a1cc9e 100644 --- a/qgis-app/templates/base.html +++ b/qgis-app/templates/base.html @@ -21,6 +21,8 @@ + + {% block extracss %}{% endblock %} diff --git a/qgis-app/templates/index.html b/qgis-app/templates/index.html index 823ddfca..0c8bb658 100644 --- a/qgis-app/templates/index.html +++ b/qgis-app/templates/index.html @@ -5,7 +5,7 @@

Welcome the the new QGIS Web Application

This application in currently under testing and will become soon the official QGIS web portal.

You are strongly encouraged to use this application and report any issue on the QGIS Web Applications Bug Tracking System.

-

In order to access to some functionalities of this website you will need to login with a valid OSGEO id. You can create a new one on OSGEO web portal.

+

In order to access to some functionalities of this website you will need to login.

Thank you for your cooperation.

{% endblock %} diff --git a/qgis-app/templates/layouts/header.html b/qgis-app/templates/layouts/header.html index ab6a58bc..c0133caf 100644 --- a/qgis-app/templates/layouts/header.html +++ b/qgis-app/templates/layouts/header.html @@ -10,7 +10,7 @@ {% if user.is_authenticated %} - + @@ -19,7 +19,7 @@ {% else %} - + @@ -87,13 +87,13 @@ {{ user.get_full_name|default:user.username }} {% else %} - + diff --git a/qgis-app/templates/registration/login.html b/qgis-app/templates/registration/login.html index fea0725d..d1b08732 100644 --- a/qgis-app/templates/registration/login.html +++ b/qgis-app/templates/registration/login.html @@ -6,16 +6,13 @@ background-size: cover;">
-