diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fe7a89aa0ed37c4d3b6bf684618a0f2f1c5ac001..4fa7c521d2265157ca19e7e1863c7fba9e763858 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,23 @@ and this project adheres to `Semantic Versioning`_. Unreleased ---------- +Changes +~~~~~~~ + +* The frontend is now able to display headings in the main toolbar. + +Fixed +~~~~~ + +* Default translations from vuetify were not loaded. +* Browser locale was not the default locale in the entire frontend. +* In some cases, some items in the sidenav menu were not shown due to its height being higher than the visible page area. +* The search bar in the sidenav menu is shown even though the user has no permission to see it. +* Add permission check to accept invitation menu point in order to hide it when this feature is disabled. +* Metrics endpoint for Prometheus was at the wrong URL. +* Polling behavior of the whoAmI and permission queries was fixed. +* Confirmation e-mail contained a wrong link. + `3.0`_ - 2022-05-11 ------------------- @@ -19,6 +36,7 @@ Added * Provide API endpoint for system status. * [Dev] UpdateIndicator Vue Component to display the status of interactive pages * [Dev] DeleteDialog Vue Component to unify item deletion in the new frontend +* Use build-in mechanism in Apollo for GraphQL batch querying. Changed diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py index efd6e34edae2dd9f6e01e02cc9c8c9a669ce7cd0..c6c15e76465feb96363eb95f225549d0b65b3d92 100644 --- a/aleksis/core/forms.py +++ b/aleksis/core/forms.py @@ -160,7 +160,18 @@ class EditGroupForm(SchoolTermRelatedExtensibleForm): class Meta: model = Group - exclude = [] + fields = [ + "school_term", + "name", + "short_name", + "group_type", + "members", + "owners", + "parent_groups", + "additional_fields", + "photo", + "avatar", + ] widgets = { "members": ModelSelect2MultipleWidget( search_fields=[ @@ -316,7 +327,16 @@ class AnnouncementForm(ExtensibleForm): class Meta: model = Announcement - exclude = [] + fields = [ + "valid_from_date", + "valid_from_time", + "valid_until_date", + "valid_until_time", + "groups", + "persons", + "title", + "description", + ] class ChildGroupsForm(forms.Form): @@ -348,7 +368,7 @@ class EditAdditionalFieldForm(forms.ModelForm): class Meta: model = AdditionalField - exclude = [] + fields = ["title", "field_type", "required", "help_text"] class EditGroupTypeForm(forms.ModelForm): @@ -366,7 +386,7 @@ class SchoolTermForm(ExtensibleForm): class Meta: model = SchoolTerm - exclude = [] + fields = ["name", "date_start", "date_end"] class DashboardWidgetOrderForm(ExtensibleForm): diff --git a/aleksis/core/frontend/app/apollo.js b/aleksis/core/frontend/app/apollo.js index 267997b9f93ba8d992a90093a93e650f32995811..519bc24aa5d7920d6433d4eebef1b38673753907 100644 --- a/aleksis/core/frontend/app/apollo.js +++ b/aleksis/core/frontend/app/apollo.js @@ -2,11 +2,12 @@ * Configuration for Apollo provider, client, and caches. */ -import { ApolloClient, HttpLink, from } from "@/apollo-boost"; +import { ApolloClient, from } from "@/apollo-boost"; import { RetryLink } from "@/apollo-link-retry"; import { persistCache, LocalStorageWrapper } from "@/apollo3-cache-persist"; import { InMemoryCache } from "@/apollo-cache-inmemory"; +import { BatchHttpLink } from "@/apollo-link-batch-http"; // Cache for GraphQL query results in memory and persistent across sessions const cache = new InMemoryCache(); @@ -33,14 +34,17 @@ const links = [ // Automatically retry failed queries new RetryLink(), // Finally, the HTTP link to the real backend (Django) - new HttpLink({ + new BatchHttpLink({ uri: getGraphqlURL(), + batchInterval: 200, + batchDebounce: true, }), ]; /** Upstream Apollo GraphQL client */ const apolloClient = new ApolloClient({ cache, + shouldBatch: true, link: from(links), }); diff --git a/aleksis/core/frontend/components/app/App.vue b/aleksis/core/frontend/components/app/App.vue index b6919fbe8353c305cc88141e0bbcdd095bd4231c..f650517ae88d122ea6684de14819c4a5f00cc241 100644 --- a/aleksis/core/frontend/components/app/App.vue +++ b/aleksis/core/frontend/components/app/App.vue @@ -25,7 +25,7 @@ class="white--text text-decoration-none" @click="$router.push({ name: 'dashboard' })" > - {{ systemProperties.sitePreferences.generalTitle }} + {{ $root.toolbarTitle }} </v-toolbar-title> <v-progress-linear @@ -246,12 +246,17 @@ export default { systemProperties: gqlSystemProperties, whoAmI: { query: gqlWhoAmI, + pollInterval: 30000, + result({ data }) { + if (data && data.whoAmI) { + this.$root.permissions = data.whoAmI.permissions; + } + }, variables() { return { - permissions: this.permissionNames, + permissions: this.$root.permissionNames, }; }, - pollInterval: 10000, }, messages: { query: gqlMessages, diff --git a/aleksis/core/frontend/components/app/LanguageForm.vue b/aleksis/core/frontend/components/app/LanguageForm.vue index 12acbe613e94a23e25f5d1195b0badf420d92aa6..cdef5932231e5b0401296b6918d009eb544588ec 100644 --- a/aleksis/core/frontend/components/app/LanguageForm.vue +++ b/aleksis/core/frontend/components/app/LanguageForm.vue @@ -33,17 +33,33 @@ export default { type: Array, required: true, }, + defaultLanguage: { + type: Object, + required: true, + }, }, methods: { setLanguage: function (languageOption) { document.cookie = languageOption.cookie; this.$i18n.locale = languageOption.code; this.$vuetify.lang.current = languageOption.code; + this.language = languageOption; }, nameForMenu: function (item) { return `${item.nameLocal} (${item.code})`; }, }, + mounted() { + if ( + this.availableLanguages.filter((lang) => lang.code === this.$i18n.locale) + .length === 0 + ) { + console.warn( + `Unsupported language ${this.$i18n.locale} selected, defaulting to ${this.defaultLanguage.code}` + ); + this.setLanguage(this.defaultLanguage); + } + }, name: "LanguageForm", }; </script> diff --git a/aleksis/core/frontend/components/app/SideNav.vue b/aleksis/core/frontend/components/app/SideNav.vue index 0975c580cda88d03fd8a5d34b2fb16425ece69ee..e2594aae9eb9d561a710530a3d87e345e2791c74 100644 --- a/aleksis/core/frontend/components/app/SideNav.vue +++ b/aleksis/core/frontend/components/app/SideNav.vue @@ -1,5 +1,10 @@ <template> - <v-navigation-drawer app :value="value" @input="$emit('input', $event)"> + <v-navigation-drawer + app + :value="value" + height="100dvh" + @input="$emit('input', $event)" + > <v-list nav dense shaped> <v-list-item class="logo"> <a @@ -10,7 +15,7 @@ <brand-logo :site-preferences="systemProperties.sitePreferences" /> </a> </v-list-item> - <v-list-item class="search"> + <v-list-item v-if="checkPermission('core.search_rule')" class="search"> <sidenav-search /> </v-list-item> <v-list-item-group :value="$route.name" v-if="sideNavMenu"> @@ -82,6 +87,7 @@ <v-spacer /> <language-form :available-languages="systemProperties.availableLanguages" + :default-language="systemProperties.defaultLanguage" /> <v-spacer /> </div> @@ -94,6 +100,8 @@ import BrandLogo from "./BrandLogo.vue"; import LanguageForm from "./LanguageForm.vue"; import SidenavSearch from "./SidenavSearch.vue"; +import permissionsMixin from "../../mixins/permissions.js"; + export default { name: "SideNav", components: { @@ -106,6 +114,10 @@ export default { systemProperties: { type: Object, required: true }, value: { type: Boolean, required: true }, }, + mixins: [permissionsMixin], + mounted() { + this.addPermissions(["core.search_rule"]); + }, }; </script> diff --git a/aleksis/core/frontend/components/app/systemProperties.graphql b/aleksis/core/frontend/components/app/systemProperties.graphql index 99533650b65369f4a07c330399a2f452a815b763..b8ec991bda2b1b689c97f2fb339dafce9d0e1175 100644 --- a/aleksis/core/frontend/components/app/systemProperties.graphql +++ b/aleksis/core/frontend/components/app/systemProperties.graphql @@ -6,6 +6,12 @@ nameLocal cookie } + defaultLanguage { + code + nameTranslated + nameLocal + cookie + } sitePreferences { themePrimary themeSecondary diff --git a/aleksis/core/frontend/components/app/whoAmI.graphql b/aleksis/core/frontend/components/app/whoAmI.graphql index 0b2877bd2cf15b5134c8e70978fb6b2218414e3a..fff7344d06817d73a37ede3f8698afaaa06e1ea6 100644 --- a/aleksis/core/frontend/components/app/whoAmI.graphql +++ b/aleksis/core/frontend/components/app/whoAmI.graphql @@ -1,4 +1,4 @@ -query ($permissions: [String]!) { +query whoAmI($permissions: [String]!) { whoAmI { username isAuthenticated diff --git a/aleksis/core/frontend/components/authorized_oauth_applications/AuthorizedApplications.vue b/aleksis/core/frontend/components/authorized_oauth_applications/AuthorizedApplications.vue index bbf35c8e7f3c2f9e71479c03feb86799b3328d7f..55e100ddf773e342033a7f691089c6e5d7940936 100644 --- a/aleksis/core/frontend/components/authorized_oauth_applications/AuthorizedApplications.vue +++ b/aleksis/core/frontend/components/authorized_oauth_applications/AuthorizedApplications.vue @@ -1,6 +1,5 @@ <template> <div> - <h1 class="mb-4">{{ $t("oauth.authorized_application.title") }}</h1> <div v-if="$apollo.queries.accessTokens.loading"> <v-skeleton-loader type="card"></v-skeleton-loader> </div> diff --git a/aleksis/core/frontend/components/celery_progress/CeleryProgressBottom.vue b/aleksis/core/frontend/components/celery_progress/CeleryProgressBottom.vue index 410e57fda0eca36d3acaca7fc0318174fd71d318..912fb779241ef577c6f900abc78a26008df008f6 100644 --- a/aleksis/core/frontend/components/celery_progress/CeleryProgressBottom.vue +++ b/aleksis/core/frontend/components/celery_progress/CeleryProgressBottom.vue @@ -47,7 +47,7 @@ export default { apollo: { celeryProgressByUser: { query: gqlCeleryProgressButton, - pollInterval: 1000, + pollInterval: 30000, }, }, }; diff --git a/aleksis/core/frontend/components/notifications/NotificationList.vue b/aleksis/core/frontend/components/notifications/NotificationList.vue index b64769cc6d3dacb130197a3efcea516ef3d89c83..1c51c00661816fe3e244e6d511a0e70c747dbca6 100644 --- a/aleksis/core/frontend/components/notifications/NotificationList.vue +++ b/aleksis/core/frontend/components/notifications/NotificationList.vue @@ -83,7 +83,7 @@ export default { apollo: { myNotifications: { query: gqlMyNotifications, - pollInterval: 1000, + pollInterval: 30000, }, }, }; diff --git a/aleksis/core/frontend/components/two_factor/TwoFactor.vue b/aleksis/core/frontend/components/two_factor/TwoFactor.vue index b6c023a55ffa3d9cf467d88109b46d78cf630ab0..96df63ebd882fa413538abb4ae3f68b5445aa966 100644 --- a/aleksis/core/frontend/components/two_factor/TwoFactor.vue +++ b/aleksis/core/frontend/components/two_factor/TwoFactor.vue @@ -1,6 +1,5 @@ <template> <div> - <h1 class="mb-4">{{ $t("accounts.two_factor.title") }}</h1> <div v-if="$apollo.queries.twoFactor.loading"> <v-skeleton-loader type="card,card"></v-skeleton-loader> </div> diff --git a/aleksis/core/frontend/index.js b/aleksis/core/frontend/index.js index f59aa8578b59addcb420d6165c6ef1672c669c30..e54375745f0941ca8799a0537ac9fdcda6da9122 100644 --- a/aleksis/core/frontend/index.js +++ b/aleksis/core/frontend/index.js @@ -36,9 +36,7 @@ import routerOpts from "./app/router.js"; import apolloOpts from "./app/apollo.js"; const i18n = new VueI18n({ - locale: Vue.$cookies.get("django_language") - ? Vue.$cookies.get("django_language") - : "en", + locale: Vue.$cookies.get("django_language") || navigator.language || "en", ...i18nOpts, }); const vuetify = new Vuetify({ @@ -46,6 +44,7 @@ const vuetify = new Vuetify({ current: Vue.$cookies.get("django_language") ? Vue.$cookies.get("django_language") : "en", + t: (key, ...params) => i18n.t(key, params), }, ...vuetifyOpts, }); @@ -70,6 +69,9 @@ const app = new Vue({ backgroundActive: true, invalidation: false, snackbarItems: [], + toolbarTitle: "AlekSIS®", + permissions: [], + permissionNames: [], }), computed: { matchedComponents() { @@ -89,5 +91,6 @@ const app = new Vue({ }); // Late setup for some plugins handed off to out ALeksisVue plugin +app.$loadVuetifyMessages(); app.$loadAppMessages(); app.$setupNavigationGuards(); diff --git a/aleksis/core/frontend/mixins/menus.js b/aleksis/core/frontend/mixins/menus.js index 9ba58bcaa84e72917e3057614fca6058df39af3a..60ce66b5b0d36efa77cc2b8944ce21e928a1f107 100644 --- a/aleksis/core/frontend/mixins/menus.js +++ b/aleksis/core/frontend/mixins/menus.js @@ -1,15 +1,17 @@ import gqlCustomMenu from "../components/app/customMenu.graphql"; +import permissionsMixin from "./permissions.js"; + /** * Vue mixin containing menu generation code. * * Only used by main App component, but factored out for readability. */ const menusMixin = { + mixins: [permissionsMixin], data() { return { footerMenu: null, - permissionNames: [], sideNavMenu: null, accountMenu: null, }; @@ -35,8 +37,7 @@ const menusMixin = { } } - this.permissionNames = permArray; - this.$apollo.queries.whoAmI.refetch(); + this.addPermissions(permArray); }, buildMenu(routes, menuKey) { let menu = {}; @@ -99,14 +100,6 @@ const menusMixin = { return Object.values(menu); }, - checkPermission(permissionName) { - return ( - this.whoAmI && - this.whoAmI.permissions && - this.whoAmI.permissions.find((p) => p.name === permissionName) && - this.whoAmI.permissions.find((p) => p.name === permissionName).result - ); - }, checkValidators(validators) { for (const validator of validators) { if (!validator(this.whoAmI)) { @@ -118,14 +111,9 @@ const menusMixin = { buildMenus() { this.accountMenu = this.buildMenu( this.$router.getRoutes(), - "inAccountMenu", - this.whoAmI ? this.whoAmI.permissions : [] - ); - this.sideNavMenu = this.buildMenu( - this.$router.getRoutes(), - "inMenu", - this.whoAmI ? this.whoAmI.permissions : [] + "inAccountMenu" ); + this.sideNavMenu = this.buildMenu(this.$router.getRoutes(), "inMenu"); }, }, apollo: { diff --git a/aleksis/core/frontend/mixins/permissions.js b/aleksis/core/frontend/mixins/permissions.js new file mode 100644 index 0000000000000000000000000000000000000000..9d5a00f51a747e06d0d38461351d9bc63a1dc8ac --- /dev/null +++ b/aleksis/core/frontend/mixins/permissions.js @@ -0,0 +1,28 @@ +/** + * Vue mixin containing permission checking code. + */ + +const permissionsMixin = { + methods: { + checkPermission(permissionName) { + return ( + this.$root.permissions && + this.$root.permissions.find((p) => p.name === permissionName) && + this.$root.permissions.find((p) => p.name === permissionName).result + ); + }, + addPermissions(newPermissionNames) { + const keepPermissionNames = this.$root.permissionNames.filter( + (oldPermName) => + !newPermissionNames.find((newPermName) => newPermName === oldPermName) + ); + + this.$root.permissionNames = [ + ...keepPermissionNames, + ...newPermissionNames, + ]; + }, + }, +}; + +export default permissionsMixin; diff --git a/aleksis/core/frontend/mixins/routes.js b/aleksis/core/frontend/mixins/routes.js index 9adbdafc7426fcc19174f91266b978471f3a38e9..e458b23a6f65d22f9682178980ab8e15fe1e74d5 100644 --- a/aleksis/core/frontend/mixins/routes.js +++ b/aleksis/core/frontend/mixins/routes.js @@ -14,7 +14,7 @@ const routesMixin = { apollo: { dynamicRoutes: { query: gqlDynamicRoutes, - pollInterval: 10000, + pollInterval: 30000, }, }, watch: { diff --git a/aleksis/core/frontend/plugins/aleksis.js b/aleksis/core/frontend/plugins/aleksis.js index c35b9127f78f6c26c3e5c052cc5732322f509090..c129aac331c51c1135203ed633a6fd3fccbc942f 100644 --- a/aleksis/core/frontend/plugins/aleksis.js +++ b/aleksis/core/frontend/plugins/aleksis.js @@ -5,6 +5,7 @@ // aleksisAppImporter is a virtual module defined in Vite config import { appMessages } from "aleksisAppImporter"; import aleksisMixin from "../mixins/aleksis.js"; +import * as langs from "@/vuetify/src/locale"; console.debug("Defining AleksisVue plugin"); const AleksisVue = {}; @@ -104,6 +105,33 @@ AleksisVue.install = function (Vue) { document.title = newTitle; }; + /** + * Set the toolbar title visible on the page. + * + * This will automatically add the base title discovered at app loading time. + * + * @param {string} title Specific title to set, or null. + * @param {Object} route Route to discover title from, or null. + */ + Vue.prototype.$setToolBarTitle = function (title, route) { + let newTitle; + + if (title) { + newTitle = title; + } else { + if (!route) { + route = this.$route; + } + if (route.meta.toolbarTitle) { + newTitle = this.$t(route.meta.toolbarTitle); + } + } + + newTitle = newTitle || Vue.$pageBaseTitle; + console.debug(`Setting toolbar title: ${newTitle}`); + this.$root.toolbarTitle = newTitle; + }; + /** * Load i18n messages from all known AlekSIS apps. */ @@ -115,6 +143,15 @@ AleksisVue.install = function (Vue) { } }; + /** + * Load vuetifys built-in translations + */ + Vue.prototype.$loadVuetifyMessages = function () { + for (const [locale, messages] of Object.entries(langs)) { + this.$i18n.mergeLocaleMessage(locale, { $vuetify: messages }); + } + }; + /** * Invalidate state and force reload from server. * @@ -150,6 +187,7 @@ AleksisVue.install = function (Vue) { this.$router.afterEach((to, from, next) => { console.debug("Setting new page title due to route change"); vm.$setPageTitle(null, to); + vm.$setToolBarTitle(null, to); }); // eslint-disable-next-line no-unused-vars diff --git a/aleksis/core/frontend/routes.js b/aleksis/core/frontend/routes.js index aa84f36c4aa9f634f081edb9338f8f264dc9c2fe..2af742809548f5f2f70e9c13a1b7091e6d8145c5 100644 --- a/aleksis/core/frontend/routes.js +++ b/aleksis/core/frontend/routes.js @@ -54,6 +54,7 @@ const routes = [ icon: "mdi-key-outline", titleKey: "accounts.invitation.accept_invitation.menu_title", validators: [notLoggedInValidator], + permission: "core.invite_enabled", }, }, { @@ -734,6 +735,7 @@ const routes = [ meta: { inAccountMenu: true, titleKey: "accounts.two_factor.menu_title", + toolbarTitle: "accounts.two_factor.title", icon: "mdi-two-factor-authentication", permission: "core.manage_2fa_rule", }, @@ -928,6 +930,7 @@ const routes = [ meta: { inAccountMenu: true, titleKey: "oauth.authorized_application.menu_title", + toolbarTitle: "oauth.authorized_application.title", icon: "mdi-gesture-tap-hold", permission: "core.manage_authorized_tokens_rule", }, @@ -956,14 +959,6 @@ const routes = [ invalidate: "leave", }, }, - { - path: "/invitations/code/enter", - component: () => import("./components/LegacyBaseTemplate.vue"), - props: { - byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true, - }, - name: "core.enter_invitation_code", - }, { path: "/invitations/code/generate", component: () => import("./components/LegacyBaseTemplate.vue"), diff --git a/aleksis/core/schema/system_properties.py b/aleksis/core/schema/system_properties.py index 1546512fc4e488faa01a93d87510249577c63388..6d6e50d5958601db24eca6e61d959482611cf5af 100644 --- a/aleksis/core/schema/system_properties.py +++ b/aleksis/core/schema/system_properties.py @@ -20,6 +20,7 @@ class LanguageType(graphene.ObjectType): class SystemPropertiesType(graphene.ObjectType): current_language = graphene.String(required=True) + default_language = graphene.Field(LanguageType) available_languages = graphene.List(LanguageType) site_preferences = graphene.Field(SitePreferencesType) custom_menu_by_name = graphene.Field(CustomMenuType) @@ -27,6 +28,11 @@ class SystemPropertiesType(graphene.ObjectType): def resolve_current_language(parent, info, **kwargs): return info.context.LANGUAGE_CODE + @staticmethod + def resolve_default_language(root, info, **kwargs): + code = settings.LANGUAGE_CODE + return translation.get_language_info(code) | {"cookie": get_language_cookie(code)} + def resolve_available_languages(parent, info, **kwargs): return [ translation.get_language_info(code) | {"cookie": get_language_cookie(code)} diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index fbe25a785c289e415445b6cf52bc9ff43bfeb477..656fcd30a69e245c02d7bf2a984517265c512da9 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -576,7 +576,7 @@ YARN_INSTALLED_APPS = [ "@fontsource/roboto@^4.5.5", "jquery@^3.6.0", "@materializecss/materialize@~1.0.0", - "material-design-icons-iconfont@^6.6.0", + "material-design-icons-iconfont@^6.7.0", "select2-materialize@^0.1.8", "paper-css@^0.4.1", "jquery-sortablejs@^1.0.1", @@ -585,8 +585,9 @@ YARN_INSTALLED_APPS = [ "luxon@^2.3.2", "@iconify/iconify@^2.2.1", "@iconify/json@^2.1.30", - "@mdi/font@^6.9.96", + "@mdi/font@^7.2.96", "apollo-boost@^0.4.9", + "apollo-link-batch-http@^1.2.14", "apollo-link-retry@^2.2.16", "apollo3-cache-persist@^0.14.1", "deepmerge@^4.2.2", diff --git a/aleksis/core/templates/account/email/email_confirmation_message.txt b/aleksis/core/templates/account/email/email_confirmation_message.txt new file mode 100644 index 0000000000000000000000000000000000000000..f795c60f7b66c75b37217caed8c38c3d7f9295e0 --- /dev/null +++ b/aleksis/core/templates/account/email/email_confirmation_message.txt @@ -0,0 +1,7 @@ +{% extends "account/email/base_message.txt" %} +{% load account %} +{% load html_helpers %} +{% load i18n %} + +{% block content %}{% user_display user as user_display %}{% blocktrans with site_name=current_site.name site_domain=current_site.domain %}Someone tried to register an account with the username {{ user_display }} and your e-mail address on {{ site_domain }}. +If it was you, please confirm the registration by clicking on the following link:{% endblocktrans %} {{ activate_url|remove_prefix:"/django/" }}{% endblock %} diff --git a/aleksis/core/urls.py b/aleksis/core/urls.py index 9792fcb75cd1e7197cda1f1e6707c3eb42ed1d3e..7a22c7bb20a9d3c2d0d0e5af6bece161ac5dbdfa 100644 --- a/aleksis/core/urls.py +++ b/aleksis/core/urls.py @@ -27,7 +27,7 @@ urlpatterns = [ path("__icons__/", include("dj_iconify.urls")), path( "graphql/", - csrf_exempt(views.LoggingGraphQLView.as_view(graphiql=True)), + csrf_exempt(views.LoggingGraphQLView.as_view(batch=True)), name="graphql", ), path("logo", force_maintenance_mode_off(views.LogoView.as_view()), name="logo"), @@ -42,11 +42,11 @@ urlpatterns = [ ), path("oauth/", include("oauth2_provider.urls", namespace="oauth2_provider")), path("system_status/", views.SystemStatusAPIView.as_view(), name="system_status_api"), + path("", include("django_prometheus.urls")), path( "django/", include( [ - path("", include("django_prometheus.urls")), path("account/login/", views.LoginView.as_view(), name="login"), path( "accounts/signup/", views.AccountRegisterView.as_view(), name="account_signup" diff --git a/docs/dev/01_setup.rst b/docs/dev/01_setup.rst index 1b82cf5e35c78585ee01b101120ceaff8fa19305..f7f56f811bcd7b0bfca48fbf9793a026ff2a44bf 100644 --- a/docs/dev/01_setup.rst +++ b/docs/dev/01_setup.rst @@ -90,7 +90,7 @@ All three steps can be done with the ``poetry shell`` command and ``aleksis-admin``:: ALEKSIS_maintenance__debug=true ALEKSIS_database__password=aleksis poetry shell - poetry run aleksis-admin yarn install + poetry run aleksis-admin vite build poetry run aleksis-admin collectstatic poetry run aleksis-admin compilemessages poetry run aleksis-admin migrate diff --git a/pyproject.toml b/pyproject.toml index f5f4f37bd1b7e4dfb02607cb9f3307d5cc942ef6..3445fb1e0e322123b5c006e0086d7e48485be76c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -106,13 +106,13 @@ django-model-utils = "^4.0.0" bs4 = "^0.0.1" django-invitations = "^2.0.0" django-cleavejs = "^0.1.0" -django-allauth = "^0.53.0" +django-allauth = "^0.54.0" django-uwsgi-ng = "^2.0" django-extensions = "^3.1.1" ipython = "^8.0.0" django-oauth-toolkit = "^2.0.0" -django-storages = {version = "^1.11.1", optional = true} -boto3 = {version = "^1.17.33", optional = true} +django-storages = {version = "^1.13.2", optional = true} +boto3 = {version = "^1.26.142", optional = true} django-cleanup = "^7.0.0" djangorestframework = "^3.12.4" Whoosh = "^2.7.4"